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
239// find_dir_entry
240static status_t
241find_dir_entry(const char *path, NodeRef ref, string &name, bool skipDot)
242{
243	// open dir
244	DIR *dir = opendir(path);
245	if (!dir)
246		return errno;
247
248	status_t error = find_dir_entry(dir, path, ref, name, skipDot);
249
250	// close dir
251	closedir(dir);
252
253	return error;
254}
255
256
257// normalize_dir_path: Make path absolute and remove redundant entries.
258static status_t
259normalize_dir_path(const char *path, string &normalizedPath)
260{
261	const size_t pathLen = strlen(path);
262
263	// Add CWD to relative paths.
264	if (pathLen == 0 || path[0] != '/') {
265		char pwd[PATH_MAX];
266		if (getcwd(pwd, sizeof(pwd)) == NULL)
267			return B_ERROR;
268
269		normalizedPath = pwd;
270	}
271
272	const char *end = &path[pathLen];
273	const char *next;
274	for (const char *ptr = path; ptr < end; ptr = next + 1) {
275		next = (char *)memchr(ptr, '/', end - ptr);
276		if (next == NULL)
277			next = end;
278
279		size_t len = next - ptr;
280		if (len == 2 && ptr[0] == '.' && ptr[1] == '.') {
281			string::size_type pos = normalizedPath.rfind('/');
282			if (pos != string::npos)
283				normalizedPath.resize(pos);
284			continue;
285		} else if (len == 0 || (len == 1 && ptr[0] == '.')) {
286			continue;
287		}
288
289		if (normalizedPath.length() != 1)
290			normalizedPath += '/';
291
292		normalizedPath.append(ptr, len);
293	}
294
295	if (normalizedPath.length() == 0)
296		normalizedPath += '/';
297
298	return B_OK;
299}
300
301
302// normalize_entry_path
303static status_t
304normalize_entry_path(const char *path, string &normalizedPath)
305{
306	const char *dirPath = NULL;
307	const char *leafName = NULL;
308
309	string dirPathString;
310	if (const char *lastSlash = strrchr(path, '/')) {
311		// found a slash: decompose into dir path and leaf name
312		leafName = lastSlash + 1;
313		if (leafName[0] == '\0') {
314			// slash is at the end: the whole path is a dir name
315			leafName = NULL;
316		} else {
317			dirPathString = string(path, leafName - path);
318			dirPath = dirPathString.c_str();
319		}
320	} else {
321		// path contains no slash, so it is a path relative to the current dir
322		dirPath = ".";
323		leafName = path;
324	}
325
326	// catch special case: no leaf, or leaf is a directory
327	if (!leafName || strcmp(leafName, ".") == 0 || strcmp(leafName, "..") == 0)
328		return normalize_dir_path(path, normalizedPath);
329
330	// normalize the dir path
331	status_t error = normalize_dir_path(dirPath, normalizedPath);
332	if (error != B_OK)
333		return error;
334
335	// append the leaf name
336	if (normalizedPath.length() > 1) // don't append "/", if parent is root
337		normalizedPath += '/';
338	normalizedPath += leafName;
339
340	return B_OK;
341}
342
343
344// #pragma mark -
345
346typedef map<NodeRef, string> DirPathMap;
347static DirPathMap sDirPathMap;
348
349// get_path
350static status_t
351get_path(const NodeRef *ref, const char *name, string &path)
352{
353	if (!ref && !name)
354		return B_BAD_VALUE;
355
356	// no ref or absolute path
357	if (!ref || (name && name[0] == '/')) {
358		path = name;
359		return B_OK;
360	}
361
362	// get the dir path
363	if (ref) {
364		DirPathMap::iterator it = sDirPathMap.find(*ref);
365		if (it == sDirPathMap.end())
366			return B_ENTRY_NOT_FOUND;
367
368		path = it->second;
369
370		// stat the path to check, if it is still valid
371		struct stat st;
372		if (stat(path.c_str(), &st) < 0) {
373			sDirPathMap.erase(it);
374			return errno;
375		}
376
377		// compare the NodeRef
378		if (NodeRef(st) != *ref) {
379			sDirPathMap.erase(it);
380			return B_ENTRY_NOT_FOUND;
381		}
382
383		// still a directory?
384		if (!S_ISDIR(st.st_mode)) {
385			sDirPathMap.erase(it);
386			return B_NOT_A_DIRECTORY;
387		}
388	}
389
390	// if there's a name, append it
391	if (name) {
392		path += '/';
393		path += name;
394	}
395
396	return B_OK;
397}
398
399// get_path
400status_t
401BPrivate::get_path(int fd, const char *name, string &path)
402{
403	// get the node ref for the fd, if any, and the path part is not absolute
404	if (fd >= 0 && !(name && name[0] == '/')) {
405		// get descriptor
406		Descriptor *descriptor = get_descriptor(fd);
407		if (!descriptor)
408			return B_FILE_ERROR;
409
410		// Handle symlink descriptors here explicitly, so this function can be
411		// used more flexibly.
412		if (SymlinkDescriptor* symlinkDescriptor
413				= dynamic_cast<SymlinkDescriptor*>(descriptor)) {
414			path = symlinkDescriptor->path;
415			if (name == NULL)
416				return B_OK;
417			path += '/';
418			path += name;
419			return B_OK;
420		}
421
422		// get node ref for the descriptor
423		NodeRef ref;
424		status_t error = descriptor->GetNodeRef(ref);
425		if (error != B_OK)
426			return error;
427
428		return ::get_path(&ref, name, path);
429
430	} else	// no descriptor or absolute path
431		return ::get_path((NodeRef*)NULL, name, path);
432}
433
434// get_path
435static status_t
436get_path(dev_t device, ino_t directory, const char *name, string &path)
437{
438	NodeRef ref;
439	ref.device = device;
440	ref.node = directory;
441
442	return get_path(&ref, name, path);
443}
444
445// add_dir_path
446static void
447add_dir_path(const char *path, const NodeRef &ref)
448{
449	// add the normalized path
450	string normalizedPath;
451	if (normalize_dir_path(path, normalizedPath) == B_OK)
452		sDirPathMap[ref] = normalizedPath;
453}
454
455
456// #pragma mark -
457
458// _kern_entry_ref_to_path
459status_t
460_kern_entry_ref_to_path(dev_t device, ino_t node, const char *leaf,
461	char *userPath, size_t pathLength)
462{
463	// get the path
464	string path;
465	status_t error = get_path(device, node, leaf, path);
466	if (error != B_OK)
467		return error;
468
469	// copy it back to the user buffer
470	if (strlcpy(userPath, path.c_str(), pathLength) >= pathLength)
471		return B_BUFFER_OVERFLOW;
472
473	return B_OK;
474}
475
476
477// #pragma mark -
478
479// _kern_create_dir
480status_t
481_kern_create_dir(int fd, const char *path, int perms)
482{
483	// get a usable path
484	string realPath;
485	status_t error = get_path(fd, path, realPath);
486	if (error != B_OK)
487		return error;
488
489	// mkdir
490	if (mkdir(realPath.c_str(), perms) < 0)
491		return errno;
492
493	return B_OK;
494}
495
496// _kern_create_dir_entry_ref
497status_t
498_kern_create_dir_entry_ref(dev_t device, ino_t node, const char *name,
499	int perms)
500{
501	// get a usable path
502	string realPath;
503	status_t error = get_path(device, node, name, realPath);
504	if (error != B_OK)
505		return error;
506
507	// mkdir
508	if (mkdir(realPath.c_str(), perms) < 0)
509		return errno;
510
511	return B_OK;
512}
513
514// open_dir
515static int
516open_dir(const char *path)
517{
518	// open the dir
519	DIR *dir = opendir(path);
520	if (!dir)
521		return errno;
522
523	// stat the entry
524	struct stat st;
525	if (stat(path, &st) < 0) {
526		closedir(dir);
527		return errno;
528	}
529
530	if (!S_ISDIR(st.st_mode)) {
531		closedir(dir);
532		return B_NOT_A_DIRECTORY;
533	}
534
535	// cache dir path
536	NodeRef ref(st);
537	add_dir_path(path, ref);
538
539	// create descriptor
540	DirectoryDescriptor *descriptor = new DirectoryDescriptor(dir, ref);
541	return add_descriptor(descriptor);
542}
543
544// _kern_open_dir
545int
546_kern_open_dir(int fd, const char *path)
547{
548	// get a usable path
549	string realPath;
550	status_t error = get_path(fd, path, realPath);
551	if (error != B_OK)
552		return error;
553
554	return open_dir(realPath.c_str());
555}
556
557// _kern_open_dir_entry_ref
558int
559_kern_open_dir_entry_ref(dev_t device, ino_t node, const char *name)
560{
561	// get a usable path
562	string realPath;
563	status_t error = get_path(device, node, name, realPath);
564	if (error != B_OK)
565		return error;
566
567	return open_dir(realPath.c_str());
568}
569
570// _kern_open_parent_dir
571int
572_kern_open_parent_dir(int fd, char *name, size_t nameLength)
573{
574	// get a usable path
575	string realPath;
576	status_t error = get_path(fd, NULL, realPath);
577	if (error != B_OK)
578		return error;
579
580	// stat the entry
581	struct stat st;
582	if (stat(realPath.c_str(), &st) < 0)
583		return errno;
584
585	if (!S_ISDIR(st.st_mode))
586		return B_NOT_A_DIRECTORY;
587
588	// get the entry name
589	realPath += "/..";
590	string entryName;
591	error = find_dir_entry(realPath.c_str(), NodeRef(st),
592		entryName, false);
593	if (error != B_OK)
594		return error;
595
596	if (strlcpy(name, entryName.c_str(), nameLength) >= nameLength)
597		return B_BUFFER_OVERFLOW;
598
599	// open the parent directory
600
601	return open_dir(realPath.c_str());
602}
603
604// _kern_read_dir
605ssize_t
606_kern_read_dir(int fd, struct dirent *buffer, size_t bufferSize,
607	uint32 maxCount)
608{
609	if (maxCount <= 0)
610		return B_BAD_VALUE;
611
612	// get the descriptor
613	DirectoryDescriptor *descriptor
614		= dynamic_cast<DirectoryDescriptor*>(get_descriptor(fd));
615	if (!descriptor)
616		return B_FILE_ERROR;
617
618	// get the next entry
619	dirent *entry;
620	errno = 0;
621	if (dynamic_cast<AttrDirDescriptor*>(descriptor))
622		entry = fs_read_attr_dir(descriptor->dir);
623	else
624		entry = readdir(descriptor->dir);
625	if (!entry)
626		return errno;
627
628	// copy the entry
629	int entryLen = &entry->d_name[strlen(entry->d_name) + 1] - (char*)entry;
630	if (entryLen > (int)bufferSize)
631		return B_BUFFER_OVERFLOW;
632
633	memcpy(buffer, entry, entryLen);
634
635	return 1;
636}
637
638// _kern_rewind_dir
639status_t
640_kern_rewind_dir(int fd)
641{
642	// get the descriptor
643	DirectoryDescriptor *descriptor
644		= dynamic_cast<DirectoryDescriptor*>(get_descriptor(fd));
645	if (!descriptor)
646		return B_FILE_ERROR;
647
648	// rewind
649	if (dynamic_cast<AttrDirDescriptor*>(descriptor))
650		fs_rewind_attr_dir(descriptor->dir);
651	else
652		rewinddir(descriptor->dir);
653
654	return B_OK;
655}
656
657
658// #pragma mark -
659
660// open_file
661static int
662open_file(const char *path, int openMode, int perms)
663{
664	// stat the node
665	bool exists = true;
666	struct stat st;
667	if (lstat(path, &st) < 0) {
668		exists = false;
669		if (!(openMode & O_CREAT))
670			return errno;
671	}
672
673	Descriptor *descriptor;
674	if (exists && S_ISLNK(st.st_mode) && (openMode & O_NOTRAVERSE) != 0) {
675		// a symlink not to be followed: create a special descriptor
676		// normalize path first
677		string normalizedPath;
678		status_t error = normalize_entry_path(path, normalizedPath);
679		if (error != B_OK)
680			return error;
681
682		descriptor = new SymlinkDescriptor(normalizedPath.c_str());
683	} else {
684		// open the file
685		openMode &= ~O_NOTRAVERSE;
686		int newFD = open(path, openMode, perms);
687		if (newFD < 0)
688			return errno;
689
690		descriptor = new FileDescriptor(newFD);
691	}
692
693	// cache path, if this is a directory
694	if (exists && S_ISDIR(st.st_mode))
695		add_dir_path(path, NodeRef(st));
696
697	return add_descriptor(descriptor);
698}
699
700// _kern_open
701int
702_kern_open(int fd, const char *path, int openMode, int perms)
703{
704	// get a usable path
705	string realPath;
706	status_t error = get_path(fd, path, realPath);
707	if (error != B_OK)
708		return error;
709
710	return open_file(realPath.c_str(), openMode, perms);
711}
712
713// _kern_open_entry_ref
714int
715_kern_open_entry_ref(dev_t device, ino_t node, const char *name,
716	int openMode, int perms)
717{
718	// get a usable path
719	string realPath;
720	status_t error = get_path(device, node, name, realPath);
721	if (error != B_OK)
722		return error;
723
724	return open_file(realPath.c_str(), openMode, perms);
725}
726
727// _kern_seek
728off_t
729_kern_seek(int fd, off_t pos, int seekType)
730{
731	// get the descriptor
732	FileDescriptor *descriptor
733		= dynamic_cast<FileDescriptor*>(get_descriptor(fd));
734	if (!descriptor)
735		return B_FILE_ERROR;
736
737	// seek
738	off_t result = lseek(descriptor->fd, pos, seekType);
739	if (result < 0)
740		return errno;
741
742	return result;
743}
744
745// _kern_read
746ssize_t
747_kern_read(int fd, off_t pos, void *buffer, size_t bufferSize)
748{
749	// get the descriptor
750	FileDescriptor *descriptor
751		= dynamic_cast<FileDescriptor*>(get_descriptor(fd));
752	if (!descriptor)
753		return B_FILE_ERROR;
754
755	// seek
756	if (pos != -1) {
757		off_t result = lseek(descriptor->fd, pos, SEEK_SET);
758		if (result < 0)
759			return errno;
760	}
761
762	// read
763	ssize_t bytesRead = haiku_host_platform_read(descriptor->fd, buffer,
764		bufferSize);
765	if (bytesRead < 0)
766		return errno;
767
768	return bytesRead;
769}
770
771// _kern_write
772ssize_t
773_kern_write(int fd, off_t pos, const void *buffer, size_t bufferSize)
774{
775	// get the descriptor
776	FileDescriptor *descriptor
777		= dynamic_cast<FileDescriptor*>(get_descriptor(fd));
778	if (!descriptor)
779		return B_FILE_ERROR;
780
781	// seek
782	if (pos != -1) {
783		off_t result = lseek(descriptor->fd, pos, SEEK_SET);
784		if (result < 0)
785			return errno;
786	}
787
788	// read
789	ssize_t bytesWritten = haiku_host_platform_write(descriptor->fd, buffer,
790		bufferSize);
791	if (bytesWritten < 0)
792		return errno;
793
794	return bytesWritten;
795}
796
797// _kern_close
798status_t
799_kern_close(int fd)
800{
801	return delete_descriptor(fd);
802}
803
804// _kern_dup
805int
806_kern_dup(int fd)
807{
808	// get the descriptor
809	Descriptor *descriptor = get_descriptor(fd);
810	if (!descriptor)
811		return B_FILE_ERROR;
812
813	// clone it
814	Descriptor *clone = NULL;
815	status_t error = descriptor->Dup(clone);
816	if (error != B_OK)
817		return error;
818	if (clone == NULL)
819		debugger("Dup() succeeded but descriptor is NULL");
820
821	return add_descriptor(clone);
822}
823
824// _kern_fsync
825status_t
826_kern_fsync(int fd)
827{
828	// get the descriptor
829	FileDescriptor *descriptor
830		= dynamic_cast<FileDescriptor*>(get_descriptor(fd));
831	if (!descriptor)
832		return B_FILE_ERROR;
833
834	// sync
835	if (fsync(descriptor->fd) < 0)
836		return errno;
837
838	return B_OK;
839}
840
841// _kern_read_stat
842status_t
843_kern_read_stat(int fd, const char *path, bool traverseLink,
844	struct stat *st, size_t statSize)
845{
846	if (path) {
847		// get a usable path
848		string realPath;
849		status_t error = get_path(fd, path, realPath);
850		if (error != B_OK)
851			return error;
852
853		// stat
854		int result;
855		if (traverseLink)
856			result = stat(realPath.c_str(), st);
857		else
858			result = lstat(realPath.c_str(), st);
859
860		if (result < 0)
861			return errno;
862	} else {
863		Descriptor *descriptor = get_descriptor(fd);
864		if (!descriptor)
865			return B_FILE_ERROR;
866
867		return descriptor->GetStat(traverseLink, st);
868	}
869
870	return B_OK;
871}
872
873// _kern_write_stat
874status_t
875_kern_write_stat(int fd, const char *path, bool traverseLink,
876	const struct stat *st, size_t statSize, int statMask)
877{
878	// get a usable path
879	int realFD = -1;
880	string realPath;
881	status_t error;
882	bool isSymlink = false;
883	if (path) {
884		error = get_path(fd, path, realPath);
885		if (error != B_OK)
886			return error;
887
888		// stat it to see, if it is a symlink
889		struct stat tmpStat;
890		if (lstat(realPath.c_str(), &tmpStat) < 0)
891			return errno;
892
893		isSymlink = S_ISLNK(tmpStat.st_mode);
894	} else {
895		Descriptor *descriptor = get_descriptor(fd);
896		if (!descriptor)
897			return B_FILE_ERROR;
898
899		if (FileDescriptor *fileFD
900				= dynamic_cast<FileDescriptor*>(descriptor)) {
901			realFD = fileFD->fd;
902		} else if (dynamic_cast<DirectoryDescriptor*>(descriptor)) {
903			error = get_path(fd, NULL, realPath);
904			if (error != B_OK)
905				return error;
906		} else if (SymlinkDescriptor *linkFD
907				= dynamic_cast<SymlinkDescriptor*>(descriptor)) {
908			realPath = linkFD->path;
909			isSymlink = true;
910		} else
911			return B_FILE_ERROR;
912	}
913
914	// We're screwed, if the node to manipulate is a symlink. All the
915	// available functions traverse symlinks.
916	if (isSymlink && !traverseLink)
917		return B_ERROR;
918
919	if (realFD >= 0) {
920		if (statMask & B_STAT_MODE) {
921			if (fchmod(realFD, st->st_mode) < 0)
922				return errno;
923		}
924
925		if (statMask & B_STAT_UID) {
926			if (fchown(realFD, st->st_uid, (gid_t)-1) < 0)
927				return errno;
928		}
929
930		if (statMask & B_STAT_GID) {
931			if (fchown(realFD, (uid_t)-1, st->st_gid) < 0)
932				return errno;
933		}
934
935		if (statMask & B_STAT_SIZE) {
936			if (ftruncate(realFD, st->st_size) < 0)
937				return errno;
938		}
939
940		if (statMask & (B_STAT_ACCESS_TIME | B_STAT_MODIFICATION_TIME)) {
941			// Grab the previous mod and access times so we only overwrite
942			// the specified time and not both
943			struct stat oldStat;
944			if (~statMask & (B_STAT_ACCESS_TIME | B_STAT_MODIFICATION_TIME)) {
945				if (fstat(realFD, &oldStat) < 0)
946					return errno;
947			}
948
949			struct timespec times[2];
950			times[0] = (statMask & B_STAT_ACCESS_TIME)
951				? HAIKU_HOST_STAT_ATIM(*st) : HAIKU_HOST_STAT_ATIM(oldStat);
952			times[1] = (statMask & B_STAT_MODIFICATION_TIME)
953				? HAIKU_HOST_STAT_MTIM(*st) : HAIKU_HOST_STAT_MTIM(oldStat);
954			if (futimens(realFD, times) < 0)
955				return errno;
956		}
957
958		// not supported
959		if (statMask & (B_STAT_CREATION_TIME | B_STAT_CHANGE_TIME))
960			return B_ERROR;
961
962		return 0;
963	} else {
964		if (statMask & B_STAT_MODE) {
965			if (chmod(realPath.c_str(), st->st_mode) < 0)
966				return errno;
967		}
968
969		if (statMask & B_STAT_UID) {
970			if (chown(realPath.c_str(), st->st_uid, (gid_t)-1) < 0)
971				return errno;
972		}
973
974		if (statMask & B_STAT_GID) {
975			if (chown(realPath.c_str(), (uid_t)-1, st->st_gid) < 0)
976				return errno;
977		}
978
979		if (statMask & B_STAT_SIZE) {
980			if (truncate(realPath.c_str(), st->st_size) < 0)
981				return errno;
982		}
983
984		if (statMask & (B_STAT_ACCESS_TIME | B_STAT_MODIFICATION_TIME)) {
985			// Grab the previous mod and access times so we only overwrite
986			// the specified time and not both
987			struct stat oldStat;
988			if (~statMask & (B_STAT_ACCESS_TIME | B_STAT_MODIFICATION_TIME)) {
989				if (stat(realPath.c_str(), &oldStat) < 0)
990					return errno;
991			}
992
993			utimbuf buffer;
994			buffer.actime = (statMask & B_STAT_ACCESS_TIME) ? st->st_atime : oldStat.st_atime;
995			buffer.modtime = (statMask & B_STAT_MODIFICATION_TIME) ? st->st_mtime : oldStat.st_mtime;
996			if (utime(realPath.c_str(), &buffer) < 0)
997				return errno;
998		}
999
1000		// not supported
1001		if (statMask & (B_STAT_CREATION_TIME | B_STAT_CHANGE_TIME))
1002			return B_ERROR;
1003	}
1004
1005	return B_OK;
1006}
1007
1008
1009// #pragma mark -
1010
1011// _kern_create_symlink
1012status_t
1013_kern_create_symlink(int fd, const char *path, const char *toPath, int mode)
1014{
1015	// Note: path must not be NULL, so this will always work.
1016	// get a usable path
1017	string realPath;
1018	status_t error = get_path(fd, path, realPath);
1019	if (error != B_OK)
1020		return error;
1021
1022	// symlink
1023	if (symlink(toPath, realPath.c_str()) < 0)
1024		return errno;
1025
1026	return B_OK;
1027}
1028
1029// _kern_read_link
1030status_t
1031_kern_read_link(int fd, const char *path, char *buffer, size_t *_bufferSize)
1032{
1033	// get the path
1034	string realPath;
1035	status_t error = get_path(fd, path, realPath);
1036	if (error != B_OK)
1037		return error;
1038
1039	ssize_t bytesRead = readlink(realPath.c_str(), buffer, *_bufferSize);
1040	if (bytesRead < 0)
1041		return errno;
1042
1043	// On Haiku _kern_read_link will return the length of the link, *not*
1044	// the number of bytes written to the buffer parameter. To emulate that
1045	// here, we use readlink() to read the links contents, and then if it is
1046	// possible that the link contents didn't fit in buffer, we'll fall back
1047	// to lstat() to get the full length of the link.
1048	if (static_cast<size_t>(bytesRead) < *_bufferSize) {
1049		buffer[bytesRead] = '\0';
1050		*_bufferSize = bytesRead;
1051	} else {
1052		// The number of bytes copied by readlink() tells us that the entire
1053		// link might not have fit into buffer. Fall back to getting the full
1054		// length of the link using lstat.
1055		struct stat linkStat;
1056		if (lstat(realPath.c_str(), &linkStat) != 0)
1057			return errno;
1058
1059		*_bufferSize = linkStat.st_size;
1060	}
1061
1062	return B_OK;
1063}
1064
1065// _kern_unlink
1066status_t
1067_kern_unlink(int fd, const char *path)
1068{
1069	// get a usable path
1070	string realPath;
1071	status_t error = get_path(fd, path, realPath);
1072	if (error != B_OK)
1073		return error;
1074
1075	// unlink
1076	if (unlink(realPath.c_str()) < 0)
1077		return errno;
1078
1079	return B_OK;
1080}
1081
1082// _kern_rename
1083status_t
1084_kern_rename(int oldDir, const char *oldPath, int newDir, const char *newPath)
1085{
1086	// get usable paths
1087	string realOldPath;
1088	status_t error = get_path(oldDir, oldPath, realOldPath);
1089	if (error != B_OK)
1090		return error;
1091
1092	string realNewPath;
1093	error = get_path(newDir, newPath, realNewPath);
1094	if (error != B_OK)
1095		return error;
1096
1097	// rename
1098	if (rename(realOldPath.c_str(), realNewPath.c_str()) < 0)
1099		return errno;
1100
1101	return B_OK;
1102}
1103
1104
1105// #pragma mark -
1106
1107// _kern_lock_node
1108status_t
1109_kern_lock_node(int fd)
1110{
1111	return B_ERROR;
1112}
1113
1114// _kern_unlock_node
1115status_t
1116_kern_unlock_node(int fd)
1117{
1118	return B_ERROR;
1119}
1120
1121
1122// #pragma mark -
1123
1124
1125#if !defined(HAIKU_HOST_PLATFORM_HAIKU)
1126ssize_t
1127read_pos(int fd, off_t pos, void *buffer, size_t bufferSize)
1128{
1129	// seek
1130	off_t result = lseek(fd, pos, SEEK_SET);
1131	if (result < 0)
1132		return errno;
1133
1134	// read
1135	ssize_t bytesRead = haiku_host_platform_read(fd, buffer, bufferSize);
1136	if (bytesRead < 0) {
1137		errno = bytesRead;
1138		return -1;
1139	}
1140
1141	return bytesRead;
1142}
1143
1144ssize_t
1145write_pos(int fd, off_t pos, const void *buffer, size_t bufferSize)
1146{
1147	// If this is an attribute descriptor, let it do the job.
1148	AttributeDescriptor* descriptor
1149		= dynamic_cast<AttributeDescriptor*>(get_descriptor(fd));
1150	if (descriptor != NULL) {
1151		status_t error = descriptor->Write(pos, buffer, bufferSize);
1152		if (error != B_OK) {
1153			errno = error;
1154			return -1;
1155		}
1156
1157		return bufferSize;
1158	}
1159
1160	// seek
1161	off_t result = lseek(fd, pos, SEEK_SET);
1162	if (result < 0)
1163		return errno;
1164
1165	// write
1166	ssize_t bytesWritten = haiku_host_platform_write(fd, buffer, bufferSize);
1167	if (bytesWritten < 0) {
1168		errno = bytesWritten;
1169		return -1;
1170	}
1171
1172	return bytesWritten;
1173}
1174#endif
1175
1176
1177ssize_t
1178_kern_readv(int fd, off_t pos, const struct iovec *vec, size_t count)
1179{
1180	// seek
1181	off_t result = lseek(fd, pos, SEEK_SET);
1182	if (result < 0)
1183		return errno;
1184
1185	// read
1186	return haiku_host_platform_readv(fd, vec, count);
1187}
1188
1189
1190ssize_t
1191_kern_writev(int fd, off_t pos, const struct iovec *vec, size_t count)
1192{
1193	// seek
1194	off_t result = lseek(fd, pos, SEEK_SET);
1195	if (result < 0)
1196		return errno;
1197
1198	// write
1199	return haiku_host_platform_writev(fd, vec, count);
1200}
1201
1202
1203// #pragma mark -
1204
1205
1206int
1207_haiku_build_fchmod(int fd, mode_t mode)
1208{
1209	return _haiku_build_fchmodat(fd, NULL, mode, AT_SYMLINK_NOFOLLOW);
1210}
1211
1212
1213int
1214_haiku_build_fchmodat(int fd, const char* path, mode_t mode, int flag)
1215{
1216	if (fd >= 0 && fd != AT_FDCWD && get_descriptor(fd) == NULL)
1217		return fchmodat(fd, path, mode, flag);
1218
1219	struct stat st;
1220	st.st_mode = mode;
1221
1222	RETURN_AND_SET_ERRNO(_kern_write_stat(fd, path,
1223		(flag & AT_SYMLINK_NOFOLLOW) == 0, &st, sizeof(st), B_STAT_MODE));
1224}
1225
1226
1227int
1228_haiku_build_fstat(int fd, struct stat* st)
1229{
1230	return _haiku_build_fstatat(fd, NULL, st, AT_SYMLINK_NOFOLLOW);
1231}
1232
1233
1234int
1235_haiku_build_fstatat(int fd, const char* path, struct stat* st, int flag)
1236{
1237	if (fd >= 0 && fd != AT_FDCWD && get_descriptor(fd) == NULL)
1238		return fstatat(fd, path, st, flag);
1239
1240	RETURN_AND_SET_ERRNO(_kern_read_stat(fd, path,
1241		(flag & AT_SYMLINK_NOFOLLOW) == 0, st, sizeof(*st)));
1242}
1243
1244
1245int
1246_haiku_build_mkdirat(int fd, const char* path, mode_t mode)
1247{
1248	if (fd >= 0 && fd != AT_FDCWD && get_descriptor(fd) == NULL)
1249		return mkdirat(fd, path, mode);
1250
1251	RETURN_AND_SET_ERRNO(_kern_create_dir(fd, path, mode));
1252}
1253
1254
1255int
1256_haiku_build_mkfifoat(int fd, const char* path, mode_t mode)
1257{
1258	return mkfifoat(fd, path, mode);
1259
1260	// TODO: Handle non-system FDs.
1261}
1262
1263
1264int
1265_haiku_build_utimensat(int fd, const char* path, const struct timespec times[2],
1266	int flag)
1267{
1268	if (fd >= 0 && fd != AT_FDCWD && get_descriptor(fd) == NULL)
1269		return utimensat(fd, path, times, flag);
1270
1271	struct stat stat;
1272	status_t status;
1273	uint32 mask = 0;
1274
1275	// Init the stat time fields to the current time, if at least one time is
1276	// supposed to be set to it.
1277	if (times == NULL || times[0].tv_nsec == UTIME_NOW
1278		|| times[1].tv_nsec == UTIME_NOW) {
1279		timeval now;
1280		gettimeofday(&now, NULL);
1281		HAIKU_HOST_STAT_ATIM(stat).tv_sec
1282			= HAIKU_HOST_STAT_MTIM(stat).tv_sec = now.tv_sec;
1283		HAIKU_HOST_STAT_ATIM(stat).tv_nsec
1284			= HAIKU_HOST_STAT_MTIM(stat).tv_nsec = now.tv_usec * 1000;
1285	}
1286
1287	if (times != NULL) {
1288		// access time
1289		if (times[0].tv_nsec != UTIME_OMIT) {
1290			mask |= B_STAT_ACCESS_TIME;
1291
1292			if (times[0].tv_nsec != UTIME_NOW) {
1293				if (times[0].tv_nsec < 0 || times[0].tv_nsec > 999999999)
1294					RETURN_AND_SET_ERRNO(EINVAL);
1295			}
1296
1297			HAIKU_HOST_STAT_ATIM(stat) = times[0];
1298		}
1299
1300		// modified time
1301		if (times[1].tv_nsec != UTIME_OMIT) {
1302			mask |= B_STAT_MODIFICATION_TIME;
1303
1304			if (times[1].tv_nsec != UTIME_NOW) {
1305				if (times[1].tv_nsec < 0 || times[1].tv_nsec > 999999999)
1306					RETURN_AND_SET_ERRNO(EINVAL);
1307			}
1308
1309			HAIKU_HOST_STAT_MTIM(stat) = times[1];
1310		}
1311	} else
1312		mask |= B_STAT_ACCESS_TIME | B_STAT_MODIFICATION_TIME;
1313
1314	// set the times -- as per spec we even need to do this, if both have
1315	// UTIME_OMIT set
1316	status = _kern_write_stat(fd, path, (flag & AT_SYMLINK_NOFOLLOW) == 0,
1317		&stat, sizeof(struct stat), mask);
1318
1319	RETURN_AND_SET_ERRNO(status);
1320}
1321
1322
1323int
1324_haiku_build_futimens(int fd, const struct timespec times[2])
1325{
1326	return _haiku_build_utimensat(fd, NULL, times, AT_SYMLINK_NOFOLLOW);
1327}
1328
1329
1330int
1331_haiku_build_faccessat(int fd, const char* path, int accessMode, int flag)
1332{
1333	if (fd >= 0 && fd != AT_FDCWD && get_descriptor(fd) == NULL)
1334		return faccessat(fd, path, accessMode, flag);
1335
1336	// stat the file
1337	struct stat st;
1338	status_t error = _kern_read_stat(fd, path, false, &st, sizeof(st));
1339	if (error != B_OK)
1340		RETURN_AND_SET_ERRNO(error);
1341
1342	// get the current user
1343	uid_t uid = (flag & AT_EACCESS) != 0 ? geteuid() : getuid();
1344
1345	int fileMode = 0;
1346
1347	if (uid == 0) {
1348		// user is root
1349		// root has always read/write permission, but at least one of the
1350		// X bits must be set for execute permission
1351		fileMode = R_OK | W_OK;
1352		if ((st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) != 0)
1353			fileMode |= X_OK;
1354	} else if (st.st_uid == uid) {
1355		// user is node owner
1356		if ((st.st_mode & S_IRUSR) != 0)
1357			fileMode |= R_OK;
1358		if ((st.st_mode & S_IWUSR) != 0)
1359			fileMode |= W_OK;
1360		if ((st.st_mode & S_IXUSR) != 0)
1361			fileMode |= X_OK;
1362	} else if (st.st_gid == ((flag & AT_EACCESS) != 0 ? getegid() : getgid())) {
1363		// user is in owning group
1364		if ((st.st_mode & S_IRGRP) != 0)
1365			fileMode |= R_OK;
1366		if ((st.st_mode & S_IWGRP) != 0)
1367			fileMode |= W_OK;
1368		if ((st.st_mode & S_IXGRP) != 0)
1369			fileMode |= X_OK;
1370	} else {
1371		// user is one of the others
1372		if ((st.st_mode & S_IROTH) != 0)
1373			fileMode |= R_OK;
1374		if ((st.st_mode & S_IWOTH) != 0)
1375			fileMode |= W_OK;
1376		if ((st.st_mode & S_IXOTH) != 0)
1377			fileMode |= X_OK;
1378	}
1379
1380	if ((accessMode & ~fileMode) != 0)
1381		RETURN_AND_SET_ERRNO(EACCES);
1382
1383	return 0;
1384}
1385
1386
1387int
1388_haiku_build_fchdir(int fd)
1389{
1390	if (is_unknown_or_system_descriptor(fd))
1391		return fchdir(fd);
1392
1393	RETURN_AND_SET_ERRNO(B_FILE_ERROR);
1394}
1395
1396
1397int
1398_haiku_build_close(int fd)
1399{
1400	if (get_descriptor(fd) == NULL)
1401		return close(fd);
1402
1403	RETURN_AND_SET_ERRNO(_kern_close(fd));
1404}
1405
1406
1407int
1408_haiku_build_dup(int fd)
1409{
1410	if (get_descriptor(fd) == NULL)
1411		return close(fd);
1412
1413	RETURN_AND_SET_ERRNO(_kern_dup(fd));
1414}
1415
1416
1417int
1418_haiku_build_dup2(int fd1, int fd2)
1419{
1420	if (is_unknown_or_system_descriptor(fd1))
1421		return dup2(fd1, fd2);
1422
1423	// TODO: Handle non-system FDs.
1424	RETURN_AND_SET_ERRNO(B_NOT_SUPPORTED);
1425}
1426
1427
1428int
1429_haiku_build_linkat(int toFD, const char* toPath, int pathFD, const char* path,
1430	int flag)
1431{
1432	return linkat(toFD, toPath, pathFD, path, flag);
1433
1434	// TODO: Handle non-system FDs.
1435}
1436
1437
1438int
1439_haiku_build_unlinkat(int fd, const char* path, int flag)
1440{
1441	if (fd >= 0 && fd != AT_FDCWD && get_descriptor(fd) == NULL)
1442		return unlinkat(fd, path, flag);
1443
1444	RETURN_AND_SET_ERRNO(_kern_unlink(fd, path));
1445}
1446
1447
1448ssize_t
1449_haiku_build_readlinkat(int fd, const char* path, char* buffer,
1450	size_t bufferSize)
1451{
1452	if (fd >= 0 && fd != AT_FDCWD && get_descriptor(fd) == NULL)
1453		return readlinkat(fd, path, buffer, bufferSize);
1454
1455	status_t error = _kern_read_link(fd, path, buffer, &bufferSize);
1456	if (error != B_OK)
1457		RETURN_AND_SET_ERRNO(error);
1458
1459	return bufferSize;
1460}
1461
1462
1463int
1464_haiku_build_symlinkat(const char* toPath, int fd, const char* symlinkPath)
1465{
1466	if (fd >= 0 && fd != AT_FDCWD && get_descriptor(fd) == NULL)
1467		return symlinkat(toPath, fd, symlinkPath);
1468
1469	RETURN_AND_SET_ERRNO(_kern_create_symlink(fd, symlinkPath, toPath,
1470		S_IRWXU | S_IRWXG | S_IRWXO));
1471}
1472
1473
1474int
1475_haiku_build_ftruncate(int fd, off_t newSize)
1476{
1477	if (fd >= 0 && fd != AT_FDCWD && get_descriptor(fd) == NULL)
1478		return ftruncate(fd, newSize);
1479
1480	struct stat st;
1481	st.st_size = newSize;
1482
1483	RETURN_AND_SET_ERRNO(_kern_write_stat(fd, NULL, false, &st, sizeof(st),
1484		B_STAT_SIZE));
1485}
1486
1487
1488int
1489_haiku_build_fchown(int fd, uid_t owner, gid_t group)
1490{
1491	return _haiku_build_fchownat(fd, NULL, owner, group, AT_SYMLINK_NOFOLLOW);
1492}
1493
1494
1495int
1496_haiku_build_fchownat(int fd, const char* path, uid_t owner, gid_t group,
1497	int flag)
1498{
1499	if (fd >= 0 && fd != AT_FDCWD && get_descriptor(fd) == NULL)
1500		return fchownat(fd, path, owner, group, flag);
1501
1502	struct stat st;
1503	st.st_uid = owner;
1504	st.st_gid = group;
1505
1506	RETURN_AND_SET_ERRNO(_kern_write_stat(fd, path,
1507		(flag & AT_SYMLINK_NOFOLLOW) == 0, &st, sizeof(st),
1508		B_STAT_UID | B_STAT_GID));
1509}
1510
1511
1512int
1513_haiku_build_mknodat(int fd, const char* name, mode_t mode, dev_t dev)
1514{
1515	return mknodat(fd, name, mode, dev);
1516
1517	// TODO: Handle non-system FDs.
1518}
1519
1520
1521int
1522_haiku_build_creat(const char* path, mode_t mode)
1523{
1524	return _haiku_build_open(path, O_WRONLY | O_CREAT | O_TRUNC, mode);
1525}
1526
1527
1528int
1529_haiku_build_open(const char* path, int openMode, mode_t permissions)
1530{
1531	return _haiku_build_openat(AT_FDCWD, path, openMode, permissions);
1532}
1533
1534
1535int
1536_haiku_build_openat(int fd, const char* path, int openMode, mode_t permissions)
1537{
1538	// adapt the permissions as required by POSIX
1539	mode_t mask = umask(0);
1540	umask(mask);
1541	permissions &= ~mask;
1542
1543	RETURN_AND_SET_ERRNO(_kern_open(fd, path, openMode, permissions));
1544}
1545
1546
1547int
1548_haiku_build_fcntl(int fd, int op, int argument)
1549{
1550	if (is_unknown_or_system_descriptor(fd))
1551		return fcntl(fd, op, argument);
1552
1553	RETURN_AND_SET_ERRNO(B_NOT_SUPPORTED);
1554}
1555
1556
1557int
1558_haiku_build_renameat(int fromFD, const char* from, int toFD, const char* to)
1559{
1560	if ((fromFD >= 0 && fromFD != AT_FDCWD && get_descriptor(fromFD) == NULL)
1561		|| (toFD >= 0 && toFD != AT_FDCWD && get_descriptor(toFD) == NULL)) {
1562		return renameat(fromFD, from, toFD, to);
1563	}
1564
1565	RETURN_AND_SET_ERRNO(_kern_rename(fromFD, from, toFD, to));
1566}
1567