xref: /haiku/src/build/libroot/fs.cpp (revision e688bf23d48bfd1216a0cacbdbda5e35a1bcd779)
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 
37 using namespace std;
38 using 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 
77 template<typename File>
78 static int
79 utimes_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 
128 struct 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 
145 private:
146 	int fFD;
147 };
148 
149 
150 int
151 futimens(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 
161 struct 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 
181 private:
182 	int			fFD;
183 	const char*	fPath;
184 	int			fFlag;
185 };
186 
187 
188 int
189 utimensat(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 
198 static status_t get_path(dev_t device, ino_t node, const char *name,
199 	string &path);
200 
201 
202 // find_dir_entry
203 static status_t
204 find_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
239 static status_t
240 find_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
256 static status_t
257 normalize_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
294 static status_t
295 normalize_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
306 static status_t
307 normalize_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 
350 typedef map<NodeRef, string> DirPathMap;
351 static DirPathMap sDirPathMap;
352 
353 // get_path
354 static status_t
355 get_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
404 status_t
405 BPrivate::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
427 static status_t
428 get_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
438 static void
439 add_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
451 status_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
472 status_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
489 status_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
507 static int
508 open_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
537 int
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
550 int
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
563 int
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
597 ssize_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
630 status_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
652 static int
653 open_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
692 int
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
705 int
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
719 off_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
737 ssize_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
763 ssize_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
789 status_t
790 _kern_close(int fd)
791 {
792 	return delete_descriptor(fd);
793 }
794 
795 // _kern_dup
796 int
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
814 status_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
831 status_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
863 status_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
991 status_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
1009 status_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
1036 status_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
1053 status_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
1078 status_t
1079 _kern_lock_node(int fd)
1080 {
1081 	return B_ERROR;
1082 }
1083 
1084 // _kern_unlock_node
1085 status_t
1086 _kern_unlock_node(int fd)
1087 {
1088 	return B_ERROR;
1089 }
1090 
1091 
1092 // #pragma mark -
1093 
1094 // read_pos
1095 ssize_t
1096 read_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
1114 ssize_t
1115 write_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
1146 ssize_t
1147 readv_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
1165 ssize_t
1166 writev_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 
1187 int
1188 _haiku_build_fchmod(int fd, mode_t mode)
1189 {
1190 	return _haiku_build_fchmodat(fd, NULL, mode, AT_SYMLINK_NOFOLLOW);
1191 }
1192 
1193 
1194 int
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 
1208 int
1209 _haiku_build_fstat(int fd, struct stat* st)
1210 {
1211 	return _haiku_build_fstatat(fd, NULL, st, AT_SYMLINK_NOFOLLOW);
1212 }
1213 
1214 
1215 int
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 
1226 int
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 
1236 int
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 
1245 int
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 
1304 int
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 
1311 int
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 
1368 int
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 
1378 int
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 
1388 int
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 
1398 int
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 
1409 int
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 
1419 int
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 
1429 ssize_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 
1444 int
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 
1455 int
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 
1469 int
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 
1476 int
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 
1493 int
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 
1502 int
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 
1509 int
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 
1516 int
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 
1528 int
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 
1538 int
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