fat: Greatly simplify and clean up dosfs_get_file_map().
[haiku.git] / src / build / libroot / fs.cpp
blobc5f59a566e502f7ad374e362fd3e5afdf2e81919
1 /*
2 * Copyright 2005-2011, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
4 */
7 #include <BeOSBuildCompatibility.h>
9 #include "fs_impl.h"
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>
21 #include <map>
22 #include <string>
24 #include <fs_attr.h>
25 #include <NodeMonitor.h> // for B_STAT_* flags
26 #include <syscalls.h>
28 #include "fs_descriptors.h"
29 #include "NodeRef.h"
30 #include "remapped_functions.h"
32 #if defined(HAIKU_HOST_PLATFORM_FREEBSD)
33 # include "fs_freebsd.h"
34 #endif
37 using namespace std;
38 using namespace BPrivate;
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
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)
75 #if defined(_HAIKU_BUILD_NO_FUTIMENS) || defined(_HAIKU_BUILD_NO_FUTIMENS)
77 template<typename File>
78 static int
79 utimes_helper(File& file, const struct timespec times[2])
81 if (times == NULL)
82 return file.SetTimes(NULL);
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;
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;
95 if (times[0].tv_nsec == UTIME_OMIT && times[1].tv_nsec == UTIME_OMIT)
96 return 0;
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;
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;
109 if (times[0].tv_nsec == UTIME_NOW || times[1].tv_nsec == UTIME_NOW) {
110 timeval now;
111 gettimeofday(&now, NULL);
113 if (times[0].tv_nsec == UTIME_NOW)
114 timeBuffer[0] = now;
116 if (times[1].tv_nsec == UTIME_NOW)
117 timeBuffer[1] = now;
120 return file.SetTimes(timeBuffer);
123 #endif // _HAIKU_BUILD_NO_FUTIMENS || _HAIKU_BUILD_NO_FUTIMENS
126 #ifdef _HAIKU_BUILD_NO_FUTIMENS
128 struct FDFile {
129 FDFile(int fd)
131 fFD(fd)
135 int GetStat(struct stat& _st)
137 return fstat(fFD, &_st);
140 int SetTimes(const timeval times[2])
142 return futimes(fFD, times);
145 private:
146 int fFD;
151 futimens(int fd, const struct timespec times[2])
153 FDFile file(fd);
154 return utimes_helper(file, times);
157 #endif // _HAIKU_BUILD_NO_FUTIMENS
159 #ifdef _HAIKU_BUILD_NO_UTIMENSAT
161 struct FDPathFile {
162 FDPathFile(int fd, const char* path, int flag)
164 fFD(fd),
165 fPath(path),
166 fFlag(flag)
170 int GetStat(struct stat& _st)
172 return fstatat(fFD, fPath, &_st, fFlag);
175 int SetTimes(const timeval times[2])
177 // TODO: fFlag (AT_SYMLINK_NOFOLLOW) is not supported here!
178 return futimesat(fFD, fPath, times);
181 private:
182 int fFD;
183 const char* fPath;
184 int fFlag;
189 utimensat(int fd, const char* path, const struct timespec times[2], int flag)
191 FDPathFile file(fd, path, flag);
192 return utimes_helper(file, times);
195 #endif // _HAIKU_BUILD_NO_UTIMENSAT
198 static status_t get_path(dev_t device, ino_t node, const char *name,
199 string &path);
202 // find_dir_entry
203 static status_t
204 find_dir_entry(DIR *dir, const char *path, NodeRef ref, string &name,
205 bool skipDot)
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;
232 if (!found)
233 return B_ENTRY_NOT_FOUND;
235 return B_OK;
238 // find_dir_entry
239 static status_t
240 find_dir_entry(const char *path, NodeRef ref, string &name, bool skipDot)
242 // open dir
243 DIR *dir = opendir(path);
244 if (!dir)
245 return errno;
247 status_t error = find_dir_entry(dir, path, ref, name, skipDot);
249 // close dir
250 closedir(dir);
252 return error;
256 static bool
257 guess_normalized_dir_path(string path, NodeRef ref, string& _normalizedPath)
259 // We assume the CWD is normalized and hope that the directory is an
260 // ancestor of it. We just chop off path components until we find a match or
261 // hit root.
262 char cwd[B_PATH_NAME_LENGTH];
263 if (getcwd(cwd, sizeof(cwd)) == NULL)
264 return false;
266 while (cwd[0] == '/') {
267 struct stat st;
268 if (stat(cwd, &st) == 0) {
269 if (st.st_dev == ref.device && st.st_ino == ref.node) {
270 _normalizedPath = cwd;
271 return true;
275 *strrchr(cwd, '/') = '\0';
278 // TODO: If path is absolute, we could also try to work with that, though
279 // the other way around -- trying prefixes until we hit a "." or ".."
280 // component.
282 return false;
286 // normalize_dir_path
287 static status_t
288 normalize_dir_path(string path, NodeRef ref, string &normalizedPath)
290 // get parent path
291 path += "/..";
293 // stat the parent dir
294 struct stat st;
295 if (lstat(path.c_str(), &st) < 0)
296 return errno;
298 // root dir?
299 NodeRef parentRef(st);
300 if (parentRef == ref) {
301 normalizedPath = "/";
302 return 0;
305 // find the entry
306 string name;
307 status_t error = find_dir_entry(path.c_str(), ref, name, true) ;
308 if (error != B_OK) {
309 if (error != B_ENTRY_NOT_FOUND) {
310 // We couldn't open the directory. This might be because we don't
311 // have read permission. We're OK with not fully normalizing the
312 // path and try to guess the path in this case. Note: We don't check
313 // error for B_PERMISSION_DENIED, since opendir() may clobber the
314 // actual kernel error code with something not helpful.
315 if (guess_normalized_dir_path(path, ref, normalizedPath))
316 return B_OK;
319 return error;
322 // recurse to get the parent dir path, if found
323 error = normalize_dir_path(path, parentRef, normalizedPath);
324 if (error != 0)
325 return error;
327 // construct the normalizedPath
328 if (normalizedPath.length() > 1) // don't append "/", if parent is root
329 normalizedPath += '/';
330 normalizedPath += name;
332 return 0;
335 // normalize_dir_path
336 static status_t
337 normalize_dir_path(const char *path, string &normalizedPath)
339 // stat() the dir
340 struct stat st;
341 if (stat(path, &st) < 0)
342 return errno;
344 return normalize_dir_path(path, NodeRef(st), normalizedPath);
347 // normalize_entry_path
348 static status_t
349 normalize_entry_path(const char *path, string &normalizedPath)
351 const char *dirPath = NULL;
352 const char *leafName = NULL;
354 string dirPathString;
355 if (const char *lastSlash = strrchr(path, '/')) {
356 // found a slash: decompose into dir path and leaf name
357 leafName = lastSlash + 1;
358 if (leafName[0] == '\0') {
359 // slash is at the end: the whole path is a dir name
360 leafName = NULL;
361 } else {
362 dirPathString = string(path, leafName - path);
363 dirPath = dirPathString.c_str();
366 } else {
367 // path contains no slash, so it is a path relative to the current dir
368 dirPath = ".";
369 leafName = path;
372 // catch special case: no leaf, or leaf is a directory
373 if (!leafName || strcmp(leafName, ".") == 0 || strcmp(leafName, "..") == 0)
374 return normalize_dir_path(path, normalizedPath);
376 // normalize the dir path
377 status_t error = normalize_dir_path(dirPath, normalizedPath);
378 if (error != B_OK)
379 return error;
381 // append the leaf name
382 if (normalizedPath.length() > 1) // don't append "/", if parent is root
383 normalizedPath += '/';
384 normalizedPath += leafName;
386 return B_OK;
390 // #pragma mark -
392 typedef map<NodeRef, string> DirPathMap;
393 static DirPathMap sDirPathMap;
395 // get_path
396 static status_t
397 get_path(const NodeRef *ref, const char *name, string &path)
399 if (!ref && !name)
400 return B_BAD_VALUE;
402 // no ref or absolute path
403 if (!ref || (name && name[0] == '/')) {
404 path = name;
405 return B_OK;
408 // get the dir path
409 if (ref) {
410 DirPathMap::iterator it = sDirPathMap.find(*ref);
411 if (it == sDirPathMap.end())
412 return B_ENTRY_NOT_FOUND;
414 path = it->second;
416 // stat the path to check, if it is still valid
417 struct stat st;
418 if (lstat(path.c_str(), &st) < 0) {
419 sDirPathMap.erase(it);
420 return errno;
423 // compare the NodeRef
424 if (NodeRef(st) != *ref) {
425 sDirPathMap.erase(it);
426 return B_ENTRY_NOT_FOUND;
429 // still a directory?
430 if (!S_ISDIR(st.st_mode)) {
431 sDirPathMap.erase(it);
432 return B_NOT_A_DIRECTORY;
436 // if there's a name, append it
437 if (name) {
438 path += '/';
439 path += name;
442 return B_OK;
445 // get_path
446 status_t
447 BPrivate::get_path(int fd, const char *name, string &path)
449 // get the node ref for the fd, if any, and the path part is not absolute
450 if (fd >= 0 && !(name && name[0] == '/')) {
451 // get descriptor
452 Descriptor *descriptor = get_descriptor(fd);
453 if (!descriptor)
454 return B_FILE_ERROR;
456 // Handle symlink descriptors here explicitly, so this function can be
457 // used more flexibly.
458 if (SymlinkDescriptor* symlinkDescriptor
459 = dynamic_cast<SymlinkDescriptor*>(descriptor)) {
460 path = symlinkDescriptor->path;
461 if (name == NULL)
462 return B_OK;
463 path += '/';
464 path += name;
465 return B_OK;
468 // get node ref for the descriptor
469 NodeRef ref;
470 status_t error = descriptor->GetNodeRef(ref);
471 if (error != B_OK)
472 return error;
474 return ::get_path(&ref, name, path);
476 } else // no descriptor or absolute path
477 return ::get_path((NodeRef*)NULL, name, path);
480 // get_path
481 static status_t
482 get_path(dev_t device, ino_t directory, const char *name, string &path)
484 NodeRef ref;
485 ref.device = device;
486 ref.node = directory;
488 return get_path(&ref, name, path);
491 // add_dir_path
492 static void
493 add_dir_path(const char *path, const NodeRef &ref)
495 // add the normalized path
496 string normalizedPath;
497 if (normalize_dir_path(path, normalizedPath) == B_OK)
498 sDirPathMap[ref] = normalizedPath;
502 // #pragma mark -
504 // _kern_entry_ref_to_path
505 status_t
506 _kern_entry_ref_to_path(dev_t device, ino_t node, const char *leaf,
507 char *userPath, size_t pathLength)
509 // get the path
510 string path;
511 status_t error = get_path(device, node, leaf, path);
512 if (error != B_OK)
513 return error;
515 // copy it back to the user buffer
516 if (strlcpy(userPath, path.c_str(), pathLength) >= pathLength)
517 return B_BUFFER_OVERFLOW;
519 return B_OK;
523 // #pragma mark -
525 // _kern_create_dir
526 status_t
527 _kern_create_dir(int fd, const char *path, int perms)
529 // get a usable path
530 string realPath;
531 status_t error = get_path(fd, path, realPath);
532 if (error != B_OK)
533 return error;
535 // mkdir
536 if (mkdir(realPath.c_str(), perms) < 0)
537 return errno;
539 return B_OK;
542 // _kern_create_dir_entry_ref
543 status_t
544 _kern_create_dir_entry_ref(dev_t device, ino_t node, const char *name,
545 int perms)
547 // get a usable path
548 string realPath;
549 status_t error = get_path(device, node, name, realPath);
550 if (error != B_OK)
551 return error;
553 // mkdir
554 if (mkdir(realPath.c_str(), perms) < 0)
555 return errno;
557 return B_OK;
560 // open_dir
561 static int
562 open_dir(const char *path)
564 // open the dir
565 DIR *dir = opendir(path);
566 if (!dir)
567 return errno;
569 // stat the entry
570 struct stat st;
571 if (stat(path, &st) < 0) {
572 closedir(dir);
573 return errno;
576 if (!S_ISDIR(st.st_mode)) {
577 closedir(dir);
578 return B_NOT_A_DIRECTORY;
581 // cache dir path
582 NodeRef ref(st);
583 add_dir_path(path, ref);
585 // create descriptor
586 DirectoryDescriptor *descriptor = new DirectoryDescriptor(dir, ref);
587 return add_descriptor(descriptor);
590 // _kern_open_dir
592 _kern_open_dir(int fd, const char *path)
594 // get a usable path
595 string realPath;
596 status_t error = get_path(fd, path, realPath);
597 if (error != B_OK)
598 return error;
600 return open_dir(realPath.c_str());
603 // _kern_open_dir_entry_ref
605 _kern_open_dir_entry_ref(dev_t device, ino_t node, const char *name)
607 // get a usable path
608 string realPath;
609 status_t error = get_path(device, node, name, realPath);
610 if (error != B_OK)
611 return error;
613 return open_dir(realPath.c_str());
616 // _kern_open_parent_dir
618 _kern_open_parent_dir(int fd, char *name, size_t nameLength)
620 // get a usable path
621 string realPath;
622 status_t error = get_path(fd, NULL, realPath);
623 if (error != B_OK)
624 return error;
626 // stat the entry
627 struct stat st;
628 if (stat(realPath.c_str(), &st) < 0)
629 return errno;
631 if (!S_ISDIR(st.st_mode))
632 return B_NOT_A_DIRECTORY;
634 // get the entry name
635 realPath += "/..";
636 string entryName;
637 error = find_dir_entry(realPath.c_str(), NodeRef(st),
638 entryName, false);
639 if (error != B_OK)
640 return error;
642 if (strlcpy(name, entryName.c_str(), nameLength) >= nameLength)
643 return B_BUFFER_OVERFLOW;
645 // open the parent directory
647 return open_dir(realPath.c_str());
650 // _kern_read_dir
651 ssize_t
652 _kern_read_dir(int fd, struct dirent *buffer, size_t bufferSize,
653 uint32 maxCount)
655 if (maxCount <= 0)
656 return B_BAD_VALUE;
658 // get the descriptor
659 DirectoryDescriptor *descriptor
660 = dynamic_cast<DirectoryDescriptor*>(get_descriptor(fd));
661 if (!descriptor)
662 return B_FILE_ERROR;
664 // get the next entry
665 dirent *entry;
666 errno = 0;
667 if (dynamic_cast<AttrDirDescriptor*>(descriptor))
668 entry = fs_read_attr_dir(descriptor->dir);
669 else
670 entry = readdir(descriptor->dir);
671 if (!entry)
672 return errno;
674 // copy the entry
675 int entryLen = &entry->d_name[strlen(entry->d_name) + 1] - (char*)entry;
676 if (entryLen > (int)bufferSize)
677 return B_BUFFER_OVERFLOW;
679 memcpy(buffer, entry, entryLen);
681 return 1;
684 // _kern_rewind_dir
685 status_t
686 _kern_rewind_dir(int fd)
688 // get the descriptor
689 DirectoryDescriptor *descriptor
690 = dynamic_cast<DirectoryDescriptor*>(get_descriptor(fd));
691 if (!descriptor)
692 return B_FILE_ERROR;
694 // rewind
695 if (dynamic_cast<AttrDirDescriptor*>(descriptor))
696 fs_rewind_attr_dir(descriptor->dir);
697 else
698 rewinddir(descriptor->dir);
700 return B_OK;
704 // #pragma mark -
706 // open_file
707 static int
708 open_file(const char *path, int openMode, int perms)
710 // stat the node
711 bool exists = true;
712 struct stat st;
713 if (lstat(path, &st) < 0) {
714 exists = false;
715 if (!(openMode & O_CREAT))
716 return errno;
719 Descriptor *descriptor;
720 if (exists && S_ISLNK(st.st_mode) && (openMode & O_NOTRAVERSE) != 0) {
721 // a symlink not to be followed: create a special descriptor
722 // normalize path first
723 string normalizedPath;
724 status_t error = normalize_entry_path(path, normalizedPath);
725 if (error != B_OK)
726 return error;
728 descriptor = new SymlinkDescriptor(normalizedPath.c_str());
729 } else {
730 // open the file
731 openMode &= ~O_NOTRAVERSE;
732 int newFD = open(path, openMode, perms);
733 if (newFD < 0)
734 return errno;
736 descriptor = new FileDescriptor(newFD);
739 // cache path, if this is a directory
740 if (exists && S_ISDIR(st.st_mode))
741 add_dir_path(path, NodeRef(st));
743 return add_descriptor(descriptor);
746 // _kern_open
748 _kern_open(int fd, const char *path, int openMode, int perms)
750 // get a usable path
751 string realPath;
752 status_t error = get_path(fd, path, realPath);
753 if (error != B_OK)
754 return error;
756 return open_file(realPath.c_str(), openMode, perms);
759 // _kern_open_entry_ref
761 _kern_open_entry_ref(dev_t device, ino_t node, const char *name,
762 int openMode, int perms)
764 // get a usable path
765 string realPath;
766 status_t error = get_path(device, node, name, realPath);
767 if (error != B_OK)
768 return error;
770 return open_file(realPath.c_str(), openMode, perms);
773 // _kern_seek
774 off_t
775 _kern_seek(int fd, off_t pos, int seekType)
777 // get the descriptor
778 FileDescriptor *descriptor
779 = dynamic_cast<FileDescriptor*>(get_descriptor(fd));
780 if (!descriptor)
781 return B_FILE_ERROR;
783 // seek
784 off_t result = lseek(descriptor->fd, pos, seekType);
785 if (result < 0)
786 return errno;
788 return result;
791 // _kern_read
792 ssize_t
793 _kern_read(int fd, off_t pos, void *buffer, size_t bufferSize)
795 // get the descriptor
796 FileDescriptor *descriptor
797 = dynamic_cast<FileDescriptor*>(get_descriptor(fd));
798 if (!descriptor)
799 return B_FILE_ERROR;
801 // seek
802 if (pos != -1) {
803 off_t result = lseek(descriptor->fd, pos, SEEK_SET);
804 if (result < 0)
805 return errno;
808 // read
809 ssize_t bytesRead = haiku_host_platform_read(descriptor->fd, buffer,
810 bufferSize);
811 if (bytesRead < 0)
812 return errno;
814 return bytesRead;
817 // _kern_write
818 ssize_t
819 _kern_write(int fd, off_t pos, const void *buffer, size_t bufferSize)
821 // get the descriptor
822 FileDescriptor *descriptor
823 = dynamic_cast<FileDescriptor*>(get_descriptor(fd));
824 if (!descriptor)
825 return B_FILE_ERROR;
827 // seek
828 if (pos != -1) {
829 off_t result = lseek(descriptor->fd, pos, SEEK_SET);
830 if (result < 0)
831 return errno;
834 // read
835 ssize_t bytesWritten = haiku_host_platform_write(descriptor->fd, buffer,
836 bufferSize);
837 if (bytesWritten < 0)
838 return errno;
840 return bytesWritten;
843 // _kern_close
844 status_t
845 _kern_close(int fd)
847 return delete_descriptor(fd);
850 // _kern_dup
852 _kern_dup(int fd)
854 // get the descriptor
855 Descriptor *descriptor = get_descriptor(fd);
856 if (!descriptor)
857 return B_FILE_ERROR;
859 // clone it
860 Descriptor *clone;
861 status_t error = descriptor->Dup(clone);
862 if (error != B_OK)
863 return error;
865 return add_descriptor(clone);
868 // _kern_fsync
869 status_t
870 _kern_fsync(int fd)
872 // get the descriptor
873 FileDescriptor *descriptor
874 = dynamic_cast<FileDescriptor*>(get_descriptor(fd));
875 if (!descriptor)
876 return B_FILE_ERROR;
878 // sync
879 if (fsync(descriptor->fd) < 0)
880 return errno;
882 return B_OK;
885 // _kern_read_stat
886 status_t
887 _kern_read_stat(int fd, const char *path, bool traverseLink,
888 struct stat *st, size_t statSize)
890 if (path) {
891 // get a usable path
892 string realPath;
893 status_t error = get_path(fd, path, realPath);
894 if (error != B_OK)
895 return error;
897 // stat
898 int result;
899 if (traverseLink)
900 result = stat(realPath.c_str(), st);
901 else
902 result = lstat(realPath.c_str(), st);
904 if (result < 0)
905 return errno;
906 } else {
907 Descriptor *descriptor = get_descriptor(fd);
908 if (!descriptor)
909 return B_FILE_ERROR;
911 return descriptor->GetStat(traverseLink, st);
914 return B_OK;
917 // _kern_write_stat
918 status_t
919 _kern_write_stat(int fd, const char *path, bool traverseLink,
920 const struct stat *st, size_t statSize, int statMask)
922 // get a usable path
923 int realFD = -1;
924 string realPath;
925 status_t error;
926 bool isSymlink = false;
927 if (path) {
928 error = get_path(fd, path, realPath);
929 if (error != B_OK)
930 return error;
932 // stat it to see, if it is a symlink
933 struct stat tmpStat;
934 if (lstat(realPath.c_str(), &tmpStat) < 0)
935 return errno;
937 isSymlink = S_ISLNK(tmpStat.st_mode);
939 } else {
940 Descriptor *descriptor = get_descriptor(fd);
941 if (!descriptor)
942 return B_FILE_ERROR;
944 if (FileDescriptor *fileFD
945 = dynamic_cast<FileDescriptor*>(descriptor)) {
946 realFD = fileFD->fd;
948 } else if (dynamic_cast<DirectoryDescriptor*>(descriptor)) {
949 error = get_path(fd, NULL, realPath);
950 if (error != B_OK)
951 return error;
953 } else if (SymlinkDescriptor *linkFD
954 = dynamic_cast<SymlinkDescriptor*>(descriptor)) {
955 realPath = linkFD->path;
956 isSymlink = true;
958 } else
959 return B_FILE_ERROR;
962 // We're screwed, if the node to manipulate is a symlink. All the
963 // available functions traverse symlinks.
964 if (isSymlink && !traverseLink)
965 return B_ERROR;
967 if (realFD >= 0) {
968 if (statMask & B_STAT_MODE) {
969 if (fchmod(realFD, st->st_mode) < 0)
970 return errno;
973 if (statMask & B_STAT_UID) {
974 if (fchown(realFD, st->st_uid, (gid_t)-1) < 0)
975 return errno;
978 if (statMask & B_STAT_GID) {
979 if (fchown(realFD, (uid_t)-1, st->st_gid) < 0)
980 return errno;
983 if (statMask & B_STAT_SIZE) {
984 if (ftruncate(realFD, st->st_size) < 0)
985 return errno;
988 // The timestamps can only be set via utime(), but that requires a
989 // path we don't have.
990 if (statMask & (B_STAT_ACCESS_TIME | B_STAT_MODIFICATION_TIME
991 | B_STAT_CREATION_TIME | B_STAT_CHANGE_TIME)) {
992 return B_ERROR;
995 return 0;
997 } else {
998 if (statMask & B_STAT_MODE) {
999 if (chmod(realPath.c_str(), st->st_mode) < 0)
1000 return errno;
1003 if (statMask & B_STAT_UID) {
1004 if (chown(realPath.c_str(), st->st_uid, (gid_t)-1) < 0)
1005 return errno;
1008 if (statMask & B_STAT_GID) {
1009 if (chown(realPath.c_str(), (uid_t)-1, st->st_gid) < 0)
1010 return errno;
1013 if (statMask & B_STAT_SIZE) {
1014 if (truncate(realPath.c_str(), st->st_size) < 0)
1015 return errno;
1018 if (statMask & (B_STAT_ACCESS_TIME | B_STAT_MODIFICATION_TIME)) {
1019 // Grab the previous mod and access times so we only overwrite
1020 // the specified time and not both
1021 struct stat oldStat;
1022 if (~statMask & (B_STAT_ACCESS_TIME | B_STAT_MODIFICATION_TIME)) {
1023 if (stat(realPath.c_str(), &oldStat) < 0)
1024 return errno;
1027 utimbuf buffer;
1028 buffer.actime = (statMask & B_STAT_ACCESS_TIME) ? st->st_atime : oldStat.st_atime;
1029 buffer.modtime = (statMask & B_STAT_MODIFICATION_TIME) ? st->st_mtime : oldStat.st_mtime;
1030 if (utime(realPath.c_str(), &buffer) < 0)
1031 return errno;
1034 // not supported
1035 if (statMask & (B_STAT_CREATION_TIME | B_STAT_CHANGE_TIME))
1036 return B_ERROR;
1039 return B_OK;
1043 // #pragma mark -
1045 // _kern_create_symlink
1046 status_t
1047 _kern_create_symlink(int fd, const char *path, const char *toPath, int mode)
1049 // Note: path must not be NULL, so this will always work.
1050 // get a usable path
1051 string realPath;
1052 status_t error = get_path(fd, path, realPath);
1053 if (error != B_OK)
1054 return error;
1056 // symlink
1057 if (symlink(toPath, realPath.c_str()) < 0)
1058 return errno;
1060 return B_OK;
1063 // _kern_read_link
1064 status_t
1065 _kern_read_link(int fd, const char *path, char *buffer, size_t *_bufferSize)
1067 // get the path
1068 string realPath;
1069 status_t error = get_path(fd, path, realPath);
1070 if (error != B_OK)
1071 return error;
1073 // readlink
1074 ssize_t bytesRead = readlink(realPath.c_str(), buffer, *_bufferSize);
1075 if (bytesRead < 0)
1076 return errno;
1078 if (*_bufferSize > 0) {
1079 if ((size_t)bytesRead == *_bufferSize)
1080 bytesRead--;
1082 buffer[bytesRead] = '\0';
1085 *_bufferSize = bytesRead;
1087 return B_OK;
1090 // _kern_unlink
1091 status_t
1092 _kern_unlink(int fd, const char *path)
1094 // get a usable path
1095 string realPath;
1096 status_t error = get_path(fd, path, realPath);
1097 if (error != B_OK)
1098 return error;
1100 // unlink
1101 if (unlink(realPath.c_str()) < 0)
1102 return errno;
1104 return B_OK;
1107 // _kern_rename
1108 status_t
1109 _kern_rename(int oldDir, const char *oldPath, int newDir, const char *newPath)
1111 // get usable paths
1112 string realOldPath;
1113 status_t error = get_path(oldDir, oldPath, realOldPath);
1114 if (error != B_OK)
1115 return error;
1117 string realNewPath;
1118 error = get_path(newDir, newPath, realNewPath);
1119 if (error != B_OK)
1120 return error;
1122 // rename
1123 if (rename(realOldPath.c_str(), realNewPath.c_str()) < 0)
1124 return errno;
1126 return B_OK;
1130 // #pragma mark -
1132 // _kern_lock_node
1133 status_t
1134 _kern_lock_node(int fd)
1136 return B_ERROR;
1139 // _kern_unlock_node
1140 status_t
1141 _kern_unlock_node(int fd)
1143 return B_ERROR;
1147 // #pragma mark -
1149 // read_pos
1150 ssize_t
1151 read_pos(int fd, off_t pos, void *buffer, size_t bufferSize)
1153 // seek
1154 off_t result = lseek(fd, pos, SEEK_SET);
1155 if (result < 0)
1156 return errno;
1158 // read
1159 ssize_t bytesRead = haiku_host_platform_read(fd, buffer, bufferSize);
1160 if (bytesRead < 0) {
1161 errno = bytesRead;
1162 return -1;
1165 return bytesRead;
1168 // write_pos
1169 ssize_t
1170 write_pos(int fd, off_t pos, const void *buffer, size_t bufferSize)
1172 // If this is an attribute descriptor, let it do the job.
1173 AttributeDescriptor* descriptor
1174 = dynamic_cast<AttributeDescriptor*>(get_descriptor(fd));
1175 if (descriptor != NULL) {
1176 status_t error = descriptor->Write(pos, buffer, bufferSize);
1177 if (error != B_OK) {
1178 errno = error;
1179 return -1;
1182 return bufferSize;
1185 // seek
1186 off_t result = lseek(fd, pos, SEEK_SET);
1187 if (result < 0)
1188 return errno;
1190 // write
1191 ssize_t bytesWritten = haiku_host_platform_write(fd, buffer, bufferSize);
1192 if (bytesWritten < 0) {
1193 errno = bytesWritten;
1194 return -1;
1197 return bytesWritten;
1200 // readv_pos
1201 ssize_t
1202 readv_pos(int fd, off_t pos, const struct iovec *vec, size_t count)
1204 // seek
1205 off_t result = lseek(fd, pos, SEEK_SET);
1206 if (result < 0)
1207 return errno;
1209 // read
1210 ssize_t bytesRead = haiku_host_platform_readv(fd, vec, count);
1211 if (bytesRead < 0) {
1212 errno = bytesRead;
1213 return -1;
1216 return bytesRead;
1219 // writev_pos
1220 ssize_t
1221 writev_pos(int fd, off_t pos, const struct iovec *vec, size_t count)
1223 // seek
1224 off_t result = lseek(fd, pos, SEEK_SET);
1225 if (result < 0)
1226 return errno;
1228 // read
1229 ssize_t bytesWritten = haiku_host_platform_writev(fd, vec, count);
1230 if (bytesWritten < 0) {
1231 errno = bytesWritten;
1232 return -1;
1235 return bytesWritten;
1239 // #pragma mark -
1243 _haiku_build_fchmod(int fd, mode_t mode)
1245 return _haiku_build_fchmodat(fd, NULL, mode, AT_SYMLINK_NOFOLLOW);
1250 _haiku_build_fchmodat(int fd, const char* path, mode_t mode, int flag)
1252 if (fd >= 0 && fd != AT_FDCWD && get_descriptor(fd) == NULL)
1253 return fchmodat(fd, path, mode, flag);
1255 struct stat st;
1256 st.st_mode = mode;
1258 RETURN_AND_SET_ERRNO(_kern_write_stat(fd, path,
1259 (flag & AT_SYMLINK_NOFOLLOW) == 0, &st, sizeof(st), B_STAT_MODE));
1264 _haiku_build_fstat(int fd, struct stat* st)
1266 return _haiku_build_fstatat(fd, NULL, st, AT_SYMLINK_NOFOLLOW);
1271 _haiku_build_fstatat(int fd, const char* path, struct stat* st, int flag)
1273 if (fd >= 0 && fd != AT_FDCWD && get_descriptor(fd) == NULL)
1274 return fstatat(fd, path, st, flag);
1276 RETURN_AND_SET_ERRNO(_kern_read_stat(fd, path,
1277 (flag & AT_SYMLINK_NOFOLLOW) == 0, st, sizeof(*st)));
1282 _haiku_build_mkdirat(int fd, const char* path, mode_t mode)
1284 if (fd >= 0 && fd != AT_FDCWD && get_descriptor(fd) == NULL)
1285 return mkdirat(fd, path, mode);
1287 RETURN_AND_SET_ERRNO(_kern_create_dir(fd, path, mode));
1292 _haiku_build_mkfifoat(int fd, const char* path, mode_t mode)
1294 return mkfifoat(fd, path, mode);
1296 // TODO: Handle non-system FDs.
1301 _haiku_build_utimensat(int fd, const char* path, const struct timespec times[2],
1302 int flag)
1304 if (fd >= 0 && fd != AT_FDCWD && get_descriptor(fd) == NULL)
1305 return utimensat(fd, path, times, flag);
1307 struct stat stat;
1308 status_t status;
1309 uint32 mask = 0;
1311 // Init the stat time fields to the current time, if at least one time is
1312 // supposed to be set to it.
1313 if (times == NULL || times[0].tv_nsec == UTIME_NOW
1314 || times[1].tv_nsec == UTIME_NOW) {
1315 timeval now;
1316 gettimeofday(&now, NULL);
1317 HAIKU_HOST_STAT_ATIM(stat).tv_sec
1318 = HAIKU_HOST_STAT_MTIM(stat).tv_sec = now.tv_sec;
1319 HAIKU_HOST_STAT_ATIM(stat).tv_nsec
1320 = HAIKU_HOST_STAT_MTIM(stat).tv_nsec = now.tv_usec * 1000;
1323 if (times != NULL) {
1324 // access time
1325 if (times[0].tv_nsec != UTIME_OMIT) {
1326 mask |= B_STAT_ACCESS_TIME;
1328 if (times[0].tv_nsec != UTIME_NOW) {
1329 if (times[0].tv_nsec < 0 || times[0].tv_nsec > 999999999)
1330 RETURN_AND_SET_ERRNO(EINVAL);
1333 HAIKU_HOST_STAT_ATIM(stat) = times[0];
1336 // modified time
1337 if (times[1].tv_nsec != UTIME_OMIT) {
1338 mask |= B_STAT_MODIFICATION_TIME;
1340 if (times[1].tv_nsec != UTIME_NOW) {
1341 if (times[1].tv_nsec < 0 || times[1].tv_nsec > 999999999)
1342 RETURN_AND_SET_ERRNO(EINVAL);
1345 HAIKU_HOST_STAT_MTIM(stat) = times[1];
1347 } else
1348 mask |= B_STAT_ACCESS_TIME | B_STAT_MODIFICATION_TIME;
1350 // set the times -- as per spec we even need to do this, if both have
1351 // UTIME_OMIT set
1352 status = _kern_write_stat(fd, path, (flag & AT_SYMLINK_NOFOLLOW) == 0,
1353 &stat, sizeof(struct stat), mask);
1355 RETURN_AND_SET_ERRNO(status);
1360 _haiku_build_futimens(int fd, const struct timespec times[2])
1362 return _haiku_build_utimensat(fd, NULL, times, AT_SYMLINK_NOFOLLOW);
1367 _haiku_build_faccessat(int fd, const char* path, int accessMode, int flag)
1369 if (fd >= 0 && fd != AT_FDCWD && get_descriptor(fd) == NULL)
1370 return faccessat(fd, path, accessMode, flag);
1372 // stat the file
1373 struct stat st;
1374 status_t error = _kern_read_stat(fd, path, false, &st, sizeof(st));
1375 if (error != B_OK)
1376 RETURN_AND_SET_ERRNO(error);
1378 // get the current user
1379 uid_t uid = (flag & AT_EACCESS) != 0 ? geteuid() : getuid();
1381 int fileMode = 0;
1383 if (uid == 0) {
1384 // user is root
1385 // root has always read/write permission, but at least one of the
1386 // X bits must be set for execute permission
1387 fileMode = R_OK | W_OK;
1388 if ((st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) != 0)
1389 fileMode |= X_OK;
1390 } else if (st.st_uid == uid) {
1391 // user is node owner
1392 if ((st.st_mode & S_IRUSR) != 0)
1393 fileMode |= R_OK;
1394 if ((st.st_mode & S_IWUSR) != 0)
1395 fileMode |= W_OK;
1396 if ((st.st_mode & S_IXUSR) != 0)
1397 fileMode |= X_OK;
1398 } else if (st.st_gid == ((flag & AT_EACCESS) != 0 ? getegid() : getgid())) {
1399 // user is in owning group
1400 if ((st.st_mode & S_IRGRP) != 0)
1401 fileMode |= R_OK;
1402 if ((st.st_mode & S_IWGRP) != 0)
1403 fileMode |= W_OK;
1404 if ((st.st_mode & S_IXGRP) != 0)
1405 fileMode |= X_OK;
1406 } else {
1407 // user is one of the others
1408 if ((st.st_mode & S_IROTH) != 0)
1409 fileMode |= R_OK;
1410 if ((st.st_mode & S_IWOTH) != 0)
1411 fileMode |= W_OK;
1412 if ((st.st_mode & S_IXOTH) != 0)
1413 fileMode |= X_OK;
1416 if ((accessMode & ~fileMode) != 0)
1417 RETURN_AND_SET_ERRNO(EACCES);
1419 return 0;
1424 _haiku_build_fchdir(int fd)
1426 if (is_unknown_or_system_descriptor(fd))
1427 return fchdir(fd);
1429 RETURN_AND_SET_ERRNO(B_FILE_ERROR);
1434 _haiku_build_close(int fd)
1436 if (get_descriptor(fd) == NULL)
1437 return close(fd);
1439 RETURN_AND_SET_ERRNO(_kern_close(fd));
1444 _haiku_build_dup(int fd)
1446 if (get_descriptor(fd) == NULL)
1447 return close(fd);
1449 RETURN_AND_SET_ERRNO(_kern_dup(fd));
1454 _haiku_build_dup2(int fd1, int fd2)
1456 if (is_unknown_or_system_descriptor(fd1))
1457 return dup2(fd1, fd2);
1459 // TODO: Handle non-system FDs.
1460 RETURN_AND_SET_ERRNO(B_NOT_SUPPORTED);
1465 _haiku_build_linkat(int toFD, const char* toPath, int pathFD, const char* path,
1466 int flag)
1468 return linkat(toFD, toPath, pathFD, path, flag);
1470 // TODO: Handle non-system FDs.
1475 _haiku_build_unlinkat(int fd, const char* path, int flag)
1477 if (fd >= 0 && fd != AT_FDCWD && get_descriptor(fd) == NULL)
1478 return unlinkat(fd, path, flag);
1480 RETURN_AND_SET_ERRNO(_kern_unlink(fd, path));
1484 ssize_t
1485 _haiku_build_readlinkat(int fd, const char* path, char* buffer,
1486 size_t bufferSize)
1488 if (fd >= 0 && fd != AT_FDCWD && get_descriptor(fd) == NULL)
1489 return readlinkat(fd, path, buffer, bufferSize);
1491 status_t error = _kern_read_link(fd, path, buffer, &bufferSize);
1492 if (error != B_OK)
1493 RETURN_AND_SET_ERRNO(error);
1495 return bufferSize;
1500 _haiku_build_symlinkat(const char* toPath, int fd, const char* symlinkPath)
1502 if (fd >= 0 && fd != AT_FDCWD && get_descriptor(fd) == NULL)
1503 return symlinkat(toPath, fd, symlinkPath);
1505 RETURN_AND_SET_ERRNO(_kern_create_symlink(fd, symlinkPath, toPath,
1506 S_IRWXU | S_IRWXG | S_IRWXO));
1511 _haiku_build_ftruncate(int fd, off_t newSize)
1513 if (fd >= 0 && fd != AT_FDCWD && get_descriptor(fd) == NULL)
1514 return ftruncate(fd, newSize);
1516 struct stat st;
1517 st.st_size = newSize;
1519 RETURN_AND_SET_ERRNO(_kern_write_stat(fd, NULL, false, &st, sizeof(st),
1520 B_STAT_SIZE));
1525 _haiku_build_fchown(int fd, uid_t owner, gid_t group)
1527 return _haiku_build_fchownat(fd, NULL, owner, group, AT_SYMLINK_NOFOLLOW);
1532 _haiku_build_fchownat(int fd, const char* path, uid_t owner, gid_t group,
1533 int flag)
1535 if (fd >= 0 && fd != AT_FDCWD && get_descriptor(fd) == NULL)
1536 return fchownat(fd, path, owner, group, flag);
1538 struct stat st;
1539 st.st_uid = owner;
1540 st.st_gid = group;
1542 RETURN_AND_SET_ERRNO(_kern_write_stat(fd, path,
1543 (flag & AT_SYMLINK_NOFOLLOW) == 0, &st, sizeof(st),
1544 B_STAT_UID | B_STAT_GID));
1549 _haiku_build_mknodat(int fd, const char* name, mode_t mode, dev_t dev)
1551 return mknodat(fd, name, mode, dev);
1553 // TODO: Handle non-system FDs.
1558 _haiku_build_creat(const char* path, mode_t mode)
1560 return _haiku_build_open(path, O_WRONLY | O_CREAT | O_TRUNC, mode);
1565 _haiku_build_open(const char* path, int openMode, mode_t permissions)
1567 return _haiku_build_openat(AT_FDCWD, path, openMode, permissions);
1572 _haiku_build_openat(int fd, const char* path, int openMode, mode_t permissions)
1574 // adapt the permissions as required by POSIX
1575 mode_t mask = umask(0);
1576 umask(mask);
1577 permissions &= ~mask;
1579 RETURN_AND_SET_ERRNO(_kern_open(fd, path, openMode, permissions));
1584 _haiku_build_fcntl(int fd, int op, int argument)
1586 if (is_unknown_or_system_descriptor(fd))
1587 return fcntl(fd, op, argument);
1589 RETURN_AND_SET_ERRNO(B_NOT_SUPPORTED);
1594 _haiku_build_renameat(int fromFD, const char* from, int toFD, const char* to)
1596 if ((fromFD >= 0 && fromFD != AT_FDCWD && get_descriptor(fromFD) == NULL)
1597 || (toFD >= 0 && toFD != AT_FDCWD && get_descriptor(toFD) == NULL)) {
1598 return renameat(fromFD, from, toFD, to);
1601 RETURN_AND_SET_ERRNO(_kern_rename(fromFD, from, toFD, to));