180b2da5eSIngo Weinhold/*
255bc3719SIngo Weinhold * Copyright 2005-2011, Ingo Weinhold, ingo_weinhold@gmx.de.
380b2da5eSIngo Weinhold * Distributed under the terms of the MIT License.
480b2da5eSIngo Weinhold */
5f54626a7SIngo Weinhold
6880de450SAxel Dörfler
7f54626a7SIngo Weinhold#include <BeOSBuildCompatibility.h>
8f54626a7SIngo Weinhold
9f54626a7SIngo Weinhold#include "fs_impl.h"
10f54626a7SIngo Weinhold
11f54626a7SIngo Weinhold#include <dirent.h>
12f54626a7SIngo Weinhold#include <errno.h>
13f54626a7SIngo Weinhold#include <fcntl.h>
14f54626a7SIngo Weinhold#include <stdio.h>
15f54626a7SIngo Weinhold#include <stdlib.h>
16f54626a7SIngo Weinhold#include <unistd.h>
17f54626a7SIngo Weinhold#include <utime.h>
18f54626a7SIngo Weinhold#include <sys/stat.h>
1955bc3719SIngo Weinhold#include <sys/time.h>
20f54626a7SIngo Weinhold
21f54626a7SIngo Weinhold#include <map>
22f54626a7SIngo Weinhold#include <string>
23f54626a7SIngo Weinhold
24f54626a7SIngo Weinhold#include <fs_attr.h>
25f54626a7SIngo Weinhold#include <NodeMonitor.h>	// for B_STAT_* flags
26f54626a7SIngo Weinhold#include <syscalls.h>
27f54626a7SIngo Weinhold
28f54626a7SIngo Weinhold#include "fs_descriptors.h"
29f54626a7SIngo Weinhold#include "NodeRef.h"
3055bc3719SIngo Weinhold#include "remapped_functions.h"
31f54626a7SIngo Weinhold
3280b2da5eSIngo Weinhold#if defined(HAIKU_HOST_PLATFORM_FREEBSD)
3380b2da5eSIngo Weinhold#	include "fs_freebsd.h"
3480b2da5eSIngo Weinhold#endif
3580b2da5eSIngo Weinhold
3680b2da5eSIngo Weinhold
37f54626a7SIngo Weinholdusing namespace std;
38f54626a7SIngo Weinholdusing namespace BPrivate;
39f54626a7SIngo Weinhold
40f54626a7SIngo Weinhold
4180b2da5eSIngo Weinhold#if defined(HAIKU_HOST_PLATFORM_FREEBSD)
4280b2da5eSIngo Weinhold#	define haiku_host_platform_read		haiku_freebsd_read
4380b2da5eSIngo Weinhold#	define haiku_host_platform_write	haiku_freebsd_write
4480b2da5eSIngo Weinhold#	define haiku_host_platform_readv	haiku_freebsd_readv
4580b2da5eSIngo Weinhold#	define haiku_host_platform_writev	haiku_freebsd_writev
46b328f5b0SIngo Weinhold#	define HAIKU_HOST_STAT_ATIM(x)		((x).st_atimespec)
47b328f5b0SIngo Weinhold#	define HAIKU_HOST_STAT_MTIM(x)		((x).st_mtimespec)
489d6e5fdbSJohn Scipione#elif defined(HAIKU_HOST_PLATFORM_DARWIN)
499d6e5fdbSJohn Scipione#	define haiku_host_platform_read		read
509d6e5fdbSJohn Scipione#	define haiku_host_platform_write	write
519d6e5fdbSJohn Scipione#	define haiku_host_platform_readv	readv
529d6e5fdbSJohn Scipione#	define haiku_host_platform_writev	writev
539d6e5fdbSJohn Scipione#	define HAIKU_HOST_STAT_ATIM(x)		((x).st_atimespec)
549d6e5fdbSJohn Scipione#	define HAIKU_HOST_STAT_MTIM(x)		((x).st_mtimespec)
5580b2da5eSIngo Weinhold#else
5680b2da5eSIngo Weinhold#	define haiku_host_platform_read		read
5780b2da5eSIngo Weinhold#	define haiku_host_platform_write	write
5880b2da5eSIngo Weinhold#	define haiku_host_platform_readv	readv
5980b2da5eSIngo Weinhold#	define haiku_host_platform_writev	writev
60b328f5b0SIngo Weinhold#	define HAIKU_HOST_STAT_ATIM(x)		((x).st_atim)
61b328f5b0SIngo Weinhold#	define HAIKU_HOST_STAT_MTIM(x)		((x).st_mtim)
6280b2da5eSIngo Weinhold#endif
6380b2da5eSIngo Weinhold
6455bc3719SIngo Weinhold#define RETURN_AND_SET_ERRNO(err)			\
6555bc3719SIngo Weinhold	do {									\
6655bc3719SIngo Weinhold		__typeof(err) __result = (err);		\
6755bc3719SIngo Weinhold		if (__result < 0) {					\
6855bc3719SIngo Weinhold			errno = __result;				\
6955bc3719SIngo Weinhold			return -1;						\
7055bc3719SIngo Weinhold		}									\
7155bc3719SIngo Weinhold		return __result;					\
7255bc3719SIngo Weinhold	} while (0)
7355bc3719SIngo Weinhold
7480b2da5eSIngo Weinhold
759d6e5fdbSJohn Scipione#if defined(_HAIKU_BUILD_NO_FUTIMENS) || defined(_HAIKU_BUILD_NO_FUTIMENS)
769d6e5fdbSJohn Scipione
779d6e5fdbSJohn Scipionetemplate<typename File>
789d6e5fdbSJohn Scipionestatic int
799d6e5fdbSJohn Scipioneutimes_helper(File& file, const struct timespec times[2])
809d6e5fdbSJohn Scipione{
819d6e5fdbSJohn Scipione	if (times == NULL)
829d6e5fdbSJohn Scipione		return file.SetTimes(NULL);
839d6e5fdbSJohn Scipione
849d6e5fdbSJohn Scipione	timeval timeBuffer[2];
859d6e5fdbSJohn Scipione	timeBuffer[0].tv_sec = times[0].tv_sec;
869d6e5fdbSJohn Scipione	timeBuffer[0].tv_usec = times[0].tv_nsec / 1000;
879d6e5fdbSJohn Scipione	timeBuffer[1].tv_sec = times[1].tv_sec;
889d6e5fdbSJohn Scipione	timeBuffer[1].tv_usec = times[1].tv_nsec / 1000;
899d6e5fdbSJohn Scipione
909d6e5fdbSJohn Scipione	if (times[0].tv_nsec == UTIME_OMIT || times[1].tv_nsec == UTIME_OMIT) {
919d6e5fdbSJohn Scipione		struct stat st;
929d6e5fdbSJohn Scipione		if (file.GetStat(st) != 0)
939d6e5fdbSJohn Scipione			return -1;
949d6e5fdbSJohn Scipione
959d6e5fdbSJohn Scipione		if (times[0].tv_nsec == UTIME_OMIT && times[1].tv_nsec == UTIME_OMIT)
969d6e5fdbSJohn Scipione			return 0;
979d6e5fdbSJohn Scipione
989d6e5fdbSJohn Scipione		if (times[0].tv_nsec == UTIME_OMIT) {
999d6e5fdbSJohn Scipione			timeBuffer[0].tv_sec = st.st_atimespec.tv_sec;
1009d6e5fdbSJohn Scipione			timeBuffer[0].tv_usec = st.st_atimespec.tv_nsec / 1000;
1019d6e5fdbSJohn Scipione		}
1029d6e5fdbSJohn Scipione
1039d6e5fdbSJohn Scipione		if (times[1].tv_nsec == UTIME_OMIT) {
1049d6e5fdbSJohn Scipione			timeBuffer[1].tv_sec = st.st_mtimespec.tv_sec;
1059d6e5fdbSJohn Scipione			timeBuffer[1].tv_usec = st.st_mtimespec.tv_nsec / 1000;
1069d6e5fdbSJohn Scipione		}
1079d6e5fdbSJohn Scipione	}
1089d6e5fdbSJohn Scipione
1099d6e5fdbSJohn Scipione	if (times[0].tv_nsec == UTIME_NOW || times[1].tv_nsec == UTIME_NOW) {
1109d6e5fdbSJohn Scipione		timeval now;
1119d6e5fdbSJohn Scipione		gettimeofday(&now, NULL);
1129d6e5fdbSJohn Scipione
1139d6e5fdbSJohn Scipione		if (times[0].tv_nsec == UTIME_NOW)
1149d6e5fdbSJohn Scipione			timeBuffer[0] = now;
1159d6e5fdbSJohn Scipione
1169d6e5fdbSJohn Scipione		if (times[1].tv_nsec == UTIME_NOW)
1179d6e5fdbSJohn Scipione			timeBuffer[1] = now;
1189d6e5fdbSJohn Scipione	}
1199d6e5fdbSJohn Scipione
1209d6e5fdbSJohn Scipione	return file.SetTimes(timeBuffer);
1219d6e5fdbSJohn Scipione}
1229d6e5fdbSJohn Scipione
1239d6e5fdbSJohn Scipione#endif	// _HAIKU_BUILD_NO_FUTIMENS || _HAIKU_BUILD_NO_FUTIMENS
1249d6e5fdbSJohn Scipione
1259d6e5fdbSJohn Scipione
1269d6e5fdbSJohn Scipione#ifdef _HAIKU_BUILD_NO_FUTIMENS
1279d6e5fdbSJohn Scipione
1289d6e5fdbSJohn Scipionestruct FDFile {
1299d6e5fdbSJohn Scipione	FDFile(int fd)
1309d6e5fdbSJohn Scipione		:
1319d6e5fdbSJohn Scipione		fFD(fd)
1329d6e5fdbSJohn Scipione	{
1339d6e5fdbSJohn Scipione	}
1349d6e5fdbSJohn Scipione
1359d6e5fdbSJohn Scipione	int GetStat(struct stat& _st)
1369d6e5fdbSJohn Scipione	{
1379d6e5fdbSJohn Scipione		return fstat(fFD, &_st);
1389d6e5fdbSJohn Scipione	}
1399d6e5fdbSJohn Scipione
1409d6e5fdbSJohn Scipione	int SetTimes(const timeval times[2])
1419d6e5fdbSJohn Scipione	{
1429d6e5fdbSJohn Scipione		return futimes(fFD, times);
1439d6e5fdbSJohn Scipione	}
1449d6e5fdbSJohn Scipione
1459d6e5fdbSJohn Scipioneprivate:
1469d6e5fdbSJohn Scipione	int fFD;
1479d6e5fdbSJohn Scipione};
1489d6e5fdbSJohn Scipione
1499d6e5fdbSJohn Scipione
1509d6e5fdbSJohn Scipioneint
1519d6e5fdbSJohn Scipionefutimens(int fd, const struct timespec times[2])
1529d6e5fdbSJohn Scipione{
1539d6e5fdbSJohn Scipione	FDFile file(fd);
1549d6e5fdbSJohn Scipione	return utimes_helper(file, times);
1559d6e5fdbSJohn Scipione}
1569d6e5fdbSJohn Scipione
1579d6e5fdbSJohn Scipione#endif	// _HAIKU_BUILD_NO_FUTIMENS
1589d6e5fdbSJohn Scipione
1599d6e5fdbSJohn Scipione#ifdef _HAIKU_BUILD_NO_UTIMENSAT
1609d6e5fdbSJohn Scipione
1619d6e5fdbSJohn Scipionestruct FDPathFile {
1629d6e5fdbSJohn Scipione	FDPathFile(int fd, const char* path, int flag)
1639d6e5fdbSJohn Scipione		:
1649d6e5fdbSJohn Scipione		fFD(fd),
1659d6e5fdbSJohn Scipione		fPath(path),
1669d6e5fdbSJohn Scipione		fFlag(flag)
1679d6e5fdbSJohn Scipione	{
1689d6e5fdbSJohn Scipione	}
1699d6e5fdbSJohn Scipione
1709d6e5fdbSJohn Scipione	int GetStat(struct stat& _st)
1719d6e5fdbSJohn Scipione	{
1729d6e5fdbSJohn Scipione		return fstatat(fFD, fPath, &_st, fFlag);
1739d6e5fdbSJohn Scipione	}
1749d6e5fdbSJohn Scipione
1759d6e5fdbSJohn Scipione	int SetTimes(const timeval times[2])
1769d6e5fdbSJohn Scipione	{
1779d6e5fdbSJohn Scipione		// TODO: fFlag (AT_SYMLINK_NOFOLLOW) is not supported here!
1789d6e5fdbSJohn Scipione		return futimesat(fFD, fPath, times);
1799d6e5fdbSJohn Scipione	}
1809d6e5fdbSJohn Scipione
1819d6e5fdbSJohn Scipioneprivate:
1829d6e5fdbSJohn Scipione	int			fFD;
1839d6e5fdbSJohn Scipione	const char*	fPath;
1849d6e5fdbSJohn Scipione	int			fFlag;
1859d6e5fdbSJohn Scipione};
1869d6e5fdbSJohn Scipione
1879d6e5fdbSJohn Scipione
1889d6e5fdbSJohn Scipioneint
1899d6e5fdbSJohn Scipioneutimensat(int fd, const char* path, const struct timespec times[2], int flag)
1909d6e5fdbSJohn Scipione{
1919d6e5fdbSJohn Scipione	FDPathFile file(fd, path, flag);
1929d6e5fdbSJohn Scipione	return utimes_helper(file, times);
1939d6e5fdbSJohn Scipione}
1949d6e5fdbSJohn Scipione
1959d6e5fdbSJohn Scipione#endif	// _HAIKU_BUILD_NO_UTIMENSAT
1969d6e5fdbSJohn Scipione
1979d6e5fdbSJohn Scipione
198f54626a7SIngo Weinholdstatic status_t get_path(dev_t device, ino_t node, const char *name,
199f54626a7SIngo Weinhold	string &path);
200f54626a7SIngo Weinhold
201f54626a7SIngo Weinhold
202f54626a7SIngo Weinhold// find_dir_entry
203f54626a7SIngo Weinholdstatic status_t
204f54626a7SIngo Weinholdfind_dir_entry(DIR *dir, const char *path, NodeRef ref, string &name,
205f54626a7SIngo Weinhold	bool skipDot)
206f54626a7SIngo Weinhold{
207f54626a7SIngo Weinhold	// find the entry
208f54626a7SIngo Weinhold	bool found = false;
209f54626a7SIngo Weinhold	while (dirent *entry = readdir(dir)) {
210c92c12d7SIngo Weinhold		if ((strcmp(entry->d_name, ".") == 0 && skipDot)
211f54626a7SIngo Weinhold			|| strcmp(entry->d_name, "..") == 0) {
212f54626a7SIngo Weinhold			// skip "." and ".."
213f54626a7SIngo Weinhold		} else /*if (entry->d_ino == ref.node)*/ {
214f54626a7SIngo Weinhold				// Note: Linux doesn't seem to translate dirent::d_ino of
215f54626a7SIngo Weinhold				// mount points. Thus we always have to lstat().
216f54626a7SIngo Weinhold			// We also need to compare the device, which is generally not
217f54626a7SIngo Weinhold			// included in the dirent structure. Hence we lstat().
218f54626a7SIngo Weinhold			string entryPath(path);
219f54626a7SIngo Weinhold			entryPath += '/';
220f54626a7SIngo Weinhold			entryPath += entry->d_name;
221f54626a7SIngo Weinhold			struct stat st;
222f54626a7SIngo Weinhold			if (lstat(entryPath.c_str(), &st) == 0) {
223f54626a7SIngo Weinhold				if (NodeRef(st) == ref) {
224f54626a7SIngo Weinhold					name = entry->d_name;
225f54626a7SIngo Weinhold					found = true;
226f54626a7SIngo Weinhold					break;
227f54626a7SIngo Weinhold				}
228f54626a7SIngo Weinhold			}
229f54626a7SIngo Weinhold		}
230f54626a7SIngo Weinhold	}
231f54626a7SIngo Weinhold
232f54626a7SIngo Weinhold	if (!found)
233f54626a7SIngo Weinhold		return B_ENTRY_NOT_FOUND;
234f54626a7SIngo Weinhold
235f54626a7SIngo Weinhold	return B_OK;
236f54626a7SIngo Weinhold}
237f54626a7SIngo Weinhold
238f54626a7SIngo Weinhold// find_dir_entry
239f54626a7SIngo Weinholdstatic status_t
240f54626a7SIngo Weinholdfind_dir_entry(const char *path, NodeRef ref, string &name, bool skipDot)
241f54626a7SIngo Weinhold{
242f54626a7SIngo Weinhold	// open dir
243f54626a7SIngo Weinhold	DIR *dir = opendir(path);
244f54626a7SIngo Weinhold	if (!dir)
245f54626a7SIngo Weinhold		return errno;
246f54626a7SIngo Weinhold
247f54626a7SIngo Weinhold	status_t error = find_dir_entry(dir, path, ref, name, skipDot);
248f54626a7SIngo Weinhold
249f54626a7SIngo Weinhold	// close dir
250f54626a7SIngo Weinhold	closedir(dir);
251f54626a7SIngo Weinhold
252f54626a7SIngo Weinhold	return error;
253f54626a7SIngo Weinhold}
254f54626a7SIngo Weinhold
2552f5551ecSIngo Weinhold
2562f5551ecSIngo Weinholdstatic bool
2572f5551ecSIngo Weinholdguess_normalized_dir_path(string path, NodeRef ref, string& _normalizedPath)
2582f5551ecSIngo Weinhold{
2592f5551ecSIngo Weinhold	// We assume the CWD is normalized and hope that the directory is an
2602f5551ecSIngo Weinhold	// ancestor of it. We just chop off path components until we find a match or
2612f5551ecSIngo Weinhold	// hit root.
2622f5551ecSIngo Weinhold	char cwd[B_PATH_NAME_LENGTH];
2632f5551ecSIngo Weinhold	if (getcwd(cwd, sizeof(cwd)) == NULL)
2642f5551ecSIngo Weinhold		return false;
2652f5551ecSIngo Weinhold
2662f5551ecSIngo Weinhold	while (cwd[0] == '/') {
2672f5551ecSIngo Weinhold		struct stat st;
2682f5551ecSIngo Weinhold		if (stat(cwd, &st) == 0) {
2692f5551ecSIngo Weinhold			if (st.st_dev == ref.device && st.st_ino == ref.node) {
2702f5551ecSIngo Weinhold				_normalizedPath = cwd;
2712f5551ecSIngo Weinhold				return true;
2722f5551ecSIngo Weinhold			}
2732f5551ecSIngo Weinhold		}
2742f5551ecSIngo Weinhold
2752f5551ecSIngo Weinhold		*strrchr(cwd, '/') = '\0';
2762f5551ecSIngo Weinhold	}
2772f5551ecSIngo Weinhold
2782f5551ecSIngo Weinhold	// TODO: If path is absolute, we could also try to work with that, though
2792f5551ecSIngo Weinhold	// the other way around -- trying prefixes until we hit a "." or ".."
2802f5551ecSIngo Weinhold	// component.
2812f5551ecSIngo Weinhold
2822f5551ecSIngo Weinhold	return false;
2832f5551ecSIngo Weinhold}
2842f5551ecSIngo Weinhold
2852f5551ecSIngo Weinhold
286f54626a7SIngo Weinhold// normalize_dir_path
287f54626a7SIngo Weinholdstatic status_t
288f54626a7SIngo Weinholdnormalize_dir_path(string path, NodeRef ref, string &normalizedPath)
289f54626a7SIngo Weinhold{
290f54626a7SIngo Weinhold	// get parent path
291f54626a7SIngo Weinhold	path += "/..";
292f54626a7SIngo Weinhold
293f54626a7SIngo Weinhold	// stat the parent dir
294f54626a7SIngo Weinhold	struct stat st;
295f54626a7SIngo Weinhold	if (lstat(path.c_str(), &st) < 0)
296f54626a7SIngo Weinhold		return errno;
297f54626a7SIngo Weinhold
298f54626a7SIngo Weinhold	// root dir?
299f54626a7SIngo Weinhold	NodeRef parentRef(st);
300f54626a7SIngo Weinhold	if (parentRef == ref) {
301f54626a7SIngo Weinhold		normalizedPath = "/";
302f54626a7SIngo Weinhold		return 0;
303f54626a7SIngo Weinhold	}
304f54626a7SIngo Weinhold
305f54626a7SIngo Weinhold	// find the entry
306f54626a7SIngo Weinhold	string name;
307f54626a7SIngo Weinhold	status_t error = find_dir_entry(path.c_str(), ref, name, true)				;
3082f5551ecSIngo Weinhold	if (error != B_OK) {
3092f5551ecSIngo Weinhold		if (error != B_ENTRY_NOT_FOUND) {
3102f5551ecSIngo Weinhold			// We couldn't open the directory. This might be because we don't
3112f5551ecSIngo Weinhold			// have read permission. We're OK with not fully normalizing the
3122f5551ecSIngo Weinhold			// path and try to guess the path in this case. Note: We don't check
3132f5551ecSIngo Weinhold			// error for B_PERMISSION_DENIED, since opendir() may clobber the
3142f5551ecSIngo Weinhold			// actual kernel error code with something not helpful.
3152f5551ecSIngo Weinhold			if (guess_normalized_dir_path(path, ref, normalizedPath))
3162f5551ecSIngo Weinhold				return B_OK;
3172f5551ecSIngo Weinhold		}
3182f5551ecSIngo Weinhold
319f54626a7SIngo Weinhold		return error;
3202f5551ecSIngo Weinhold	}
321d9516a06SIngo Weinhold
322f54626a7SIngo Weinhold	// recurse to get the parent dir path, if found
323f54626a7SIngo Weinhold	error = normalize_dir_path(path, parentRef, normalizedPath);
324f54626a7SIngo Weinhold	if (error != 0)
325f54626a7SIngo Weinhold		return error;
326f54626a7SIngo Weinhold
327d9516a06SIngo Weinhold	// construct the normalizedPath
328f54626a7SIngo Weinhold	if (normalizedPath.length() > 1) // don't append "/", if parent is root
329f54626a7SIngo Weinhold		normalizedPath += '/';
330f54626a7SIngo Weinhold	normalizedPath += name;
331d9516a06SIngo Weinhold
332f54626a7SIngo Weinhold	return 0;
333f54626a7SIngo Weinhold}
334f54626a7SIngo Weinhold
335f54626a7SIngo Weinhold// normalize_dir_path
336f54626a7SIngo Weinholdstatic status_t
337f54626a7SIngo Weinholdnormalize_dir_path(const char *path, string &normalizedPath)
338f54626a7SIngo Weinhold{
339f54626a7SIngo Weinhold	// stat() the dir
340f54626a7SIngo Weinhold	struct stat st;
341f54626a7SIngo Weinhold	if (stat(path, &st) < 0)
342f54626a7SIngo Weinhold		return errno;
343d9516a06SIngo Weinhold
344f54626a7SIngo Weinhold	return normalize_dir_path(path, NodeRef(st), normalizedPath);
345f54626a7SIngo Weinhold}
346f54626a7SIngo Weinhold
347f54626a7SIngo Weinhold// normalize_entry_path
348f54626a7SIngo Weinholdstatic status_t
349f54626a7SIngo Weinholdnormalize_entry_path(const char *path, string &normalizedPath)
350f54626a7SIngo Weinhold{
351f54626a7SIngo Weinhold	const char *dirPath = NULL;
352f54626a7SIngo Weinhold	const char *leafName = NULL;
353d9516a06SIngo Weinhold
354f54626a7SIngo Weinhold	string dirPathString;
3550aab2cafSJérôme Duval	if (const char *lastSlash = strrchr(path, '/')) {
356f54626a7SIngo Weinhold		// found a slash: decompose into dir path and leaf name
357f54626a7SIngo Weinhold		leafName = lastSlash + 1;
358f54626a7SIngo Weinhold		if (leafName[0] == '\0') {
359f54626a7SIngo Weinhold			// slash is at the end: the whole path is a dir name
360f54626a7SIngo Weinhold			leafName = NULL;
361f54626a7SIngo Weinhold		} else {
362f54626a7SIngo Weinhold			dirPathString = string(path, leafName - path);
363f54626a7SIngo Weinhold			dirPath = dirPathString.c_str();
364f54626a7SIngo Weinhold		}
365f54626a7SIngo Weinhold
366f54626a7SIngo Weinhold	} else {
367f54626a7SIngo Weinhold		// path contains no slash, so it is a path relative to the current dir
368f54626a7SIngo Weinhold		dirPath = ".";
369f54626a7SIngo Weinhold		leafName = path;
370f54626a7SIngo Weinhold	}
371f54626a7SIngo Weinhold
372f54626a7SIngo Weinhold	// catch special case: no leaf, or leaf is a directory
373f54626a7SIngo Weinhold	if (!leafName || strcmp(leafName, ".") == 0 || strcmp(leafName, "..") == 0)
374f54626a7SIngo Weinhold		return normalize_dir_path(path, normalizedPath);
375d9516a06SIngo Weinhold
376f54626a7SIngo Weinhold	// normalize the dir path
377f54626a7SIngo Weinhold	status_t error = normalize_dir_path(dirPath, normalizedPath);
378f54626a7SIngo Weinhold	if (error != B_OK)
379f54626a7SIngo Weinhold		return error;
380f54626a7SIngo Weinhold
381f54626a7SIngo Weinhold	// append the leaf name
382f54626a7SIngo Weinhold	if (normalizedPath.length() > 1) // don't append "/", if parent is root
383f54626a7SIngo Weinhold		normalizedPath += '/';
384f54626a7SIngo Weinhold	normalizedPath += leafName;
385f54626a7SIngo Weinhold
386f54626a7SIngo Weinhold	return B_OK;
387f54626a7SIngo Weinhold}
388f54626a7SIngo Weinhold
389f54626a7SIngo Weinhold
390f54626a7SIngo Weinhold// #pragma mark -
391f54626a7SIngo Weinhold
392f54626a7SIngo Weinholdtypedef map<NodeRef, string> DirPathMap;
393f54626a7SIngo Weinholdstatic DirPathMap sDirPathMap;
394f54626a7SIngo Weinhold
395f54626a7SIngo Weinhold// get_path
396f54626a7SIngo Weinholdstatic status_t
397f54626a7SIngo Weinholdget_path(const NodeRef *ref, const char *name, string &path)
398f54626a7SIngo Weinhold{
399f54626a7SIngo Weinhold	if (!ref && !name)
400f54626a7SIngo Weinhold		return B_BAD_VALUE;
401f54626a7SIngo Weinhold
402f54626a7SIngo Weinhold	// no ref or absolute path
403f54626a7SIngo Weinhold	if (!ref || (name && name[0] == '/')) {
404f54626a7SIngo Weinhold		path = name;
405f54626a7SIngo Weinhold		return B_OK;
406f54626a7SIngo Weinhold	}
407f54626a7SIngo Weinhold
408f54626a7SIngo Weinhold	// get the dir path
409f54626a7SIngo Weinhold	if (ref) {
410f54626a7SIngo Weinhold		DirPathMap::iterator it = sDirPathMap.find(*ref);
411f54626a7SIngo Weinhold		if (it == sDirPathMap.end())
412f54626a7SIngo Weinhold			return B_ENTRY_NOT_FOUND;
413d9516a06SIngo Weinhold
414f54626a7SIngo Weinhold		path = it->second;
415f54626a7SIngo Weinhold
416f54626a7SIngo Weinhold		// stat the path to check, if it is still valid
417f54626a7SIngo Weinhold		struct stat st;
418f54626a7SIngo Weinhold		if (lstat(path.c_str(), &st) < 0) {
419f54626a7SIngo Weinhold			sDirPathMap.erase(it);
420f54626a7SIngo Weinhold			return errno;
421f54626a7SIngo Weinhold		}
422f54626a7SIngo Weinhold
423f54626a7SIngo Weinhold		// compare the NodeRef
424f54626a7SIngo Weinhold		if (NodeRef(st) != *ref) {
425f54626a7SIngo Weinhold			sDirPathMap.erase(it);
426f54626a7SIngo Weinhold			return B_ENTRY_NOT_FOUND;
427f54626a7SIngo Weinhold		}
428f54626a7SIngo Weinhold
429f54626a7SIngo Weinhold		// still a directory?
430f54626a7SIngo Weinhold		if (!S_ISDIR(st.st_mode)) {
431f54626a7SIngo Weinhold			sDirPathMap.erase(it);
432f54626a7SIngo Weinhold			return B_NOT_A_DIRECTORY;
433f54626a7SIngo Weinhold		}
434f54626a7SIngo Weinhold	}
435f54626a7SIngo Weinhold
436f54626a7SIngo Weinhold	// if there's a name, append it
437f54626a7SIngo Weinhold	if (name) {
438f54626a7SIngo Weinhold		path += '/';
439f54626a7SIngo Weinhold		path += name;
440f54626a7SIngo Weinhold	}
441d9516a06SIngo Weinhold
442f54626a7SIngo Weinhold	return B_OK;
443f54626a7SIngo Weinhold}
444f54626a7SIngo Weinhold
445f54626a7SIngo Weinhold// get_path
446f54626a7SIngo Weinholdstatus_t
447f54626a7SIngo WeinholdBPrivate::get_path(int fd, const char *name, string &path)
448f54626a7SIngo Weinhold{
449f54626a7SIngo Weinhold	// get the node ref for the fd, if any, and the path part is not absolute
450f54626a7SIngo Weinhold	if (fd >= 0 && !(name && name[0] == '/')) {
451f54626a7SIngo Weinhold		// get descriptor
452f54626a7SIngo Weinhold		Descriptor *descriptor = get_descriptor(fd);
453f54626a7SIngo Weinhold		if (!descriptor)
454f54626a7SIngo Weinhold			return B_FILE_ERROR;
455f54626a7SIngo Weinhold
456280b7cb6SIngo Weinhold		// Handle symlink descriptors here explicitly, so this function can be
457280b7cb6SIngo Weinhold		// used more flexibly.
458280b7cb6SIngo Weinhold		if (SymlinkDescriptor* symlinkDescriptor
459280b7cb6SIngo Weinhold				= dynamic_cast<SymlinkDescriptor*>(descriptor)) {
460280b7cb6SIngo Weinhold			path = symlinkDescriptor->path;
461280b7cb6SIngo Weinhold			if (name == NULL)
462280b7cb6SIngo Weinhold				return B_OK;
463280b7cb6SIngo Weinhold			path += '/';
464280b7cb6SIngo Weinhold			path += name;
465280b7cb6SIngo Weinhold			return B_OK;
466280b7cb6SIngo Weinhold		}
467280b7cb6SIngo Weinhold
468f54626a7SIngo Weinhold		// get node ref for the descriptor
469f54626a7SIngo Weinhold		NodeRef ref;
470f54626a7SIngo Weinhold		status_t error = descriptor->GetNodeRef(ref);
471f54626a7SIngo Weinhold		if (error != B_OK)
472f54626a7SIngo Weinhold			return error;
473f54626a7SIngo Weinhold
474f54626a7SIngo Weinhold		return ::get_path(&ref, name, path);
475d9516a06SIngo Weinhold
476f54626a7SIngo Weinhold	} else	// no descriptor or absolute path
477f54626a7SIngo Weinhold		return ::get_path((NodeRef*)NULL, name, path);
478f54626a7SIngo Weinhold}
479f54626a7SIngo Weinhold
480f54626a7SIngo Weinhold// get_path
481f54626a7SIngo Weinholdstatic status_t
482f54626a7SIngo Weinholdget_path(dev_t device, ino_t directory, const char *name, string &path)
483f54626a7SIngo Weinhold{
484f54626a7SIngo Weinhold	NodeRef ref;
485f54626a7SIngo Weinhold	ref.device = device;
486f54626a7SIngo Weinhold	ref.node = directory;
487d9516a06SIngo Weinhold
488f54626a7SIngo Weinhold	return get_path(&ref, name, path);
489f54626a7SIngo Weinhold}
490f54626a7SIngo Weinhold
491f54626a7SIngo Weinhold// add_dir_path
492f54626a7SIngo Weinholdstatic void
493f54626a7SIngo Weinholdadd_dir_path(const char *path, const NodeRef &ref)
494f54626a7SIngo Weinhold{
495f54626a7SIngo Weinhold	// add the normalized path
496f54626a7SIngo Weinhold	string normalizedPath;
497f54626a7SIngo Weinhold	if (normalize_dir_path(path, normalizedPath) == B_OK)
498f54626a7SIngo Weinhold		sDirPathMap[ref] = normalizedPath;
499f54626a7SIngo Weinhold}
500f54626a7SIngo Weinhold
501f54626a7SIngo Weinhold
502f54626a7SIngo Weinhold// #pragma mark -
503f54626a7SIngo Weinhold
504f54626a7SIngo Weinhold// _kern_entry_ref_to_path
505f54626a7SIngo Weinholdstatus_t
506f54626a7SIngo Weinhold_kern_entry_ref_to_path(dev_t device, ino_t node, const char *leaf,
507f54626a7SIngo Weinhold	char *userPath, size_t pathLength)
508f54626a7SIngo Weinhold{
509f54626a7SIngo Weinhold	// get the path
510f54626a7SIngo Weinhold	string path;
511f54626a7SIngo Weinhold	status_t error = get_path(device, node, leaf, path);
512f54626a7SIngo Weinhold	if (error != B_OK)
513f54626a7SIngo Weinhold		return error;
514f54626a7SIngo Weinhold
515f54626a7SIngo Weinhold	// copy it back to the user buffer
516f54626a7SIngo Weinhold	if (strlcpy(userPath, path.c_str(), pathLength) >= pathLength)
517f54626a7SIngo Weinhold		return B_BUFFER_OVERFLOW;
518d9516a06SIngo Weinhold
519f54626a7SIngo Weinhold	return B_OK;
520f54626a7SIngo Weinhold}
521f54626a7SIngo Weinhold
522f54626a7SIngo Weinhold
523f54626a7SIngo Weinhold// #pragma mark -
524f54626a7SIngo Weinhold
525f54626a7SIngo Weinhold// _kern_create_dir
526f54626a7SIngo Weinholdstatus_t
527f54626a7SIngo Weinhold_kern_create_dir(int fd, const char *path, int perms)
528f54626a7SIngo Weinhold{
529f54626a7SIngo Weinhold	// get a usable path
530f54626a7SIngo Weinhold	string realPath;
531f54626a7SIngo Weinhold	status_t error = get_path(fd, path, realPath);
532f54626a7SIngo Weinhold	if (error != B_OK)
533f54626a7SIngo Weinhold		return error;
534f54626a7SIngo Weinhold
535f54626a7SIngo Weinhold	// mkdir
536f54626a7SIngo Weinhold	if (mkdir(realPath.c_str(), perms) < 0)
537d9516a06SIngo Weinhold		return errno;
538d9516a06SIngo Weinhold
539f54626a7SIngo Weinhold	return B_OK;
540f54626a7SIngo Weinhold}
541f54626a7SIngo Weinhold
542f54626a7SIngo Weinhold// _kern_create_dir_entry_ref
543f54626a7SIngo Weinholdstatus_t
544f54626a7SIngo Weinhold_kern_create_dir_entry_ref(dev_t device, ino_t node, const char *name,
545f54626a7SIngo Weinhold	int perms)
546f54626a7SIngo Weinhold{
547f54626a7SIngo Weinhold	// get a usable path
548f54626a7SIngo Weinhold	string realPath;
549f54626a7SIngo Weinhold	status_t error = get_path(device, node, name, realPath);
550f54626a7SIngo Weinhold	if (error != B_OK)
551f54626a7SIngo Weinhold		return error;
552f54626a7SIngo Weinhold
553f54626a7SIngo Weinhold	// mkdir
554f54626a7SIngo Weinhold	if (mkdir(realPath.c_str(), perms) < 0)
555d9516a06SIngo Weinhold		return errno;
556d9516a06SIngo Weinhold
557f54626a7SIngo Weinhold	return B_OK;
558f54626a7SIngo Weinhold}
559f54626a7SIngo Weinhold
560f54626a7SIngo Weinhold// open_dir
561f54626a7SIngo Weinholdstatic int
562f54626a7SIngo Weinholdopen_dir(const char *path)
563f54626a7SIngo Weinhold{
564f54626a7SIngo Weinhold	// open the dir
565f54626a7SIngo Weinhold	DIR *dir = opendir(path);
566f54626a7SIngo Weinhold	if (!dir)
567f54626a7SIngo Weinhold		return errno;
568f54626a7SIngo Weinhold
569f54626a7SIngo Weinhold	// stat the entry
570f54626a7SIngo Weinhold	struct stat st;
571f54626a7SIngo Weinhold	if (stat(path, &st) < 0) {
572f54626a7SIngo Weinhold		closedir(dir);
573f54626a7SIngo Weinhold		return errno;
574f54626a7SIngo Weinhold	}
575f54626a7SIngo Weinhold
576f54626a7SIngo Weinhold	if (!S_ISDIR(st.st_mode)) {
577f54626a7SIngo Weinhold		closedir(dir);
578f54626a7SIngo Weinhold		return B_NOT_A_DIRECTORY;
579f54626a7SIngo Weinhold	}
580f54626a7SIngo Weinhold
581f54626a7SIngo Weinhold	// cache dir path
582f54626a7SIngo Weinhold	NodeRef ref(st);
583f54626a7SIngo Weinhold	add_dir_path(path, ref);
584f54626a7SIngo Weinhold
585d9516a06SIngo Weinhold	// create descriptor
586f54626a7SIngo Weinhold	DirectoryDescriptor *descriptor = new DirectoryDescriptor(dir, ref);
587f54626a7SIngo Weinhold	return add_descriptor(descriptor);
588f54626a7SIngo Weinhold}
589f54626a7SIngo Weinhold
590f54626a7SIngo Weinhold// _kern_open_dir
591f54626a7SIngo Weinholdint
592f54626a7SIngo Weinhold_kern_open_dir(int fd, const char *path)
593f54626a7SIngo Weinhold{
594f54626a7SIngo Weinhold	// get a usable path
595f54626a7SIngo Weinhold	string realPath;
596f54626a7SIngo Weinhold	status_t error = get_path(fd, path, realPath);
597f54626a7SIngo Weinhold	if (error != B_OK)
598f54626a7SIngo Weinhold		return error;
599f54626a7SIngo Weinhold
600f54626a7SIngo Weinhold	return open_dir(realPath.c_str());
601f54626a7SIngo Weinhold}
602f54626a7SIngo Weinhold
603f54626a7SIngo Weinhold// _kern_open_dir_entry_ref
604f54626a7SIngo Weinholdint
605f54626a7SIngo Weinhold_kern_open_dir_entry_ref(dev_t device, ino_t node, const char *name)
606f54626a7SIngo Weinhold{
607f54626a7SIngo Weinhold	// get a usable path
608f54626a7SIngo Weinhold	string realPath;
609f54626a7SIngo Weinhold	status_t error = get_path(device, node, name, realPath);
610f54626a7SIngo Weinhold	if (error != B_OK)
611f54626a7SIngo Weinhold		return error;
612f54626a7SIngo Weinhold
613f54626a7SIngo Weinhold	return open_dir(realPath.c_str());
614f54626a7SIngo Weinhold}
615f54626a7SIngo Weinhold
616f54626a7SIngo Weinhold// _kern_open_parent_dir
617f54626a7SIngo Weinholdint
618f54626a7SIngo Weinhold_kern_open_parent_dir(int fd, char *name, size_t nameLength)
619f54626a7SIngo Weinhold{
620f54626a7SIngo Weinhold	// get a usable path
621f54626a7SIngo Weinhold	string realPath;
622b962e484SMichael Lotz	status_t error = get_path(fd, NULL, realPath);
623f54626a7SIngo Weinhold	if (error != B_OK)
624f54626a7SIngo Weinhold		return error;
625f54626a7SIngo Weinhold
626f54626a7SIngo Weinhold	// stat the entry
627f54626a7SIngo Weinhold	struct stat st;
628f54626a7SIngo Weinhold	if (stat(realPath.c_str(), &st) < 0)
629f54626a7SIngo Weinhold		return errno;
630f54626a7SIngo Weinhold
631f54626a7SIngo Weinhold	if (!S_ISDIR(st.st_mode))
632f54626a7SIngo Weinhold		return B_NOT_A_DIRECTORY;
633f54626a7SIngo Weinhold
634f54626a7SIngo Weinhold	// get the entry name
635f54626a7SIngo Weinhold	realPath += "/..";
636f54626a7SIngo Weinhold	string entryName;
637f54626a7SIngo Weinhold	error = find_dir_entry(realPath.c_str(), NodeRef(st),
638f54626a7SIngo Weinhold		entryName, false);
639f54626a7SIngo Weinhold	if (error != B_OK)
640f54626a7SIngo Weinhold		return error;
641f54626a7SIngo Weinhold
642f54626a7SIngo Weinhold	if (strlcpy(name, entryName.c_str(), nameLength) >= nameLength)
643f54626a7SIngo Weinhold		return B_BUFFER_OVERFLOW;
644f54626a7SIngo Weinhold
645f54626a7SIngo Weinhold	// open the parent directory
646d9516a06SIngo Weinhold
647f54626a7SIngo Weinhold	return open_dir(realPath.c_str());
648f54626a7SIngo Weinhold}
649f54626a7SIngo Weinhold
650f54626a7SIngo Weinhold// _kern_read_dir
651f54626a7SIngo Weinholdssize_t
652f54626a7SIngo Weinhold_kern_read_dir(int fd, struct dirent *buffer, size_t bufferSize,
653f54626a7SIngo Weinhold	uint32 maxCount)
654f54626a7SIngo Weinhold{
655f54626a7SIngo Weinhold	if (maxCount <= 0)
656f54626a7SIngo Weinhold		return B_BAD_VALUE;
657f54626a7SIngo Weinhold
658d9516a06SIngo Weinhold	// get the descriptor
659f54626a7SIngo Weinhold	DirectoryDescriptor *descriptor
660f54626a7SIngo Weinhold		= dynamic_cast<DirectoryDescriptor*>(get_descriptor(fd));
661f54626a7SIngo Weinhold	if (!descriptor)
662f54626a7SIngo Weinhold		return B_FILE_ERROR;
663f54626a7SIngo Weinhold
664f54626a7SIngo Weinhold	// get the next entry
665f54626a7SIngo Weinhold	dirent *entry;
66675c10de2SIngo Weinhold	errno = 0;
667f54626a7SIngo Weinhold	if (dynamic_cast<AttrDirDescriptor*>(descriptor))
668f54626a7SIngo Weinhold		entry = fs_read_attr_dir(descriptor->dir);
669f54626a7SIngo Weinhold	else
670f54626a7SIngo Weinhold		entry = readdir(descriptor->dir);
671f54626a7SIngo Weinhold	if (!entry)
672f54626a7SIngo Weinhold		return errno;
673f54626a7SIngo Weinhold
674f54626a7SIngo Weinhold	// copy the entry
675f54626a7SIngo Weinhold	int entryLen = &entry->d_name[strlen(entry->d_name) + 1] - (char*)entry;
676f54626a7SIngo Weinhold	if (entryLen > (int)bufferSize)
677f54626a7SIngo Weinhold		return B_BUFFER_OVERFLOW;
678f54626a7SIngo Weinhold
679f54626a7SIngo Weinhold	memcpy(buffer, entry, entryLen);
680f54626a7SIngo Weinhold
681f54626a7SIngo Weinhold	return 1;
682f54626a7SIngo Weinhold}
683f54626a7SIngo Weinhold
684f54626a7SIngo Weinhold// _kern_rewind_dir
685f54626a7SIngo Weinholdstatus_t
686f54626a7SIngo Weinhold_kern_rewind_dir(int fd)
687f54626a7SIngo Weinhold{
688d9516a06SIngo Weinhold	// get the descriptor
689f54626a7SIngo Weinhold	DirectoryDescriptor *descriptor
690f54626a7SIngo Weinhold		= dynamic_cast<DirectoryDescriptor*>(get_descriptor(fd));
691f54626a7SIngo Weinhold	if (!descriptor)
692f54626a7SIngo Weinhold		return B_FILE_ERROR;
693f54626a7SIngo Weinhold
694f54626a7SIngo Weinhold	// rewind
695f54626a7SIngo Weinhold	if (dynamic_cast<AttrDirDescriptor*>(descriptor))
696f54626a7SIngo Weinhold		fs_rewind_attr_dir(descriptor->dir);
697f54626a7SIngo Weinhold	else
698f54626a7SIngo Weinhold		rewinddir(descriptor->dir);
699f54626a7SIngo Weinhold
700f54626a7SIngo Weinhold	return B_OK;
701f54626a7SIngo Weinhold}
702f54626a7SIngo Weinhold
703f54626a7SIngo Weinhold
704f54626a7SIngo Weinhold// #pragma mark -
705f54626a7SIngo Weinhold
706f54626a7SIngo Weinhold// open_file
707f54626a7SIngo Weinholdstatic int
708f54626a7SIngo Weinholdopen_file(const char *path, int openMode, int perms)
709f54626a7SIngo Weinhold{
710f54626a7SIngo Weinhold	// stat the node
711f54626a7SIngo Weinhold	bool exists = true;
712f54626a7SIngo Weinhold	struct stat st;
713f54626a7SIngo Weinhold	if (lstat(path, &st) < 0) {
714f54626a7SIngo Weinhold		exists = false;
715f54626a7SIngo Weinhold		if (!(openMode & O_CREAT))
716f54626a7SIngo Weinhold			return errno;
717f54626a7SIngo Weinhold	}
718f54626a7SIngo Weinhold
719f54626a7SIngo Weinhold	Descriptor *descriptor;
720880de450SAxel Dörfler	if (exists && S_ISLNK(st.st_mode) && (openMode & O_NOTRAVERSE) != 0) {
721f54626a7SIngo Weinhold		// a symlink not to be followed: create a special descriptor
722f54626a7SIngo Weinhold		// normalize path first
723f54626a7SIngo Weinhold		string normalizedPath;
724f54626a7SIngo Weinhold		status_t error = normalize_entry_path(path, normalizedPath);
725f54626a7SIngo Weinhold		if (error != B_OK)
726f54626a7SIngo Weinhold			return error;
727d9516a06SIngo Weinhold
728f54626a7SIngo Weinhold		descriptor = new SymlinkDescriptor(normalizedPath.c_str());
729f54626a7SIngo Weinhold	} else {
730f54626a7SIngo Weinhold		// open the file
731f54626a7SIngo Weinhold		openMode &= ~O_NOTRAVERSE;
732f54626a7SIngo Weinhold		int newFD = open(path, openMode, perms);
733f54626a7SIngo Weinhold		if (newFD < 0)
734f54626a7SIngo Weinhold			return errno;
735f54626a7SIngo Weinhold
736f54626a7SIngo Weinhold		descriptor = new FileDescriptor(newFD);
737f54626a7SIngo Weinhold	}
738d9516a06SIngo Weinhold
739f54626a7SIngo Weinhold	// cache path, if this is a directory
740f54626a7SIngo Weinhold	if (exists && S_ISDIR(st.st_mode))
741f54626a7SIngo Weinhold		add_dir_path(path, NodeRef(st));
742d9516a06SIngo Weinhold
743f54626a7SIngo Weinhold	return add_descriptor(descriptor);
744f54626a7SIngo Weinhold}
745f54626a7SIngo Weinhold
746f54626a7SIngo Weinhold// _kern_open
747f54626a7SIngo Weinholdint
748f54626a7SIngo Weinhold_kern_open(int fd, const char *path, int openMode, int perms)
749f54626a7SIngo Weinhold{
750f54626a7SIngo Weinhold	// get a usable path
751f54626a7SIngo Weinhold	string realPath;
752f54626a7SIngo Weinhold	status_t error = get_path(fd, path, realPath);
753f54626a7SIngo Weinhold	if (error != B_OK)
754f54626a7SIngo Weinhold		return error;
755f54626a7SIngo Weinhold
756f54626a7SIngo Weinhold	return open_file(realPath.c_str(), openMode, perms);
757f54626a7SIngo Weinhold}
758f54626a7SIngo Weinhold
759f54626a7SIngo Weinhold// _kern_open_entry_ref
760f54626a7SIngo Weinholdint
761f54626a7SIngo Weinhold_kern_open_entry_ref(dev_t device, ino_t node, const char *name,
762f54626a7SIngo Weinhold	int openMode, int perms)
763f54626a7SIngo Weinhold{
764f54626a7SIngo Weinhold	// get a usable path
765f54626a7SIngo Weinhold	string realPath;
766f54626a7SIngo Weinhold	status_t error = get_path(device, node, name, realPath);
767f54626a7SIngo Weinhold	if (error != B_OK)
768f54626a7SIngo Weinhold		return error;
769f54626a7SIngo Weinhold
770f54626a7SIngo Weinhold	return open_file(realPath.c_str(), openMode, perms);
771f54626a7SIngo Weinhold}
772f54626a7SIngo Weinhold
773f54626a7SIngo Weinhold// _kern_seek
774f54626a7SIngo Weinholdoff_t
775f54626a7SIngo Weinhold_kern_seek(int fd, off_t pos, int seekType)
776f54626a7SIngo Weinhold{
777f54626a7SIngo Weinhold	// get the descriptor
778f54626a7SIngo Weinhold	FileDescriptor *descriptor
779f54626a7SIngo Weinhold		= dynamic_cast<FileDescriptor*>(get_descriptor(fd));
780f54626a7SIngo Weinhold	if (!descriptor)
781f54626a7SIngo Weinhold		return B_FILE_ERROR;
782f54626a7SIngo Weinhold
783f54626a7SIngo Weinhold	// seek
784f54626a7SIngo Weinhold	off_t result = lseek(descriptor->fd, pos, seekType);
785f54626a7SIngo Weinhold	if (result < 0)
786f54626a7SIngo Weinhold		return errno;
787f54626a7SIngo Weinhold
788f54626a7SIngo Weinhold	return result;
789f54626a7SIngo Weinhold}
790f54626a7SIngo Weinhold
791f54626a7SIngo Weinhold// _kern_read
792f54626a7SIngo Weinholdssize_t
793f54626a7SIngo Weinhold_kern_read(int fd, off_t pos, void *buffer, size_t bufferSize)
794f54626a7SIngo Weinhold{
795f54626a7SIngo Weinhold	// get the descriptor
796f54626a7SIngo Weinhold	FileDescriptor *descriptor
797f54626a7SIngo Weinhold		= dynamic_cast<FileDescriptor*>(get_descriptor(fd));
798f54626a7SIngo Weinhold	if (!descriptor)
799f54626a7SIngo Weinhold		return B_FILE_ERROR;
800f54626a7SIngo Weinhold
801f54626a7SIngo Weinhold	// seek
802f54626a7SIngo Weinhold	if (pos != -1) {
803f54626a7SIngo Weinhold		off_t result = lseek(descriptor->fd, pos, SEEK_SET);
804f54626a7SIngo Weinhold		if (result < 0)
805f54626a7SIngo Weinhold			return errno;
806f54626a7SIngo Weinhold	}
807d9516a06SIngo Weinhold
808f54626a7SIngo Weinhold	// read
80980b2da5eSIngo Weinhold	ssize_t bytesRead = haiku_host_platform_read(descriptor->fd, buffer,
81080b2da5eSIngo Weinhold		bufferSize);
811f54626a7SIngo Weinhold	if (bytesRead < 0)
812f54626a7SIngo Weinhold		return errno;
813f54626a7SIngo Weinhold
814f54626a7SIngo Weinhold	return bytesRead;
815f54626a7SIngo Weinhold}
816f54626a7SIngo Weinhold
817f54626a7SIngo Weinhold// _kern_write
818f54626a7SIngo Weinholdssize_t
819f54626a7SIngo Weinhold_kern_write(int fd, off_t pos, const void *buffer, size_t bufferSize)
820f54626a7SIngo Weinhold{
821f54626a7SIngo Weinhold	// get the descriptor
822f54626a7SIngo Weinhold	FileDescriptor *descriptor
823f54626a7SIngo Weinhold		= dynamic_cast<FileDescriptor*>(get_descriptor(fd));
824f54626a7SIngo Weinhold	if (!descriptor)
825f54626a7SIngo Weinhold		return B_FILE_ERROR;
826f54626a7SIngo Weinhold
827f54626a7SIngo Weinhold	// seek
828f54626a7SIngo Weinhold	if (pos != -1) {
829f54626a7SIngo Weinhold		off_t result = lseek(descriptor->fd, pos, SEEK_SET);
830f54626a7SIngo Weinhold		if (result < 0)
831f54626a7SIngo Weinhold			return errno;
832f54626a7SIngo Weinhold	}
833d9516a06SIngo Weinhold
834f54626a7SIngo Weinhold	// read
83580b2da5eSIngo Weinhold	ssize_t bytesWritten = haiku_host_platform_write(descriptor->fd, buffer,
83680b2da5eSIngo Weinhold		bufferSize);
837f54626a7SIngo Weinhold	if (bytesWritten < 0)
838f54626a7SIngo Weinhold		return errno;
839f54626a7SIngo Weinhold
840f54626a7SIngo Weinhold	return bytesWritten;
841f54626a7SIngo Weinhold}
842f54626a7SIngo Weinhold
843f54626a7SIngo Weinhold// _kern_close
844f54626a7SIngo Weinholdstatus_t
845f54626a7SIngo Weinhold_kern_close(int fd)
846f54626a7SIngo Weinhold{
847f54626a7SIngo Weinhold	return delete_descriptor(fd);
848f54626a7SIngo Weinhold}
849f54626a7SIngo Weinhold
850f54626a7SIngo Weinhold// _kern_dup
851f54626a7SIngo Weinholdint
852f54626a7SIngo Weinhold_kern_dup(int fd)
853f54626a7SIngo Weinhold{
854f54626a7SIngo Weinhold	// get the descriptor
855f54626a7SIngo Weinhold	Descriptor *descriptor = get_descriptor(fd);
856f54626a7SIngo Weinhold	if (!descriptor)
857f54626a7SIngo Weinhold		return B_FILE_ERROR;
858f54626a7SIngo Weinhold
859f54626a7SIngo Weinhold	// clone it
860f54626a7SIngo Weinhold	Descriptor *clone;
861f54626a7SIngo Weinhold	status_t error = descriptor->Dup(clone);
862f54626a7SIngo Weinhold	if (error != B_OK)
863f54626a7SIngo Weinhold		return error;
864f54626a7SIngo Weinhold
865f54626a7SIngo Weinhold	return add_descriptor(clone);
866f54626a7SIngo Weinhold}
867f54626a7SIngo Weinhold
868f54626a7SIngo Weinhold// _kern_fsync
869f54626a7SIngo Weinholdstatus_t
870f54626a7SIngo Weinhold_kern_fsync(int fd)
871f54626a7SIngo Weinhold{
872f54626a7SIngo Weinhold	// get the descriptor
873f54626a7SIngo Weinhold	FileDescriptor *descriptor
874f54626a7SIngo Weinhold		= dynamic_cast<FileDescriptor*>(get_descriptor(fd));
875f54626a7SIngo Weinhold	if (!descriptor)
876f54626a7SIngo Weinhold		return B_FILE_ERROR;
877f54626a7SIngo Weinhold
878f54626a7SIngo Weinhold	// sync
879f54626a7SIngo Weinhold	if (fsync(descriptor->fd) < 0)
880f54626a7SIngo Weinhold		return errno;
881f54626a7SIngo Weinhold
882f54626a7SIngo Weinhold	return B_OK;
883f54626a7SIngo Weinhold}
884f54626a7SIngo Weinhold
885f54626a7SIngo Weinhold// _kern_read_stat
886f54626a7SIngo Weinholdstatus_t
887f54626a7SIngo Weinhold_kern_read_stat(int fd, const char *path, bool traverseLink,
888f54626a7SIngo Weinhold	struct stat *st, size_t statSize)
889f54626a7SIngo Weinhold{
890f54626a7SIngo Weinhold	if (path) {
891f54626a7SIngo Weinhold		// get a usable path
892f54626a7SIngo Weinhold		string realPath;
893f54626a7SIngo Weinhold		status_t error = get_path(fd, path, realPath);
894f54626a7SIngo Weinhold		if (error != B_OK)
895f54626a7SIngo Weinhold			return error;
896f54626a7SIngo Weinhold
897f54626a7SIngo Weinhold		// stat
898f54626a7SIngo Weinhold		int result;
899f54626a7SIngo Weinhold		if (traverseLink)
900f54626a7SIngo Weinhold			result = stat(realPath.c_str(), st);
901f54626a7SIngo Weinhold		else
902f54626a7SIngo Weinhold			result = lstat(realPath.c_str(), st);
903f54626a7SIngo Weinhold
904f54626a7SIngo Weinhold		if (result < 0)
905f54626a7SIngo Weinhold			return errno;
906f54626a7SIngo Weinhold	} else {
907f54626a7SIngo Weinhold		Descriptor *descriptor = get_descriptor(fd);
908f54626a7SIngo Weinhold		if (!descriptor)
909f54626a7SIngo Weinhold			return B_FILE_ERROR;
910d9516a06SIngo Weinhold
911f54626a7SIngo Weinhold		return descriptor->GetStat(traverseLink, st);
912f54626a7SIngo Weinhold	}
913d9516a06SIngo Weinhold
914f54626a7SIngo Weinhold	return B_OK;
915f54626a7SIngo Weinhold}
916f54626a7SIngo Weinhold
917f54626a7SIngo Weinhold// _kern_write_stat
918f54626a7SIngo Weinholdstatus_t
919f54626a7SIngo Weinhold_kern_write_stat(int fd, const char *path, bool traverseLink,
920f54626a7SIngo Weinhold	const struct stat *st, size_t statSize, int statMask)
921f54626a7SIngo Weinhold{
922f54626a7SIngo Weinhold	// get a usable path
923f54626a7SIngo Weinhold	int realFD = -1;
924f54626a7SIngo Weinhold	string realPath;
925f54626a7SIngo Weinhold	status_t error;
926f54626a7SIngo Weinhold	bool isSymlink = false;
927f54626a7SIngo Weinhold	if (path) {
928f54626a7SIngo Weinhold		error = get_path(fd, path, realPath);
929f54626a7SIngo Weinhold		if (error != B_OK)
930f54626a7SIngo Weinhold			return error;
931f54626a7SIngo Weinhold
932f54626a7SIngo Weinhold		// stat it to see, if it is a symlink
933f54626a7SIngo Weinhold		struct stat tmpStat;
934f54626a7SIngo Weinhold		if (lstat(realPath.c_str(), &tmpStat) < 0)
935f54626a7SIngo Weinhold			return errno;
936f54626a7SIngo Weinhold
937f54626a7SIngo Weinhold		isSymlink = S_ISLNK(tmpStat.st_mode);
938d9516a06SIngo Weinhold
939f54626a7SIngo Weinhold	} else {
940f54626a7SIngo Weinhold		Descriptor *descriptor = get_descriptor(fd);
941f54626a7SIngo Weinhold		if (!descriptor)
942f54626a7SIngo Weinhold			return B_FILE_ERROR;
943f54626a7SIngo Weinhold
944f54626a7SIngo Weinhold		if (FileDescriptor *fileFD
945f54626a7SIngo Weinhold				= dynamic_cast<FileDescriptor*>(descriptor)) {
946f54626a7SIngo Weinhold			realFD = fileFD->fd;
947d9516a06SIngo Weinhold
948f54626a7SIngo Weinhold		} else if (dynamic_cast<DirectoryDescriptor*>(descriptor)) {
949f54626a7SIngo Weinhold			error = get_path(fd, NULL, realPath);
950f54626a7SIngo Weinhold			if (error != B_OK)
951f54626a7SIngo Weinhold				return error;
952d9516a06SIngo Weinhold
953f54626a7SIngo Weinhold		} else if (SymlinkDescriptor *linkFD
954f54626a7SIngo Weinhold				= dynamic_cast<SymlinkDescriptor*>(descriptor)) {
955f54626a7SIngo Weinhold			realPath = linkFD->path;
956f54626a7SIngo Weinhold			isSymlink = true;
957d9516a06SIngo Weinhold
958f54626a7SIngo Weinhold		} else
959f54626a7SIngo Weinhold			return B_FILE_ERROR;
960f54626a7SIngo Weinhold	}
961f54626a7SIngo Weinhold
962f54626a7SIngo Weinhold	// We're screwed, if the node to manipulate is a symlink. All the
963f54626a7SIngo Weinhold	// available functions traverse symlinks.
964f54626a7SIngo Weinhold	if (isSymlink && !traverseLink)
965f54626a7SIngo Weinhold		return B_ERROR;
966d9516a06SIngo Weinhold
967f54626a7SIngo Weinhold	if (realFD >= 0) {
968f54626a7SIngo Weinhold		if (statMask & B_STAT_MODE) {
969f54626a7SIngo Weinhold			if (fchmod(realFD, st->st_mode) < 0)
970f54626a7SIngo Weinhold				return errno;
971f54626a7SIngo Weinhold		}
972d9516a06SIngo Weinhold
973f54626a7SIngo Weinhold		if (statMask & B_STAT_UID) {
974f54626a7SIngo Weinhold			if (fchown(realFD, st->st_uid, (gid_t)-1) < 0)
975f54626a7SIngo Weinhold				return errno;
976f54626a7SIngo Weinhold		}
977d9516a06SIngo Weinhold
978f54626a7SIngo Weinhold		if (statMask & B_STAT_GID) {
979f54626a7SIngo Weinhold			if (fchown(realFD, (uid_t)-1, st->st_gid) < 0)
980f54626a7SIngo Weinhold				return errno;
981f54626a7SIngo Weinhold		}
982d9516a06SIngo Weinhold
983f54626a7SIngo Weinhold		if (statMask & B_STAT_SIZE) {
984f54626a7SIngo Weinhold			if (ftruncate(realFD, st->st_size) < 0)
985f54626a7SIngo Weinhold				return errno;
986f54626a7SIngo Weinhold		}
987f54626a7SIngo Weinhold
988f54626a7SIngo Weinhold		// The timestamps can only be set via utime(), but that requires a
989f54626a7SIngo Weinhold		// path we don't have.
990f54626a7SIngo Weinhold		if (statMask & (B_STAT_ACCESS_TIME | B_STAT_MODIFICATION_TIME
991f54626a7SIngo Weinhold				| B_STAT_CREATION_TIME | B_STAT_CHANGE_TIME)) {
992f54626a7SIngo Weinhold			return B_ERROR;
993f54626a7SIngo Weinhold		}
994d9516a06SIngo Weinhold
995f54626a7SIngo Weinhold		return 0;
996d9516a06SIngo Weinhold
997f54626a7SIngo Weinhold	} else {
998f54626a7SIngo Weinhold		if (statMask & B_STAT_MODE) {
999f54626a7SIngo Weinhold			if (chmod(realPath.c_str(), st->st_mode) < 0)
1000f54626a7SIngo Weinhold				return errno;
1001f54626a7SIngo Weinhold		}
1002d9516a06SIngo Weinhold
1003f54626a7SIngo Weinhold		if (statMask & B_STAT_UID) {
1004f54626a7SIngo Weinhold			if (chown(realPath.c_str(), st->st_uid, (gid_t)-1) < 0)
1005f54626a7SIngo Weinhold				return errno;
1006f54626a7SIngo Weinhold		}
1007d9516a06SIngo Weinhold
1008f54626a7SIngo Weinhold		if (statMask & B_STAT_GID) {
1009f54626a7SIngo Weinhold			if (chown(realPath.c_str(), (uid_t)-1, st->st_gid) < 0)
1010f54626a7SIngo Weinhold				return errno;
1011f54626a7SIngo Weinhold		}
1012d9516a06SIngo Weinhold
1013f54626a7SIngo Weinhold		if (statMask & B_STAT_SIZE) {
1014f54626a7SIngo Weinhold			if (truncate(realPath.c_str(), st->st_size) < 0)
1015f54626a7SIngo Weinhold				return errno;
1016f54626a7SIngo Weinhold		}
1017f54626a7SIngo Weinhold
1018f54626a7SIngo Weinhold		if (statMask & (B_STAT_ACCESS_TIME | B_STAT_MODIFICATION_TIME)) {
1019f54626a7SIngo Weinhold