1/*
2 * Copyright 2005-2011, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
4 */
5
6
7#include <BeOSBuildCompatibility.h>
8
9#include "fs_impl.h"
10
11#include <dirent.h>
12#include <errno.h>
13#include <fcntl.h>
14#include <stdio.h>
15#include <stdlib.h>
16#include <unistd.h>
17#include <utime.h>
18#include <sys/stat.h>
19#include <sys/time.h>
20
21#include <map>
22#include <string>
23
24#include <fs_attr.h>
25#include <NodeMonitor.h>	// for B_STAT_* flags
26#include <syscalls.h>
27
28#include "fs_descriptors.h"
29#include "NodeRef.h"
30#include "remapped_functions.h"
31
32#if defined(HAIKU_HOST_PLATFORM_FREEBSD)
33#	include "fs_freebsd.h"
34#endif
35
36
37using namespace std;
38using namespace BPrivate;
39
40
41#if defined(HAIKU_HOST_PLATFORM_FREEBSD)
42#	define haiku_host_platform_read		haiku_freebsd_read
43#	define haiku_host_platform_write	haiku_freebsd_write
44#	define haiku_host_platform_readv	haiku_freebsd_readv
45#	define haiku_host_platform_writev	haiku_freebsd_writev
46#	define HAIKU_HOST_STAT_ATIM(x)		((x).st_atimespec)
47#	define HAIKU_HOST_STAT_MTIM(x)		((x).st_mtimespec)
48#elif defined(HAIKU_HOST_PLATFORM_DARWIN)
49#	define haiku_host_platform_read		read
50#	define haiku_host_platform_write	write
51#	define haiku_host_platform_readv	readv
52#	define haiku_host_platform_writev	writev
53#	define HAIKU_HOST_STAT_ATIM(x)		((x).st_atimespec)
54#	define HAIKU_HOST_STAT_MTIM(x)		((x).st_mtimespec)
55#else
56#	define haiku_host_platform_read		read
57#	define haiku_host_platform_write	write
58#	define haiku_host_platform_readv	readv
59#	define haiku_host_platform_writev	writev
60#	define HAIKU_HOST_STAT_ATIM(x)		((x).st_atim)
61#	define HAIKU_HOST_STAT_MTIM(x)		((x).st_mtim)
62#endif
63
64#define RETURN_AND_SET_ERRNO(err)			\
65	do {									\
66		__typeof(err) __result = (err);		\
67		if (__result < 0) {					\
68			errno = __result;				\
69			return -1;						\
70		}									\
71		return __result;					\
72	} while (0)
73
74
75#if defined(_HAIKU_BUILD_NO_FUTIMENS) || defined(_HAIKU_BUILD_NO_FUTIMENS)
76
77template<typename File>
78static int
79utimes_helper(File& file, const struct timespec times[2])
80{
81	if (times == NULL)
82		return file.SetTimes(NULL);
83
84	timeval timeBuffer[2];
85	timeBuffer[0].tv_sec = times[0].tv_sec;
86	timeBuffer[0].tv_usec = times[0].tv_nsec / 1000;
87	timeBuffer[1].tv_sec = times[1].tv_sec;
88	timeBuffer[1].tv_usec = times[1].tv_nsec / 1000;
89
90	if (times[0].tv_nsec == UTIME_OMIT || times[1].tv_nsec == UTIME_OMIT) {
91		struct stat st;
92		if (file.GetStat(st) != 0)
93			return -1;
94
95		if (times[0].tv_nsec == UTIME_OMIT && times[1].tv_nsec == UTIME_OMIT)
96			return 0;
97
98		if (times[0].tv_nsec == UTIME_OMIT) {
99			timeBuffer[0].tv_sec = st.st_atimespec.tv_sec;
100			timeBuffer[0].tv_usec = st.st_atimespec.tv_nsec / 1000;
101		}
102
103		if (times[1].tv_nsec == UTIME_OMIT) {
104			timeBuffer[1].tv_sec = st.st_mtimespec.tv_sec;
105			timeBuffer[1].tv_usec = st.st_mtimespec.tv_nsec / 1000;
106		}
107	}
108
109	if (times[0].tv_nsec == UTIME_NOW || times[1].tv_nsec == UTIME_NOW) {
110		timeval now;
111		gettimeofday(&now, NULL);
112
113		if (times[0].tv_nsec == UTIME_NOW)
114			timeBuffer[0] = now;
115
116		if (times[1].tv_nsec == UTIME_NOW)
117			timeBuffer[1] = now;
118	}
119
120	return file.SetTimes(timeBuffer);
121}
122
123#endif	// _HAIKU_BUILD_NO_FUTIMENS || _HAIKU_BUILD_NO_FUTIMENS
124
125
126#ifdef _HAIKU_BUILD_NO_FUTIMENS
127
128struct FDFile {
129	FDFile(int fd)
130		:
131		fFD(fd)
132	{
133	}
134
135	int GetStat(struct stat& _st)
136	{
137		return fstat(fFD, &_st);
138	}
139
140	int SetTimes(const timeval times[2])
141	{
142		return futimes(fFD, times);
143	}
144
145private:
146	int fFD;
147};
148
149
150int
151futimens(int fd, const struct timespec times[2])
152{
153	FDFile file(fd);
154	return utimes_helper(file, times);
155}
156
157#endif	// _HAIKU_BUILD_NO_FUTIMENS
158
159#ifdef _HAIKU_BUILD_NO_UTIMENSAT
160
161struct FDPathFile {
162	FDPathFile(int fd, const char* path, int flag)
163		:
164		fFD(fd),
165		fPath(path),
166		fFlag(flag)
167	{
168	}
169
170	int GetStat(struct stat& _st)
171	{
172		return fstatat(fFD, fPath, &_st, fFlag);
173	}
174
175	int SetTimes(const timeval times[2])
176	{
177		// TODO: fFlag (AT_SYMLINK_NOFOLLOW) is not supported here!
178		return futimesat(fFD, fPath, times);
179	}
180
181private:
182	int			fFD;
183	const char*	fPath;
184	int			fFlag;
185};
186
187
188int
189utimensat(int fd, const char* path, const struct timespec times[2], int flag)
190{
191	FDPathFile file(fd, path, flag);
192	return utimes_helper(file, times);
193}
194
195#endif	// _HAIKU_BUILD_NO_UTIMENSAT
196
197
198static status_t get_path(dev_t device, ino_t node, const char *name,
199	string &path);
200
201
202// find_dir_entry
203static status_t
204find_dir_entry(DIR *dir, const char *path, NodeRef ref, string &name,
205	bool skipDot)
206{
207	// find the entry
208	bool found = false;
209	while (dirent *entry = readdir(dir)) {
210		if ((strcmp(entry->d_name, ".") == 0 && skipDot)
211			|| strcmp(entry->d_name, "..") == 0) {
212			// skip "." and ".."
213		} else /*if (entry->d_ino == ref.node)*/ {
214				// Note: Linux doesn't seem to translate dirent::d_ino of
215				// mount points. Thus we always have to lstat().
216			// We also need to compare the device, which is generally not
217			// included in the dirent structure. Hence we lstat().
218			string entryPath(path);
219			entryPath += '/';
220			entryPath += entry->d_name;
221			struct stat st;
222			if (lstat(entryPath.c_str(), &st) == 0) {
223				if (NodeRef(st) == ref) {
224					name = entry->d_name;
225					found = true;
226					break;
227				}
228			}
229		}
230	}
231
232	if (!found)
233		return B_ENTRY_NOT_FOUND;
234
235	return B_OK;
236}
237
238// find_dir_entry
239static status_t
240find_dir_entry(const char *path, NodeRef ref, string &name, bool skipDot)
241{
242	// open dir
243	DIR *dir = opendir(path);
244	if (!dir)
245		return errno;
246
247	status_t error = find_dir_entry(dir, path, ref, name, skipDot);
248
249	// close dir
250	closedir(dir);
251
252	return error;
253}
254
255
256static bool
257guess_normalized_dir_path(string path, NodeRef ref, string& _normalizedPath)
258{
259	// We assume the CWD is normalized and hope that the directory is an
260	// ancestor of it. We just chop off path components until we find a match or
261	// hit root.
262	char cwd[B_PATH_NAME_LENGTH];
263	if (getcwd(cwd, sizeof(cwd)) == NULL)
264		return false;
265
266	while (cwd[0] == '/') {
267		struct stat st;
268		if (stat(cwd, &st) == 0) {
269			if (st.st_dev == ref.device && st.st_ino == ref.node) {
270				_normalizedPath = cwd;
271				return true;
272			}
273		}
274
275		*strrchr(cwd, '/') = '\0';
276	}
277
278	// TODO: If path is absolute, we could also try to work with that, though
279	// the other way around -- trying prefixes until we hit a "." or ".."
280	// component.
281
282	return false;
283}
284
285
286// normalize_dir_path
287static status_t
288normalize_dir_path(string path, NodeRef ref, string &normalizedPath)
289{
290	// get parent path
291	path += "/..";
292
293	// stat the parent dir
294	struct stat st;
295	if (lstat(path.c_str(), &st) < 0)
296		return errno;
297
298	// root dir?
299	NodeRef parentRef(st);
300	if (parentRef == ref) {
301		normalizedPath = "/";
302		return 0;
303	}
304
305	// find the entry
306	string name;
307	status_t error = find_dir_entry(path.c_str(), ref, name, true)				;
308	if (error != B_OK) {
309		if (error != B_ENTRY_NOT_FOUND) {
310			// We couldn't open the directory. This might be because we don't
311			// have read permission. We're OK with not fully normalizing the
312			// path and try to guess the path in this case. Note: We don't check
313			// error for B_PERMISSION_DENIED, since opendir() may clobber the
314			// actual kernel error code with something not helpful.
315			if (guess_normalized_dir_path(path, ref, normalizedPath))
316				return B_OK;
317		}
318
319		return error;
320	}
321
322	// recurse to get the parent dir path, if found
323	error = normalize_dir_path(path, parentRef, normalizedPath);
324	if (error != 0)
325		return error;
326
327	// construct the normalizedPath
328	if (normalizedPath.length() > 1) // don't append "/", if parent is root
329		normalizedPath += '/';
330	normalizedPath += name;
331
332	return 0;
333}
334
335// normalize_dir_path
336static status_t
337normalize_dir_path(const char *path, string &normalizedPath)
338{
339	// stat() the dir
340	struct stat st;
341	if (stat(path, &st) < 0)
342		return errno;
343
344	return normalize_dir_path(path, NodeRef(st), normalizedPath);
345}
346
347// normalize_entry_path
348static status_t
349normalize_entry_path(const char *path, string &normalizedPath)
350{
351	const char *dirPath = NULL;
352	const char *leafName = NULL;
353
354	string dirPathString;
355	if (const char *lastSlash = strrchr(path, '/')) {
356		// found a slash: decompose into dir path and leaf name
357		leafName = lastSlash + 1;
358		if (leafName[0] == '\0') {
359			// slash is at the end: the whole path is a dir name
360			leafName = NULL;
361		} else {
362			dirPathString = string(path, leafName - path);
363			dirPath = dirPathString.c_str();
364		}
365
366	} else {
367		// path contains no slash, so it is a path relative to the current dir
368		dirPath = ".";
369		leafName = path;
370	}
371
372	// catch special case: no leaf, or leaf is a directory
373	if (!leafName || strcmp(leafName, ".") == 0 || strcmp(leafName, "..") == 0)
374		return normalize_dir_path(path, normalizedPath);
375
376	// normalize the dir path
377	status_t error = normalize_dir_path(dirPath, normalizedPath);
378	if (error != B_OK)
379		return error;
380
381	// append the leaf name
382	if (normalizedPath.length() > 1) // don't append "/", if parent is root
383		normalizedPath += '/';
384	normalizedPath += leafName;
385
386	return B_OK;
387}
388
389
390// #pragma mark -
391
392typedef map<NodeRef, string> DirPathMap;
393static DirPathMap sDirPathMap;
394
395// get_path
396static status_t
397get_path(const NodeRef *ref, const char *name, string &path)
398{
399	if (!ref && !name)
400		return B_BAD_VALUE;
401
402	// no ref or absolute path
403	if (!ref || (name && name[0] == '/')) {
404		path = name;
405		return B_OK;
406	}
407
408	// get the dir path
409	if (ref) {
410		DirPathMap::iterator it = sDirPathMap.find(*ref);
411		if (it == sDirPathMap.end())
412			return B_ENTRY_NOT_FOUND;
413
414		path = it->second;
415
416		// stat the path to check, if it is still valid
417		struct stat st;
418		if (lstat(path.c_str(), &st) < 0) {
419			sDirPathMap.erase(it);
420			return errno;
421		}
422
423		// compare the NodeRef
424		if (NodeRef(st) != *ref) {
425			sDirPathMap.erase(it);
426			return B_ENTRY_NOT_FOUND;
427		}
428
429		// still a directory?
430		if (!S_ISDIR(st.st_mode)) {
431			sDirPathMap.erase(it);
432			return B_NOT_A_DIRECTORY;
433		}
434	}
435
436	// if there's a name, append it
437	if (name) {
438		path += '/';
439		path += name;
440	}
441
442	return B_OK;
443}
444
445// get_path
446status_t
447BPrivate::get_path(int fd, const char *name, string &path)
448{
449	// get the node ref for the fd, if any, and the path part is not absolute
450	if (fd >= 0 && !(name && name[0] == '/')) {
451		// get descriptor
452		Descriptor *descriptor = get_descriptor(fd);
453		if (!descriptor)
454			return B_FILE_ERROR;
455
456		// Handle symlink descriptors here explicitly, so this function can be
457		// used more flexibly.
458		if (SymlinkDescriptor* symlinkDescriptor
459				= dynamic_cast<SymlinkDescriptor*>(descriptor)) {
460			path = symlinkDescriptor->path;
461			if (name == NULL)
462				return B_OK;
463			path += '/';
464			path += name;
465			return B_OK;
466		}
467
468		// get node ref for the descriptor
469		NodeRef ref;
470		status_t error = descriptor->GetNodeRef(ref);
471		if (error != B_OK)
472			return error;
473
474		return ::get_path(&ref, name, path);
475
476	} else	// no descriptor or absolute path
477		return ::get_path((NodeRef*)NULL, name, path);
478}
479
480// get_path
481static status_t
482get_path(dev_t device, ino_t directory, const char *name, string &path)
483{
484	NodeRef ref;
485	ref.device = device;
486	ref.node = directory;
487
488	return get_path(&ref, name, path);
489}
490
491// add_dir_path
492static void
493add_dir_path(const char *path, const NodeRef &ref)
494{
495	// add the normalized path
496	string normalizedPath;
497	if (normalize_dir_path(path, normalizedPath) == B_OK)
498		sDirPathMap[ref] = normalizedPath;
499}
500
501
502// #pragma mark -
503
504// _kern_entry_ref_to_path
505status_t
506_kern_entry_ref_to_path(dev_t device, ino_t node, const char *leaf,
507	char *userPath, size_t pathLength)
508{
509	// get the path
510	string path;
511	status_t error = get_path(device, node, leaf, path);
512	if (error != B_OK)
513		return error;
514
515	// copy it back to the user buffer
516	if (strlcpy(userPath, path.c_str(), pathLength) >= pathLength)
517		return B_BUFFER_OVERFLOW;
518
519	return B_OK;
520}
521
522
523// #pragma mark -
524
525// _kern_create_dir
526status_t
527_kern_create_dir(int fd, const char *path, int perms)
528{
529	// get a usable path
530	string realPath;
531	status_t error = get_path(fd, path, realPath);
532	if (error != B_OK)
533		return error;
534
535	// mkdir
536	if (mkdir(realPath.c_str(), perms) < 0)
537		return errno;
538
539	return B_OK;
540}
541
542// _kern_create_dir_entry_ref
543status_t
544_kern_create_dir_entry_ref(dev_t device, ino_t node, const char *name,
545	int perms)
546{
547	// get a usable path
548	string realPath;
549	status_t error = get_path(device, node, name, realPath);
550	if (error != B_OK)
551		return error;
552
553	// mkdir
554	if (mkdir(realPath.c_str(), perms) < 0)
555		return errno;
556
557	return B_OK;
558}
559
560// open_dir
561static int
562open_dir(const char *path)
563{
564	// open the dir
565	DIR *dir = opendir(path);
566	if (!dir)
567		return errno;
568
569	// stat the entry
570	struct stat st;
571	if (stat(path, &st) < 0) {
572		closedir(dir);
573		return errno;
574	}
575
576	if (!S_ISDIR(st.st_mode)) {
577		closedir(dir);
578		return B_NOT_A_DIRECTORY;
579	}
580
581	// cache dir path
582	NodeRef ref(st);
583	add_dir_path(path, ref);
584
585	// create descriptor
586	DirectoryDescriptor *descriptor = new DirectoryDescriptor(dir, ref);
587	return add_descriptor(descriptor);
588}
589
590// _kern_open_dir
591int
592_kern_open_dir(int fd, const char *path)
593{
594	// get a usable path
595	string realPath;
596	status_t error = get_path(fd, path, realPath);
597	if (error != B_OK)
598		return error;
599
600	return open_dir(realPath.c_str());
601}
602
603// _kern_open_dir_entry_ref
604int
605_kern_open_dir_entry_ref(dev_t device, ino_t node, const char *name)
606{
607	// get a usable path
608	string realPath;
609	status_t error = get_path(device, node, name, realPath);
610	if (error != B_OK)
611		return error;
612
613	return open_dir(realPath.c_str());
614}
615
616// _kern_open_parent_dir
617int
618_kern_open_parent_dir(int fd, char *name, size_t nameLength)
619{
620	// get a usable path
621	string realPath;
622	status_t error = get_path(fd, NULL, realPath);
623	if (error != B_OK)
624		return error;
625
626	// stat the entry
627	struct stat st;
628	if (stat(realPath.c_str(), &st) < 0)
629		return errno;
630
631	if (!S_ISDIR(st.st_mode))
632		return B_NOT_A_DIRECTORY;
633
634	// get the entry name
635	realPath += "/..";
636	string entryName;
637	error = find_dir_entry(realPath.c_str(), NodeRef(st),
638		entryName, false);
639	if (error != B_OK)
640		return error;
641
642	if (strlcpy(name, entryName.c_str(), nameLength) >= nameLength)
643		return B_BUFFER_OVERFLOW;
644
645	// open the parent directory
646
647	return open_dir(realPath.c_str());
648}
649
650// _kern_read_dir
651ssize_t
652_kern_read_dir(int fd, struct dirent *buffer, size_t bufferSize,
653	uint32 maxCount)
654{
655	if (maxCount <= 0)
656		return B_BAD_VALUE;
657
658	// get the descriptor
659	DirectoryDescriptor *descriptor
660		= dynamic_cast<DirectoryDescriptor*>(get_descriptor(fd));
661	if (!descriptor)
662		return B_FILE_ERROR;
663
664	// get the next entry
665	dirent *entry;
666	errno = 0;
667	if (dynamic_cast<AttrDirDescriptor*>(descriptor))
668		entry = fs_read_attr_dir(descriptor->dir);
669	else
670		entry = readdir(descriptor->dir);
671	if (!entry)
672		return errno;
673
674	// copy the entry
675	int entryLen = &entry->d_name[strlen(entry->d_name) + 1] - (char*)entry;
676	if (entryLen > (int)bufferSize)
677		return B_BUFFER_OVERFLOW;
678
679	memcpy(buffer, entry, entryLen);
680
681	return 1;
682}
683
684// _kern_rewind_dir
685status_t
686_kern_rewind_dir(int fd)
687{
688	// get the descriptor
689	DirectoryDescriptor *descriptor
690		= dynamic_cast<DirectoryDescriptor*>(get_descriptor(fd));
691	if (!descriptor)
692		return B_FILE_ERROR;
693
694	// rewind
695	if (dynamic_cast<AttrDirDescriptor*>(descriptor))
696		fs_rewind_attr_dir(descriptor->dir);
697	else
698		rewinddir(descriptor->dir);
699
700	return B_OK;
701}
702
703
704// #pragma mark -
705
706// open_file
707static int
708open_file(const char *path, int openMode, int perms)
709{
710	// stat the node
711	bool exists = true;
712	struct stat st;
713	if (lstat(path, &st) < 0) {
714		exists = false;
715		if (!(openMode & O_CREAT))
716			return errno;
717	}
718
719	Descriptor *descriptor;
720	if (exists && S_ISLNK(st.st_mode) && (openMode & O_NOTRAVERSE) != 0) {
721		// a symlink not to be followed: create a special descriptor
722		// normalize path first
723		string normalizedPath;
724		status_t error = normalize_entry_path(path, normalizedPath);
725		if (error != B_OK)
726			return error;
727
728		descriptor = new SymlinkDescriptor(normalizedPath.c_str());
729	} else {
730		// open the file
731		openMode &= ~O_NOTRAVERSE;
732		int newFD = open(path, openMode, perms);
733		if (newFD < 0)
734			return errno;
735
736		descriptor = new FileDescriptor(newFD);
737	}
738
739	// cache path, if this is a directory
740	if (exists && S_ISDIR(st.st_mode))
741		add_dir_path(path, NodeRef(st));
742
743	return add_descriptor(descriptor);
744}
745
746// _kern_open
747int
748_kern_open(int fd, const char *path, int openMode, int perms)
749{
750	// get a usable path
751	string realPath;
752	status_t error = get_path(fd, path, realPath);
753	if (error != B_OK)
754		return error;
755
756	return open_file(realPath.c_str(), openMode, perms);
757}
758
759// _kern_open_entry_ref
760int
761_kern_open_entry_ref(dev_t device, ino_t node, const char *name,
762	int openMode, int perms)
763{
764	// get a usable path
765	string realPath;
766	status_t error = get_path(device, node, name, realPath);
767	if (error != B_OK)
768		return error;
769
770	return open_file(realPath.c_str(), openMode, perms);
771}
772
773// _kern_seek
774off_t
775_kern_seek(int fd, off_t pos, int seekType)
776{
777	// get the descriptor
778	FileDescriptor *descriptor
779		= dynamic_cast<FileDescriptor*>(get_descriptor(fd));
780	if (!descriptor)
781		return B_FILE_ERROR;
782
783	// seek
784	off_t result = lseek(descriptor->fd, pos, seekType);
785	if (result < 0)
786		return errno;
787
788	return result;
789}
790
791// _kern_read
792ssize_t
793_kern_read(int fd, off_t pos, void *buffer, size_t bufferSize)
794{
795	// get the descriptor
796	FileDescriptor *descriptor
797		= dynamic_cast<FileDescriptor*>(get_descriptor(fd));
798	if (!descriptor)
799		return B_FILE_ERROR;
800
801	// seek
802	if (pos != -1) {
803		off_t result = lseek(descriptor->fd, pos, SEEK_SET);
804		if (result < 0)
805			return errno;
806	}
807
808	// read
809	ssize_t bytesRead = haiku_host_platform_read(descriptor->fd, buffer,
810		bufferSize);
811	if (bytesRead < 0)
812		return errno;
813
814	return bytesRead;
815}
816
817// _kern_write
818ssize_t
819_kern_write(int fd, off_t pos, const void *buffer, size_t bufferSize)
820{
821	// get the descriptor
822	FileDescriptor *descriptor
823		= dynamic_cast<FileDescriptor*>(get_descriptor(fd));
824	if (!descriptor)
825		return B_FILE_ERROR;
826
827	// seek
828	if (pos != -1) {
829		off_t result = lseek(descriptor->fd, pos, SEEK_SET);
830		if (result < 0)
831			return errno;
832	}
833
834	// read
835	ssize_t bytesWritten = haiku_host_platform_write(descriptor->fd, buffer,
836		bufferSize);
837	if (bytesWritten < 0)
838		return errno;
839
840	return bytesWritten;
841}
842
843// _kern_close
844status_t
845_kern_close(int fd)
846{
847	return delete_descriptor(fd);
848}
849
850// _kern_dup
851int
852_kern_dup(int fd)
853{
854	// get the descriptor
855	Descriptor *descriptor = get_descriptor(fd);
856	if (!descriptor)
857		return B_FILE_ERROR;
858
859	// clone it
860	Descriptor *clone;
861	status_t error = descriptor->Dup(clone);
862	if (error != B_OK)
863		return error;
864
865	return add_descriptor(clone);
866}
867
868// _kern_fsync
869status_t
870_kern_fsync(int fd)
871{
872	// get the descriptor
873	FileDescriptor *descriptor
874		= dynamic_cast<FileDescriptor*>(get_descriptor(fd));
875	if (!descriptor)
876		return B_FILE_ERROR;
877
878	// sync
879	if (fsync(descriptor->fd) < 0)
880		return errno;
881
882	return B_OK;
883}
884
885// _kern_read_stat
886status_t
887_kern_read_stat(int fd, const char *path, bool traverseLink,
888	struct stat *st, size_t statSize)
889{
890	if (path) {
891		// get a usable path
892		string realPath;
893		status_t error = get_path(fd, path, realPath);
894		if (error != B_OK)
895			return error;
896
897		// stat
898		int result;
899		if (traverseLink)
900			result = stat(realPath.c_str(), st);
901		else
902			result = lstat(realPath.c_str(), st);
903
904		if (result < 0)
905			return errno;
906	} else {
907		Descriptor *descriptor = get_descriptor(fd);
908		if (!descriptor)
909			return B_FILE_ERROR;
910
911		return descriptor->GetStat(traverseLink, st);
912	}
913
914	return B_OK;
915}
916
917// _kern_write_stat
918status_t
919_kern_write_stat(int fd, const char *path, bool traverseLink,
920	const struct stat *st, size_t statSize, int statMask)
921{
922	// get a usable path
923	int realFD = -1;
924	string realPath;
925	status_t error;
926	bool isSymlink = false;
927	if (path) {
928		error = get_path(fd, path, realPath);
929		if (error != B_OK)
930			return error;
931
932		// stat it to see, if it is a symlink
933		struct stat tmpStat;
934		if (lstat(realPath.c_str(), &tmpStat) < 0)
935			return errno;
936
937		isSymlink = S_ISLNK(tmpStat.st_mode);
938
939	} else {
940		Descriptor *descriptor = get_descriptor(fd);
941		if (!descriptor)
942			return B_FILE_ERROR;
943
944		if (FileDescriptor *fileFD
945				= dynamic_cast<FileDescriptor*>(descriptor)) {
946			realFD = fileFD->fd;
947
948		} else if (dynamic_cast<DirectoryDescriptor*>(descriptor)) {
949			error = get_path(fd, NULL, realPath);
950			if (error != B_OK)
951				return error;
952
953		} else if (SymlinkDescriptor *linkFD
954				= dynamic_cast<SymlinkDescriptor*>(descriptor)) {
955			realPath = linkFD->path;
956			isSymlink = true;
957
958		} else
959			return B_FILE_ERROR;
960	}
961
962	// We're screwed, if the node to manipulate is a symlink. All the
963	// available functions traverse symlinks.
964	if (isSymlink && !traverseLink)
965		return B_ERROR;
966
967	if (realFD >= 0) {
968		if (statMask & B_STAT_MODE) {
969			if (fchmod(realFD, st->st_mode) < 0)
970				return errno;
971		}
972
973		if (statMask & B_STAT_UID) {
974			if (fchown(realFD, st->st_uid, (gid_t)-1) < 0)
975				return errno;
976		}
977
978		if (statMask & B_STAT_GID) {
979			if (fchown(realFD, (uid_t)-1, st->st_gid) < 0)
980				return errno;
981		}
982
983		if (statMask & B_STAT_SIZE) {
984			if (ftruncate(realFD, st->st_size) < 0)
985				return errno;
986		}
987
988		// The timestamps can only be set via utime(), but that requires a
989		// path we don't have.
990		if (statMask & (B_STAT_ACCESS_TIME | B_STAT_MODIFICATION_TIME
991				| B_STAT_CREATION_TIME | B_STAT_CHANGE_TIME)) {
992			return B_ERROR;
993		}
994
995		return 0;
996
997	} else {
998		if (statMask & B_STAT_MODE) {
999			if (chmod(realPath.c_str(), st->st_mode) < 0)
1000				return errno;
1001		}
1002
1003		if (statMask & B_STAT_UID) {
1004			if (chown(realPath.c_str(), st->st_uid, (gid_t)-1) < 0)
1005				return errno;
1006		}
1007
1008		if (statMask & B_STAT_GID) {
1009			if (chown(realPath.c_str(), (uid_t)-1, st->st_gid) < 0)
1010				return errno;
1011		}
1012
1013		if (statMask & B_STAT_SIZE) {
1014			if (truncate(realPath.c_str(), st->st_size) < 0)
1015				return errno;
1016		}
1017
1018		if (statMask & (B_STAT_ACCESS_TIME | B_STAT_MODIFICATION_TIME)) {
1019			// Grab the previous mod and access times so we only overwrite
1020			// the specified time and not both
1021			struct stat oldStat;
1022			if (~statMask & (B_STAT_ACCESS_TIME | B_STAT_MODIFICATION_TIME)) {
1023				if (stat(realPath.c_str(), &oldStat) < 0)
1024					return errno;
1025			}
1026
1027			utimbuf buffer;
1028			buffer.actime = (statMask & B_STAT_ACCESS_TIME) ? st->st_atime : oldStat.st_atime;
1029			buffer.modtime = (statMask & B_STAT_MODIFICATION_TIME) ? st->st_mtime : oldStat.st_mtime;
1030			if (utime(realPath.c_str(), &buffer) < 0)
1031				return errno;
1032		}
1033
1034		// not supported
1035		if (statMask & (B_STAT_CREATION_TIME | B_STAT_CHANGE_TIME))
1036			return B_ERROR;
1037	}
1038
1039	return B_OK;
1040}
1041
1042
1043// #pragma mark -
1044
1045// _kern_create_symlink
1046status_t
1047_kern_create_symlink(int fd, const char *path, const char *toPath, int mode)
1048{
1049	// Note: path must not be NULL, so this will always work.
1050	// get a usable path
1051	string realPath;
1052	status_t error = get_path(fd, path, realPath);
1053	if (error != B_OK)
1054		return error;
1055
1056	// symlink
1057	if (symlink(toPath, realPath.c_str()) < 0)
1058		return errno;
1059
1060	return B_OK;
1061}
1062
1063// _kern_read_link
1064status_t
1065_kern_read_link(int fd, const char *path, char *buffer, size_t *_bufferSize)
1066{
1067	// get the path
1068	string realPath;
1069	status_t error = get_path(fd, path, realPath);
1070	if (error != B_OK)
1071		return error;
1072
1073	// readlink
1074	ssize_t bytesRead = readlink(realPath.c_str(), buffer, *_bufferSize);
1075	if (bytesRead < 0)
1076		return errno;
1077
1078	if (*_bufferSize > 0) {
1079		if ((size_t)bytesRead == *_bufferSize)
1080			bytesRead--;
1081
1082		buffer[bytesRead] = '\0';
1083	}
1084
1085	*_bufferSize = bytesRead;
1086
1087	return B_OK;
1088}
1089
1090// _kern_unlink
1091status_t
1092_kern_unlink(int fd, const char *path)
1093{
1094	// get a usable path
1095	string realPath;
1096	status_t error = get_path(fd, path, realPath);
1097	if (error != B_OK)
1098		return error;
1099
1100	// unlink
1101	if (unlink(realPath.c_str()) < 0)
1102		return errno;
1103
1104	return B_OK;
1105}
1106
1107// _kern_rename
1108status_t
1109_kern_rename(int oldDir, const char *oldPath, int newDir, const char *newPath)
1110{
1111	// get usable paths
1112	string realOldPath;
1113	status_t error = get_path(oldDir, oldPath, realOldPath);
1114	if (error != B_OK)
1115		return error;
1116
1117	string realNewPath;
1118	error = get_path(newDir, newPath, realNewPath);
1119	if (error != B_OK)
1120		return error;
1121
1122	// rename
1123	if (rename(realOldPath.c_str(), realNewPath.c_str()) < 0)
1124		return errno;
1125
1126	return B_OK;
1127}
1128
1129
1130// #pragma mark -
1131
1132// _kern_lock_node
1133status_t
1134_kern_lock_node(int fd)
1135{
1136	return B_ERROR;
1137}
1138
1139// _kern_unlock_node
1140status_t
1141_kern_unlock_node(int fd)
1142{
1143	return B_ERROR;
1144}
1145
1146
1147// #pragma mark -
1148
1149// read_pos
1150ssize_t
1151read_pos(int fd, off_t pos, void *buffer, size_t bufferSize)
1152{
1153	// seek
1154	off_t result = lseek(fd, pos, SEEK_SET);
1155	if (result < 0)
1156		return errno;
1157
1158	// read
1159	ssize_t bytesRead = haiku_host_platform_read(fd, buffer, bufferSize);
1160	if (bytesRead < 0) {
1161		errno = bytesRead;
1162		return -1;
1163	}
1164
1165	return bytesRead;
1166}
1167
1168// write_pos
1169ssize_t
1170write_pos(int fd, off_t pos, const void *buffer, size_t bufferSize)
1171{
1172	// If this is an attribute descriptor, let it do the job.
1173	AttributeDescriptor* descriptor
1174		= dynamic_cast<AttributeDescriptor*>(get_descriptor(fd));
1175	if (descriptor != NULL) {
1176		status_t error = descriptor->Write(pos, buffer, bufferSize);
1177		if (error != B_OK) {
1178			errno = error;
1179			return -1;
1180		}
1181
1182		return bufferSize;
1183	}
1184
1185	// seek
1186	off_t result = lseek(fd, pos, SEEK_SET);
1187	if (result < 0)
1188		return errno;
1189
1190	// write
1191	ssize_t bytesWritten = haiku_host_platform_write(fd, buffer, bufferSize);
1192	if (bytesWritten < 0) {
1193		errno = bytesWritten;
1194		return -1;
1195	}
1196
1197	return bytesWritten;
1198}
1199
1200// readv_pos
1201ssize_t
1202readv_pos(int fd, off_t pos, const struct iovec *vec, size_t count)
1203{
1204	// seek
1205	off_t result = lseek(fd, pos, SEEK_SET);
1206	if (result < 0)
1207		return errno;
1208
1209	// read
1210	ssize_t bytesRead = haiku_host_platform_readv(fd, vec, count);
1211	if (bytesRead < 0) {
1212		errno = bytesRead;
1213		return -1;
1214	}
1215
1216	return bytesRead;
1217}
1218
1219// writev_pos
1220ssize_t
1221writev_pos(int fd, off_t pos, const struct iovec *vec, size_t count)
1222{
1223	// seek
1224	off_t result = lseek(fd, pos, SEEK_SET);
1225	if (result < 0)
1226		return errno;
1227
1228	// read
1229	ssize_t bytesWritten = haiku_host_platform_writev(fd, vec, count);
1230	if (bytesWritten < 0) {
1231		errno = bytesWritten;
1232		return -1;
1233	}
1234
1235	return bytesWritten;
1236}
1237
1238
1239// #pragma mark -
1240
1241
1242int
1243_haiku_build_fchmod(int fd, mode_t mode)
1244{
1245	return _haiku_build_fchmodat(fd, NULL, mode, AT_SYMLINK_NOFOLLOW);
1246}
1247
1248
1249int
1250_haiku_build_fchmodat(int fd, const char* path, mode_t mode, int flag)
1251{
1252	if (fd >= 0 && fd != AT_FDCWD && get_descriptor(fd) == NULL)
1253		return fchmodat(fd, path, mode, flag);
1254
1255	struct stat st;
1256	st.st_mode = mode;
1257
1258	RETURN_AND_SET_ERRNO(_kern_write_stat(fd, path,
1259		(flag & AT_SYMLINK_NOFOLLOW) == 0, &st, sizeof(st), B_STAT_MODE));
1260}
1261
1262
1263int
1264_haiku_build_fstat(int fd, struct stat* st)
1265{
1266	return _haiku_build_fstatat(fd, NULL, st, AT_SYMLINK_NOFOLLOW);
1267}
1268
1269
1270int
1271_haiku_build_fstatat(int fd, const char* path, struct stat* st, int flag)
1272{
1273	if (fd >= 0 && fd != AT_FDCWD && get_descriptor(fd) == NULL)
1274		return fstatat(fd, path, st, flag);
1275
1276	RETURN_AND_SET_ERRNO(_kern_read_stat(fd, path,
1277		(flag & AT_SYMLINK_NOFOLLOW) == 0, st, sizeof(*st)));
1278}
1279
1280
1281int
1282_haiku_build_mkdirat(int fd, const char* path, mode_t mode)
1283{
1284	if (fd >= 0 && fd != AT_FDCWD && get_descriptor(fd) == NULL)
1285		return mkdirat(fd, path, mode);
1286
1287	RETURN_AND_SET_ERRNO(_kern_create_dir(fd, path, mode));
1288}
1289
1290
1291int
1292_haiku_build_mkfifoat(int fd, const char* path, mode_t mode)
1293{
1294	return mkfifoat(fd, path, mode);
1295
1296	// TODO: Handle non-system FDs.
1297}
1298
1299
1300int
1301_haiku_build_utimensat(int fd, const char* path, const struct timespec times[2],
1302	int flag)
1303{
1304	if (fd >= 0 && fd != AT_FDCWD && get_descriptor(fd) == NULL)
1305		return utimensat(fd, path, times, flag);
1306
1307	struct stat stat;
1308	status_t status;
1309	uint32 mask = 0;
1310
1311	// Init the stat time fields to the current time, if at least one time is
1312	// supposed to be set to it.
1313	if (times == NULL || times[0].tv_nsec == UTIME_NOW
1314		|| times[1].tv_nsec == UTIME_NOW) {
1315		timeval now;
1316		gettimeofday(&now, NULL);
1317		HAIKU_HOST_STAT_ATIM(stat).tv_sec
1318			= HAIKU_HOST_STAT_MTIM(stat).tv_sec = now.tv_sec;
1319		HAIKU_HOST_STAT_ATIM(stat).tv_nsec
1320			= HAIKU_HOST_STAT_MTIM(stat).tv_nsec = now.tv_usec * 1000;
1321	}
1322
1323	if (times != NULL) {
1324		// access time
1325		if (times[0].tv_nsec != UTIME_OMIT) {
1326			mask |= B_STAT_ACCESS_TIME;
1327
1328			if (times[0].tv_nsec != UTIME_NOW) {
1329				if (times[0].tv_nsec < 0 || times[0].tv_nsec > 999999999)
1330					RETURN_AND_SET_ERRNO(EINVAL);
1331			}
1332
1333			HAIKU_HOST_STAT_ATIM(stat) = times[0];
1334		}
1335
1336		// modified time
1337		if (times[1].tv_nsec != UTIME_OMIT) {
1338			mask |= B_STAT_MODIFICATION_TIME;
1339
1340			if (times[1].tv_nsec != UTIME_NOW) {
1341				if (times[1].tv_nsec < 0 || times[1].tv_nsec > 999999999)
1342					RETURN_AND_SET_ERRNO(EINVAL);
1343			}
1344
1345			HAIKU_HOST_STAT_MTIM(stat) = times[1];
1346		}
1347	} else
1348		mask |= B_STAT_ACCESS_TIME | B_STAT_MODIFICATION_TIME;
1349
1350	// set the times -- as per spec we even need to do this, if both have
1351	// UTIME_OMIT set
1352	status = _kern_write_stat(fd, path, (flag & AT_SYMLINK_NOFOLLOW) == 0,
1353		&stat, sizeof(struct stat), mask);
1354
1355	RETURN_AND_SET_ERRNO(status);
1356}
1357
1358
1359int
1360_haiku_build_futimens(int fd, const struct timespec times[2])
1361{
1362	return _haiku_build_utimensat(fd, NULL, times, AT_SYMLINK_NOFOLLOW);
1363}
1364
1365
1366int
1367_haiku_build_faccessat(int fd, const char* path, int accessMode, int flag)
1368{
1369	if (fd >= 0 && fd != AT_FDCWD && get_descriptor(fd) == NULL)
1370		return faccessat(fd, path, accessMode, flag);
1371
1372	// stat the file
1373	struct stat st;
1374	status_t error = _kern_read_stat(fd, path, false, &st, sizeof(st));
1375	if (error != B_OK)
1376		RETURN_AND_SET_ERRNO(error);
1377
1378	// get the current user
1379	uid_t uid = (flag & AT_EACCESS) != 0 ? geteuid() : getuid();
1380
1381	int fileMode = 0;
1382
1383	if (uid == 0) {
1384		// user is root
1385		// root has always read/write permission, but at least one of the
1386		// X bits must be set for execute permission
1387		fileMode = R_OK | W_OK;
1388		if ((st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) != 0)
1389			fileMode |= X_OK;
1390	} else if (st.st_uid == uid) {
1391		// user is node owner
1392		if ((st.st_mode & S_IRUSR) != 0)
1393			fileMode |= R_OK;
1394		if ((st.st_mode & S_IWUSR) != 0)
1395			fileMode |= W_OK;
1396		if ((st.st_mode & S_IXUSR) != 0)
1397			fileMode |= X_OK;
1398	} else if (st.st_gid == ((flag & AT_EACCESS) != 0 ? getegid() : getgid())) {
1399		// user is in owning group
1400		if ((st.st_mode & S_IRGRP) != 0)
1401			fileMode |= R_OK;
1402		if ((st.st_mode & S_IWGRP) != 0)
1403			fileMode |= W_OK;
1404		if ((st.st_mode & S_IXGRP) != 0)
1405			fileMode |= X_OK;
1406	} else {
1407		// user is one of the others
1408		if ((st.st_mode & S_IROTH) != 0)
1409			fileMode |= R_OK;
1410		if ((st.st_mode & S_IWOTH) != 0)
1411			fileMode |= W_OK;
1412		if ((st.st_mode & S_IXOTH) != 0)
1413			fileMode |= X_OK;
1414	}
1415
1416	if ((accessMode & ~fileMode) != 0)
1417		RETURN_AND_SET_ERRNO(EACCES);
1418
1419	return 0;
1420}
1421
1422
1423int
1424_haiku_build_fchdir(int fd)
1425{
1426	if (is_unknown_or_system_descriptor(fd))
1427		return fchdir(fd);
1428
1429	RETURN_AND_SET_ERRNO(B_FILE_ERROR);
1430}
1431
1432
1433int
1434_haiku_build_close(int fd)
1435{
1436	if (get_descriptor(fd) == NULL)
1437		return close(fd);
1438
1439	RETURN_AND_SET_ERRNO(_kern_close(fd));
1440}
1441
1442
1443int
1444_haiku_build_dup(int fd)
1445{
1446	if (get_descriptor(fd) == NULL)
1447		return close(fd);
1448
1449	RETURN_AND_SET_ERRNO(_kern_dup(fd));
1450}
1451
1452
1453int
1454_haiku_build_dup2(int fd1, int fd2)
1455{
1456	if (is_unknown_or_system_descriptor(fd1))
1457		return dup2(fd1, fd2);
1458
1459	// TODO: Handle non-system FDs.
1460	RETURN_AND_SET_ERRNO(B_NOT_SUPPORTED);
1461}
1462
1463
1464int
1465_haiku_build_linkat(int toFD, const char* toPath, int pathFD, const char* path,
1466	int flag)
1467{
1468	return linkat(toFD, toPath, pathFD, path, flag);
1469
1470	// TODO: Handle non-system FDs.
1471}
1472
1473
1474int
1475_haiku_build_unlinkat(int fd, const char* path, int flag)
1476{
1477	if (fd >= 0 && fd != AT_FDCWD && get_descriptor(fd) == NULL)
1478		return unlinkat(fd, path, flag);
1479
1480	RETURN_AND_SET_ERRNO(_kern_unlink(fd, path));
1481}
1482
1483
1484ssize_t
1485_haiku_build_readlinkat(int fd, const char* path, char* buffer,
1486	size_t bufferSize)
1487{
1488	if (fd >= 0 && fd != AT_FDCWD && get_descriptor(fd) == NULL)
1489		return readlinkat(fd, path, buffer, bufferSize);
1490
1491	status_t error = _kern_read_link(fd, path, buffer, &bufferSize);
1492	if (error != B_OK)
1493		RETURN_AND_SET_ERRNO(error);
1494
1495	return bufferSize;
1496}
1497
1498
1499int
1500_haiku_build_symlinkat(const char* toPath, int fd, const char* symlinkPath)
1501{
1502	if (fd >= 0 && fd != AT_FDCWD && get_descriptor(fd) == NULL)
1503		return symlinkat(toPath, fd, symlinkPath);
1504
1505	RETURN_AND_SET_ERRNO(_kern_create_symlink(fd, symlinkPath, toPath,
1506		S_IRWXU | S_IRWXG | S_IRWXO));
1507}
1508
1509
1510int
1511_haiku_build_ftruncate(int fd, off_t newSize)
1512{
1513	if (fd >= 0 && fd != AT_FDCWD && get_descriptor(fd) == NULL)
1514		return ftruncate(fd, newSize);
1515
1516	struct stat st;
1517	st.st_size = newSize;
1518
1519	RETURN_AND_SET_ERRNO(_kern_write_stat(fd, NULL, false, &st, sizeof(st),
1520		B_STAT_SIZE));
1521}
1522
1523
1524int
1525_haiku_build_fchown(int fd, uid_t owner, gid_t group)
1526{
1527	return _haiku_build_fchownat(fd, NULL, owner, group, AT_SYMLINK_NOFOLLOW);
1528}
1529
1530
1531int
1532_haiku_build_fchownat(int fd, const char* path, uid_t owner, gid_t group,
1533	int flag)
1534{
1535	if (fd >= 0 && fd != AT_FDCWD && get_descriptor(fd) == NULL)
1536		return fchownat(fd, path, owner, group, flag);
1537
1538	struct stat st;
1539	st.st_uid = owner;
1540	st.st_gid = group;
1541
1542	RETURN_AND_SET_ERRNO(_kern_write_stat(fd, path,
1543		(flag & AT_SYMLINK_NOFOLLOW) == 0, &st, sizeof(st),
1544		B_STAT_UID | B_STAT_GID));
1545}
1546
1547
1548int
1549_haiku_build_mknodat(int fd, const char* name, mode_t mode, dev_t dev)
1550{
1551	return mknodat(fd, name, mode, dev);
1552
1553	// TODO: Handle non-system FDs.
1554}
1555
1556
1557int
1558_haiku_build_creat(const char* path, mode_t mode)
1559{
1560	return _haiku_build_open(path, O_WRONLY | O_CREAT | O_TRUNC, mode);
1561}
1562
1563
1564int
1565_haiku_build_open(const char* path, int openMode, mode_t permissions)
1566{
1567	return _haiku_build_openat(AT_FDCWD, path, openMode, permissions);
1568}
1569
1570
1571int
1572_haiku_build_openat(int fd, const char* path, int openMode, mode_t permissions)
1573{
1574	// adapt the permissions as required by POSIX
1575	mode_t mask = umask(0);
1576	umask(mask);
1577	permissions &= ~mask;
1578
1579	RETURN_AND_SET_ERRNO(_kern_open(fd, path, openMode, permissions));
1580}
1581
1582
1583int
1584_haiku_build_fcntl(int fd, int op, int argument)
1585{
1586	if (is_unknown_or_system_descriptor(fd))
1587		return fcntl(fd, op, argument);
1588
1589	RETURN_AND_SET_ERRNO(B_NOT_SUPPORTED);
1590}
1591
1592
1593int
1594_haiku_build_renameat(int fromFD, const char* from, int toFD, const char* to)
1595{
1596	if ((fromFD >= 0 && fromFD != AT_FDCWD && get_descriptor(fromFD) == NULL)
1597		|| (toFD >= 0 && toFD != AT_FDCWD && get_descriptor(toFD) == NULL)) {
1598		return renameat(fromFD, from, toFD, to);
1599	}
1600
1601	RETURN_AND_SET_ERRNO(_kern_rename(fromFD, from, toFD, to));
1602}
1603