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