2 * Copyright 2005-2011, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
7 #include <BeOSBuildCompatibility.h>
25 #include <NodeMonitor.h> // for B_STAT_* flags
28 #include "fs_descriptors.h"
30 #include "remapped_functions.h"
32 #if defined(HAIKU_HOST_PLATFORM_FREEBSD)
33 # include "fs_freebsd.h"
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)
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)
64 #define RETURN_AND_SET_ERRNO(err) \
66 __typeof(err) __result = (err); \
75 #if defined(_HAIKU_BUILD_NO_FUTIMENS) || defined(_HAIKU_BUILD_NO_FUTIMENS)
77 template<typename File
>
79 utimes_helper(File
& file
, const struct timespec times
[2])
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
) {
92 if (file
.GetStat(st
) != 0)
95 if (times
[0].tv_nsec
== UTIME_OMIT
&& times
[1].tv_nsec
== UTIME_OMIT
)
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
) {
111 gettimeofday(&now
, NULL
);
113 if (times
[0].tv_nsec
== UTIME_NOW
)
116 if (times
[1].tv_nsec
== UTIME_NOW
)
120 return file
.SetTimes(timeBuffer
);
123 #endif // _HAIKU_BUILD_NO_FUTIMENS || _HAIKU_BUILD_NO_FUTIMENS
126 #ifdef _HAIKU_BUILD_NO_FUTIMENS
135 int GetStat(struct stat
& _st
)
137 return fstat(fFD
, &_st
);
140 int SetTimes(const timeval times
[2])
142 return futimes(fFD
, times
);
151 futimens(int fd
, const struct timespec times
[2])
154 return utimes_helper(file
, times
);
157 #endif // _HAIKU_BUILD_NO_FUTIMENS
159 #ifdef _HAIKU_BUILD_NO_UTIMENSAT
162 FDPathFile(int fd
, const char* path
, int 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
);
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
,
204 find_dir_entry(DIR *dir
, const char *path
, NodeRef ref
, string
&name
,
209 while (dirent
*entry
= readdir(dir
)) {
210 if ((strcmp(entry
->d_name
, ".") == 0 && skipDot
)
211 || strcmp(entry
->d_name
, "..") == 0) {
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
);
220 entryPath
+= entry
->d_name
;
222 if (lstat(entryPath
.c_str(), &st
) == 0) {
223 if (NodeRef(st
) == ref
) {
224 name
= entry
->d_name
;
233 return B_ENTRY_NOT_FOUND
;
240 find_dir_entry(const char *path
, NodeRef ref
, string
&name
, bool skipDot
)
243 DIR *dir
= opendir(path
);
247 status_t error
= find_dir_entry(dir
, path
, ref
, name
, skipDot
);
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
262 char cwd
[B_PATH_NAME_LENGTH
];
263 if (getcwd(cwd
, sizeof(cwd
)) == NULL
)
266 while (cwd
[0] == '/') {
268 if (stat(cwd
, &st
) == 0) {
269 if (st
.st_dev
== ref
.device
&& st
.st_ino
== ref
.node
) {
270 _normalizedPath
= cwd
;
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 ".."
286 // normalize_dir_path
288 normalize_dir_path(string path
, NodeRef ref
, string
&normalizedPath
)
293 // stat the parent dir
295 if (lstat(path
.c_str(), &st
) < 0)
299 NodeRef
parentRef(st
);
300 if (parentRef
== ref
) {
301 normalizedPath
= "/";
307 status_t error
= find_dir_entry(path
.c_str(), ref
, name
, true) ;
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
))
322 // recurse to get the parent dir path, if found
323 error
= normalize_dir_path(path
, parentRef
, normalizedPath
);
327 // construct the normalizedPath
328 if (normalizedPath
.length() > 1) // don't append "/", if parent is root
329 normalizedPath
+= '/';
330 normalizedPath
+= name
;
335 // normalize_dir_path
337 normalize_dir_path(const char *path
, string
&normalizedPath
)
341 if (stat(path
, &st
) < 0)
344 return normalize_dir_path(path
, NodeRef(st
), normalizedPath
);
347 // normalize_entry_path
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
362 dirPathString
= string(path
, leafName
- path
);
363 dirPath
= dirPathString
.c_str();
367 // path contains no slash, so it is a path relative to the current dir
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
);
381 // append the leaf name
382 if (normalizedPath
.length() > 1) // don't append "/", if parent is root
383 normalizedPath
+= '/';
384 normalizedPath
+= leafName
;
392 typedef map
<NodeRef
, string
> DirPathMap
;
393 static DirPathMap sDirPathMap
;
397 get_path(const NodeRef
*ref
, const char *name
, string
&path
)
402 // no ref or absolute path
403 if (!ref
|| (name
&& name
[0] == '/')) {
410 DirPathMap::iterator it
= sDirPathMap
.find(*ref
);
411 if (it
== sDirPathMap
.end())
412 return B_ENTRY_NOT_FOUND
;
416 // stat the path to check, if it is still valid
418 if (lstat(path
.c_str(), &st
) < 0) {
419 sDirPathMap
.erase(it
);
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
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] == '/')) {
452 Descriptor
*descriptor
= get_descriptor(fd
);
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
;
468 // get node ref for the descriptor
470 status_t error
= descriptor
->GetNodeRef(ref
);
474 return ::get_path(&ref
, name
, path
);
476 } else // no descriptor or absolute path
477 return ::get_path((NodeRef
*)NULL
, name
, path
);
482 get_path(dev_t device
, ino_t directory
, const char *name
, string
&path
)
486 ref
.node
= directory
;
488 return get_path(&ref
, name
, path
);
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
;
504 // _kern_entry_ref_to_path
506 _kern_entry_ref_to_path(dev_t device
, ino_t node
, const char *leaf
,
507 char *userPath
, size_t pathLength
)
511 status_t error
= get_path(device
, node
, leaf
, path
);
515 // copy it back to the user buffer
516 if (strlcpy(userPath
, path
.c_str(), pathLength
) >= pathLength
)
517 return B_BUFFER_OVERFLOW
;
527 _kern_create_dir(int fd
, const char *path
, int perms
)
531 status_t error
= get_path(fd
, path
, realPath
);
536 if (mkdir(realPath
.c_str(), perms
) < 0)
542 // _kern_create_dir_entry_ref
544 _kern_create_dir_entry_ref(dev_t device
, ino_t node
, const char *name
,
549 status_t error
= get_path(device
, node
, name
, realPath
);
554 if (mkdir(realPath
.c_str(), perms
) < 0)
562 open_dir(const char *path
)
565 DIR *dir
= opendir(path
);
571 if (stat(path
, &st
) < 0) {
576 if (!S_ISDIR(st
.st_mode
)) {
578 return B_NOT_A_DIRECTORY
;
583 add_dir_path(path
, ref
);
586 DirectoryDescriptor
*descriptor
= new DirectoryDescriptor(dir
, ref
);
587 return add_descriptor(descriptor
);
592 _kern_open_dir(int fd
, const char *path
)
596 status_t error
= get_path(fd
, path
, realPath
);
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
)
609 status_t error
= get_path(device
, node
, name
, realPath
);
613 return open_dir(realPath
.c_str());
616 // _kern_open_parent_dir
618 _kern_open_parent_dir(int fd
, char *name
, size_t nameLength
)
622 status_t error
= get_path(fd
, NULL
, realPath
);
628 if (stat(realPath
.c_str(), &st
) < 0)
631 if (!S_ISDIR(st
.st_mode
))
632 return B_NOT_A_DIRECTORY
;
634 // get the entry name
637 error
= find_dir_entry(realPath
.c_str(), NodeRef(st
),
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());
652 _kern_read_dir(int fd
, struct dirent
*buffer
, size_t bufferSize
,
658 // get the descriptor
659 DirectoryDescriptor
*descriptor
660 = dynamic_cast<DirectoryDescriptor
*>(get_descriptor(fd
));
664 // get the next entry
667 if (dynamic_cast<AttrDirDescriptor
*>(descriptor
))
668 entry
= fs_read_attr_dir(descriptor
->dir
);
670 entry
= readdir(descriptor
->dir
);
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
);
686 _kern_rewind_dir(int fd
)
688 // get the descriptor
689 DirectoryDescriptor
*descriptor
690 = dynamic_cast<DirectoryDescriptor
*>(get_descriptor(fd
));
695 if (dynamic_cast<AttrDirDescriptor
*>(descriptor
))
696 fs_rewind_attr_dir(descriptor
->dir
);
698 rewinddir(descriptor
->dir
);
708 open_file(const char *path
, int openMode
, int perms
)
713 if (lstat(path
, &st
) < 0) {
715 if (!(openMode
& O_CREAT
))
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
);
728 descriptor
= new SymlinkDescriptor(normalizedPath
.c_str());
731 openMode
&= ~O_NOTRAVERSE
;
732 int newFD
= open(path
, openMode
, perms
);
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
);
748 _kern_open(int fd
, const char *path
, int openMode
, int perms
)
752 status_t error
= get_path(fd
, path
, realPath
);
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
)
766 status_t error
= get_path(device
, node
, name
, realPath
);
770 return open_file(realPath
.c_str(), openMode
, perms
);
775 _kern_seek(int fd
, off_t pos
, int seekType
)
777 // get the descriptor
778 FileDescriptor
*descriptor
779 = dynamic_cast<FileDescriptor
*>(get_descriptor(fd
));
784 off_t result
= lseek(descriptor
->fd
, pos
, seekType
);
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
));
803 off_t result
= lseek(descriptor
->fd
, pos
, SEEK_SET
);
809 ssize_t bytesRead
= haiku_host_platform_read(descriptor
->fd
, buffer
,
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
));
829 off_t result
= lseek(descriptor
->fd
, pos
, SEEK_SET
);
835 ssize_t bytesWritten
= haiku_host_platform_write(descriptor
->fd
, buffer
,
837 if (bytesWritten
< 0)
847 return delete_descriptor(fd
);
854 // get the descriptor
855 Descriptor
*descriptor
= get_descriptor(fd
);
861 status_t error
= descriptor
->Dup(clone
);
865 return add_descriptor(clone
);
872 // get the descriptor
873 FileDescriptor
*descriptor
874 = dynamic_cast<FileDescriptor
*>(get_descriptor(fd
));
879 if (fsync(descriptor
->fd
) < 0)
887 _kern_read_stat(int fd
, const char *path
, bool traverseLink
,
888 struct stat
*st
, size_t statSize
)
893 status_t error
= get_path(fd
, path
, realPath
);
900 result
= stat(realPath
.c_str(), st
);
902 result
= lstat(realPath
.c_str(), st
);
907 Descriptor
*descriptor
= get_descriptor(fd
);
911 return descriptor
->GetStat(traverseLink
, st
);
919 _kern_write_stat(int fd
, const char *path
, bool traverseLink
,
920 const struct stat
*st
, size_t statSize
, int statMask
)
926 bool isSymlink
= false;
928 error
= get_path(fd
, path
, realPath
);
932 // stat it to see, if it is a symlink
934 if (lstat(realPath
.c_str(), &tmpStat
) < 0)
937 isSymlink
= S_ISLNK(tmpStat
.st_mode
);
940 Descriptor
*descriptor
= get_descriptor(fd
);
944 if (FileDescriptor
*fileFD
945 = dynamic_cast<FileDescriptor
*>(descriptor
)) {
948 } else if (dynamic_cast<DirectoryDescriptor
*>(descriptor
)) {
949 error
= get_path(fd
, NULL
, realPath
);
953 } else if (SymlinkDescriptor
*linkFD
954 = dynamic_cast<SymlinkDescriptor
*>(descriptor
)) {
955 realPath
= linkFD
->path
;
962 // We're screwed, if the node to manipulate is a symlink. All the
963 // available functions traverse symlinks.
964 if (isSymlink
&& !traverseLink
)
968 if (statMask
& B_STAT_MODE
) {
969 if (fchmod(realFD
, st
->st_mode
) < 0)
973 if (statMask
& B_STAT_UID
) {
974 if (fchown(realFD
, st
->st_uid
, (gid_t
)-1) < 0)
978 if (statMask
& B_STAT_GID
) {
979 if (fchown(realFD
, (uid_t
)-1, st
->st_gid
) < 0)
983 if (statMask
& B_STAT_SIZE
) {
984 if (ftruncate(realFD
, st
->st_size
) < 0)
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
)) {
998 if (statMask
& B_STAT_MODE
) {
999 if (chmod(realPath
.c_str(), st
->st_mode
) < 0)
1003 if (statMask
& B_STAT_UID
) {
1004 if (chown(realPath
.c_str(), st
->st_uid
, (gid_t
)-1) < 0)
1008 if (statMask
& B_STAT_GID
) {
1009 if (chown(realPath
.c_str(), (uid_t
)-1, st
->st_gid
) < 0)
1013 if (statMask
& B_STAT_SIZE
) {
1014 if (truncate(realPath
.c_str(), st
->st_size
) < 0)
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)
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)
1035 if (statMask
& (B_STAT_CREATION_TIME
| B_STAT_CHANGE_TIME
))
1045 // _kern_create_symlink
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
1052 status_t error
= get_path(fd
, path
, realPath
);
1057 if (symlink(toPath
, realPath
.c_str()) < 0)
1065 _kern_read_link(int fd
, const char *path
, char *buffer
, size_t *_bufferSize
)
1069 status_t error
= get_path(fd
, path
, realPath
);
1074 ssize_t bytesRead
= readlink(realPath
.c_str(), buffer
, *_bufferSize
);
1078 if (*_bufferSize
> 0) {
1079 if ((size_t)bytesRead
== *_bufferSize
)
1082 buffer
[bytesRead
] = '\0';
1085 *_bufferSize
= bytesRead
;
1092 _kern_unlink(int fd
, const char *path
)
1094 // get a usable path
1096 status_t error
= get_path(fd
, path
, realPath
);
1101 if (unlink(realPath
.c_str()) < 0)
1109 _kern_rename(int oldDir
, const char *oldPath
, int newDir
, const char *newPath
)
1113 status_t error
= get_path(oldDir
, oldPath
, realOldPath
);
1118 error
= get_path(newDir
, newPath
, realNewPath
);
1123 if (rename(realOldPath
.c_str(), realNewPath
.c_str()) < 0)
1134 _kern_lock_node(int fd
)
1139 // _kern_unlock_node
1141 _kern_unlock_node(int fd
)
1151 read_pos(int fd
, off_t pos
, void *buffer
, size_t bufferSize
)
1154 off_t result
= lseek(fd
, pos
, SEEK_SET
);
1159 ssize_t bytesRead
= haiku_host_platform_read(fd
, buffer
, bufferSize
);
1160 if (bytesRead
< 0) {
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
) {
1186 off_t result
= lseek(fd
, pos
, SEEK_SET
);
1191 ssize_t bytesWritten
= haiku_host_platform_write(fd
, buffer
, bufferSize
);
1192 if (bytesWritten
< 0) {
1193 errno
= bytesWritten
;
1197 return bytesWritten
;
1202 readv_pos(int fd
, off_t pos
, const struct iovec
*vec
, size_t count
)
1205 off_t result
= lseek(fd
, pos
, SEEK_SET
);
1210 ssize_t bytesRead
= haiku_host_platform_readv(fd
, vec
, count
);
1211 if (bytesRead
< 0) {
1221 writev_pos(int fd
, off_t pos
, const struct iovec
*vec
, size_t count
)
1224 off_t result
= lseek(fd
, pos
, SEEK_SET
);
1229 ssize_t bytesWritten
= haiku_host_platform_writev(fd
, vec
, count
);
1230 if (bytesWritten
< 0) {
1231 errno
= bytesWritten
;
1235 return bytesWritten
;
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
);
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],
1304 if (fd
>= 0 && fd
!= AT_FDCWD
&& get_descriptor(fd
) == NULL
)
1305 return utimensat(fd
, path
, times
, flag
);
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
) {
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
) {
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];
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];
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
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
);
1374 status_t error
= _kern_read_stat(fd
, path
, false, &st
, sizeof(st
));
1376 RETURN_AND_SET_ERRNO(error
);
1378 // get the current user
1379 uid_t uid
= (flag
& AT_EACCESS
) != 0 ? geteuid() : getuid();
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)
1390 } else if (st
.st_uid
== uid
) {
1391 // user is node owner
1392 if ((st
.st_mode
& S_IRUSR
) != 0)
1394 if ((st
.st_mode
& S_IWUSR
) != 0)
1396 if ((st
.st_mode
& S_IXUSR
) != 0)
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)
1402 if ((st
.st_mode
& S_IWGRP
) != 0)
1404 if ((st
.st_mode
& S_IXGRP
) != 0)
1407 // user is one of the others
1408 if ((st
.st_mode
& S_IROTH
) != 0)
1410 if ((st
.st_mode
& S_IWOTH
) != 0)
1412 if ((st
.st_mode
& S_IXOTH
) != 0)
1416 if ((accessMode
& ~fileMode
) != 0)
1417 RETURN_AND_SET_ERRNO(EACCES
);
1424 _haiku_build_fchdir(int fd
)
1426 if (is_unknown_or_system_descriptor(fd
))
1429 RETURN_AND_SET_ERRNO(B_FILE_ERROR
);
1434 _haiku_build_close(int fd
)
1436 if (get_descriptor(fd
) == NULL
)
1439 RETURN_AND_SET_ERRNO(_kern_close(fd
));
1444 _haiku_build_dup(int fd
)
1446 if (get_descriptor(fd
) == NULL
)
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
,
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
));
1485 _haiku_build_readlinkat(int fd
, const char* path
, char* buffer
,
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
);
1493 RETURN_AND_SET_ERRNO(error
);
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
);
1517 st
.st_size
= newSize
;
1519 RETURN_AND_SET_ERRNO(_kern_write_stat(fd
, NULL
, false, &st
, sizeof(st
),
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
,
1535 if (fd
>= 0 && fd
!= AT_FDCWD
&& get_descriptor(fd
) == NULL
)
1536 return fchownat(fd
, path
, owner
, group
, flag
);
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);
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
));