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