From f54626a7ae5cfac264ef37722ab2c4767e5b3953 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Tue, 5 Feb 2008 19:40:26 +0000 Subject: [PATCH] Converted to UNIX line breaks. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@23878 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/build/libroot/fs.cpp | 1998 +++++++++++++++++++------------------- 1 file changed, 999 insertions(+), 999 deletions(-) diff --git a/src/build/libroot/fs.cpp b/src/build/libroot/fs.cpp index 7622785034..713dae83f8 100644 --- a/src/build/libroot/fs.cpp +++ b/src/build/libroot/fs.cpp @@ -1,999 +1,999 @@ - -#include - -#include "fs_impl.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include // for B_STAT_* flags -#include - -#include "fs_descriptors.h" -#include "NodeRef.h" - -using namespace std; -using namespace BPrivate; - - -static status_t get_path(dev_t device, ino_t node, const char *name, - string &path); - - -// find_dir_entry -static status_t -find_dir_entry(DIR *dir, const char *path, NodeRef ref, string &name, - bool skipDot) -{ - // find the entry - bool found = false; - while (dirent *entry = readdir(dir)) { - if ((!skipDot && strcmp(entry->d_name, ".") == 0) - || strcmp(entry->d_name, "..") == 0) { - // skip "." and ".." - } else /*if (entry->d_ino == ref.node)*/ { - // Note: Linux doesn't seem to translate dirent::d_ino of - // mount points. Thus we always have to lstat(). - // We also need to compare the device, which is generally not - // included in the dirent structure. Hence we lstat(). - string entryPath(path); - entryPath += '/'; - entryPath += entry->d_name; - struct stat st; - if (lstat(entryPath.c_str(), &st) == 0) { - if (NodeRef(st) == ref) { - name = entry->d_name; - found = true; - break; - } - } - } - } - - if (!found) - return B_ENTRY_NOT_FOUND; - - return B_OK; -} - -// find_dir_entry -static status_t -find_dir_entry(const char *path, NodeRef ref, string &name, bool skipDot) -{ - // open dir - DIR *dir = opendir(path); - if (!dir) - return errno; - - status_t error = find_dir_entry(dir, path, ref, name, skipDot); - - // close dir - closedir(dir); - - return error; -} - -// normalize_dir_path -static status_t -normalize_dir_path(string path, NodeRef ref, string &normalizedPath) -{ - // get parent path - path += "/.."; - - // stat the parent dir - struct stat st; - if (lstat(path.c_str(), &st) < 0) - return errno; - - // root dir? - NodeRef parentRef(st); - if (parentRef == ref) { - normalizedPath = "/"; - return 0; - } - - // find the entry - string name; - status_t error = find_dir_entry(path.c_str(), ref, name, true) ; - if (error != B_OK) - return error; - - // recurse to get the parent dir path, if found - error = normalize_dir_path(path, parentRef, normalizedPath); - if (error != 0) - return error; - - // construct the normalizedPath - if (normalizedPath.length() > 1) // don't append "/", if parent is root - normalizedPath += '/'; - normalizedPath += name; - - return 0; -} - -// normalize_dir_path -static status_t -normalize_dir_path(const char *path, string &normalizedPath) -{ - // stat() the dir - struct stat st; - if (stat(path, &st) < 0) - return errno; - - return normalize_dir_path(path, NodeRef(st), normalizedPath); -} - -// normalize_entry_path -static status_t -normalize_entry_path(const char *path, string &normalizedPath) -{ - const char *dirPath = NULL; - const char *leafName = NULL; - - string dirPathString; - if (char *lastSlash = strrchr(path, '/')) { - // found a slash: decompose into dir path and leaf name - leafName = lastSlash + 1; - if (leafName[0] == '\0') { - // slash is at the end: the whole path is a dir name - leafName = NULL; - } else { - dirPathString = string(path, leafName - path); - dirPath = dirPathString.c_str(); - } - - } else { - // path contains no slash, so it is a path relative to the current dir - dirPath = "."; - leafName = path; - } - - // catch special case: no leaf, or leaf is a directory - if (!leafName || strcmp(leafName, ".") == 0 || strcmp(leafName, "..") == 0) - return normalize_dir_path(path, normalizedPath); - - // normalize the dir path - status_t error = normalize_dir_path(dirPath, normalizedPath); - if (error != B_OK) - return error; - - // append the leaf name - if (normalizedPath.length() > 1) // don't append "/", if parent is root - normalizedPath += '/'; - normalizedPath += leafName; - - return B_OK; -} - - -// #pragma mark - - -typedef map DirPathMap; -static DirPathMap sDirPathMap; - -// get_path -static status_t -get_path(const NodeRef *ref, const char *name, string &path) -{ - if (!ref && !name) - return B_BAD_VALUE; - - // no ref or absolute path - if (!ref || (name && name[0] == '/')) { - path = name; - return B_OK; - } - - // get the dir path - if (ref) { - DirPathMap::iterator it = sDirPathMap.find(*ref); - if (it == sDirPathMap.end()) - return B_ENTRY_NOT_FOUND; - - path = it->second; - - // stat the path to check, if it is still valid - struct stat st; - if (lstat(path.c_str(), &st) < 0) { - sDirPathMap.erase(it); - return errno; - } - - // compare the NodeRef - if (NodeRef(st) != *ref) { - sDirPathMap.erase(it); - return B_ENTRY_NOT_FOUND; - } - - // still a directory? - if (!S_ISDIR(st.st_mode)) { - sDirPathMap.erase(it); - return B_NOT_A_DIRECTORY; - } - } - - // if there's a name, append it - if (name) { - path += '/'; - path += name; - } - - return B_OK; -} - -// get_path -status_t -BPrivate::get_path(int fd, const char *name, string &path) -{ - // get the node ref for the fd, if any, and the path part is not absolute - if (fd >= 0 && !(name && name[0] == '/')) { - // get descriptor - Descriptor *descriptor = get_descriptor(fd); - if (!descriptor) - return B_FILE_ERROR; - - // get node ref for the descriptor - NodeRef ref; - status_t error = descriptor->GetNodeRef(ref); - if (error != B_OK) - return error; - - return ::get_path(&ref, name, path); - - } else // no descriptor or absolute path - return ::get_path((NodeRef*)NULL, name, path); -} - -// get_path -static status_t -get_path(dev_t device, ino_t directory, const char *name, string &path) -{ - NodeRef ref; - ref.device = device; - ref.node = directory; - - return get_path(&ref, name, path); -} - -// add_dir_path -static void -add_dir_path(const char *path, const NodeRef &ref) -{ - // add the normalized path - string normalizedPath; - if (normalize_dir_path(path, normalizedPath) == B_OK) - sDirPathMap[ref] = normalizedPath; -} - - -// #pragma mark - - -// _kern_entry_ref_to_path -status_t -_kern_entry_ref_to_path(dev_t device, ino_t node, const char *leaf, - char *userPath, size_t pathLength) -{ - // get the path - string path; - status_t error = get_path(device, node, leaf, path); - if (error != B_OK) - return error; - - // copy it back to the user buffer - if (strlcpy(userPath, path.c_str(), pathLength) >= pathLength) - return B_BUFFER_OVERFLOW; - - return B_OK; -} - - -// #pragma mark - - -// _kern_create_dir -status_t -_kern_create_dir(int fd, const char *path, int perms) -{ - // get a usable path - string realPath; - status_t error = get_path(fd, path, realPath); - if (error != B_OK) - return error; - - // mkdir - if (mkdir(realPath.c_str(), perms) < 0) - return errno; - - return B_OK; -} - -// _kern_create_dir_entry_ref -status_t -_kern_create_dir_entry_ref(dev_t device, ino_t node, const char *name, - int perms) -{ - // get a usable path - string realPath; - status_t error = get_path(device, node, name, realPath); - if (error != B_OK) - return error; - - // mkdir - if (mkdir(realPath.c_str(), perms) < 0) - return errno; - - return B_OK; -} - -// open_dir -static int -open_dir(const char *path) -{ - // open the dir - DIR *dir = opendir(path); - if (!dir) - return errno; - - // stat the entry - struct stat st; - if (stat(path, &st) < 0) { - closedir(dir); - return errno; - } - - if (!S_ISDIR(st.st_mode)) { - closedir(dir); - return B_NOT_A_DIRECTORY; - } - - // cache dir path - NodeRef ref(st); - add_dir_path(path, ref); - - // create descriptor - DirectoryDescriptor *descriptor = new DirectoryDescriptor(dir, ref); - return add_descriptor(descriptor); -} - -// _kern_open_dir -int -_kern_open_dir(int fd, const char *path) -{ - // get a usable path - string realPath; - status_t error = get_path(fd, path, realPath); - if (error != B_OK) - return error; - - return open_dir(realPath.c_str()); -} - -// _kern_open_dir_entry_ref -int -_kern_open_dir_entry_ref(dev_t device, ino_t node, const char *name) -{ - // get a usable path - string realPath; - status_t error = get_path(device, node, name, realPath); - if (error != B_OK) - return error; - - return open_dir(realPath.c_str()); -} - -// _kern_open_parent_dir -int -_kern_open_parent_dir(int fd, char *name, size_t nameLength) -{ - // get a usable path - string realPath; - status_t error = get_path(fd, name, realPath); - if (error != B_OK) - return error; - - // stat the entry - struct stat st; - if (stat(realPath.c_str(), &st) < 0) - return errno; - - if (!S_ISDIR(st.st_mode)) - return B_NOT_A_DIRECTORY; - - // get the entry name - realPath += "/.."; - string entryName; - error = find_dir_entry(realPath.c_str(), NodeRef(st), - entryName, false); - if (error != B_OK) - return error; - - if (strlcpy(name, entryName.c_str(), nameLength) >= nameLength) - return B_BUFFER_OVERFLOW; - - // open the parent directory - - return open_dir(realPath.c_str()); -} - -// _kern_read_dir -ssize_t -_kern_read_dir(int fd, struct dirent *buffer, size_t bufferSize, - uint32 maxCount) -{ - if (maxCount <= 0) - return B_BAD_VALUE; - - // get the descriptor - DirectoryDescriptor *descriptor - = dynamic_cast(get_descriptor(fd)); - if (!descriptor) - return B_FILE_ERROR; - - // get the next entry - dirent *entry; - if (dynamic_cast(descriptor)) - entry = fs_read_attr_dir(descriptor->dir); - else - entry = readdir(descriptor->dir); - if (!entry) - return errno; - - // copy the entry - int entryLen = &entry->d_name[strlen(entry->d_name) + 1] - (char*)entry; - if (entryLen > (int)bufferSize) - return B_BUFFER_OVERFLOW; - - memcpy(buffer, entry, entryLen); - - return 1; -} - -// _kern_rewind_dir -status_t -_kern_rewind_dir(int fd) -{ - // get the descriptor - DirectoryDescriptor *descriptor - = dynamic_cast(get_descriptor(fd)); - if (!descriptor) - return B_FILE_ERROR; - - // rewind - if (dynamic_cast(descriptor)) - fs_rewind_attr_dir(descriptor->dir); - else - rewinddir(descriptor->dir); - - return B_OK; -} - - -// #pragma mark - - -// open_file -static int -open_file(const char *path, int openMode, int perms) -{ - // stat the node - bool exists = true; - struct stat st; - if (lstat(path, &st) < 0) { - exists = false; - if (!(openMode & O_CREAT)) - return errno; - } - - Descriptor *descriptor; - if (exists && S_ISLNK(st.st_mode) && (openMode & O_NOTRAVERSE)) { - // a symlink not to be followed: create a special descriptor - // normalize path first - string normalizedPath; - status_t error = normalize_entry_path(path, normalizedPath); - if (error != B_OK) - return error; - - descriptor = new SymlinkDescriptor(normalizedPath.c_str()); - - } else { - // open the file - openMode &= ~O_NOTRAVERSE; - int newFD = open(path, openMode, perms); - if (newFD < 0) - return errno; - - descriptor = new FileDescriptor(newFD); - } - - // cache path, if this is a directory - if (exists && S_ISDIR(st.st_mode)) - add_dir_path(path, NodeRef(st)); - - return add_descriptor(descriptor); -} - -// _kern_open -int -_kern_open(int fd, const char *path, int openMode, int perms) -{ - // get a usable path - string realPath; - status_t error = get_path(fd, path, realPath); - if (error != B_OK) - return error; - - return open_file(realPath.c_str(), openMode, perms); -} - -// _kern_open_entry_ref -int -_kern_open_entry_ref(dev_t device, ino_t node, const char *name, - int openMode, int perms) -{ - // get a usable path - string realPath; - status_t error = get_path(device, node, name, realPath); - if (error != B_OK) - return error; - - return open_file(realPath.c_str(), openMode, perms); -} - -// _kern_seek -off_t -_kern_seek(int fd, off_t pos, int seekType) -{ - // get the descriptor - FileDescriptor *descriptor - = dynamic_cast(get_descriptor(fd)); - if (!descriptor) - return B_FILE_ERROR; - - // seek - off_t result = lseek(descriptor->fd, pos, seekType); - if (result < 0) - return errno; - - return result; -} - -// _kern_read -ssize_t -_kern_read(int fd, off_t pos, void *buffer, size_t bufferSize) -{ - // get the descriptor - FileDescriptor *descriptor - = dynamic_cast(get_descriptor(fd)); - if (!descriptor) - return B_FILE_ERROR; - - // seek - if (pos != -1) { - off_t result = lseek(descriptor->fd, pos, SEEK_SET); - if (result < 0) - return errno; - } - - // read - ssize_t bytesRead = read(descriptor->fd, buffer, bufferSize); - if (bytesRead < 0) - return errno; - - return bytesRead; -} - -// _kern_write -ssize_t -_kern_write(int fd, off_t pos, const void *buffer, size_t bufferSize) -{ - // get the descriptor - FileDescriptor *descriptor - = dynamic_cast(get_descriptor(fd)); - if (!descriptor) - return B_FILE_ERROR; - - // seek - if (pos != -1) { - off_t result = lseek(descriptor->fd, pos, SEEK_SET); - if (result < 0) - return errno; - } - - // read - ssize_t bytesWritten = write(descriptor->fd, buffer, bufferSize); - if (bytesWritten < 0) - return errno; - - return bytesWritten; -} - -// _kern_close -status_t -_kern_close(int fd) -{ - return delete_descriptor(fd); -} - -// _kern_dup -int -_kern_dup(int fd) -{ - // get the descriptor - Descriptor *descriptor = get_descriptor(fd); - if (!descriptor) - return B_FILE_ERROR; - - // clone it - Descriptor *clone; - status_t error = descriptor->Dup(clone); - if (error != B_OK) - return error; - - return add_descriptor(clone); -} - -// _kern_fsync -status_t -_kern_fsync(int fd) -{ - // get the descriptor - FileDescriptor *descriptor - = dynamic_cast(get_descriptor(fd)); - if (!descriptor) - return B_FILE_ERROR; - - // sync - if (fsync(descriptor->fd) < 0) - return errno; - - return B_OK; -} - -// _kern_read_stat -status_t -_kern_read_stat(int fd, const char *path, bool traverseLink, - struct stat *st, size_t statSize) -{ - if (path) { - // get a usable path - string realPath; - status_t error = get_path(fd, path, realPath); - if (error != B_OK) - return error; - - // stat - int result; - if (traverseLink) - result = stat(realPath.c_str(), st); - else - result = lstat(realPath.c_str(), st); - - if (result < 0) - return errno; - } else { - Descriptor *descriptor = get_descriptor(fd); - if (!descriptor) - return B_FILE_ERROR; - - return descriptor->GetStat(traverseLink, st); - } - - return B_OK; -} - -// _kern_write_stat -status_t -_kern_write_stat(int fd, const char *path, bool traverseLink, - const struct stat *st, size_t statSize, int statMask) -{ - // get a usable path - int realFD = -1; - string realPath; - status_t error; - bool isSymlink = false; - if (path) { - error = get_path(fd, path, realPath); - if (error != B_OK) - return error; - - // stat it to see, if it is a symlink - struct stat tmpStat; - if (lstat(realPath.c_str(), &tmpStat) < 0) - return errno; - - isSymlink = S_ISLNK(tmpStat.st_mode); - - } else { - Descriptor *descriptor = get_descriptor(fd); - if (!descriptor) - return B_FILE_ERROR; - - if (FileDescriptor *fileFD - = dynamic_cast(descriptor)) { - realFD = fileFD->fd; - - } else if (dynamic_cast(descriptor)) { - error = get_path(fd, NULL, realPath); - if (error != B_OK) - return error; - - } else if (SymlinkDescriptor *linkFD - = dynamic_cast(descriptor)) { - realPath = linkFD->path; - isSymlink = true; - - } else - return B_FILE_ERROR; - } - - // We're screwed, if the node to manipulate is a symlink. All the - // available functions traverse symlinks. - if (isSymlink && !traverseLink) - return B_ERROR; - - if (realFD >= 0) { - if (statMask & B_STAT_MODE) { - if (fchmod(realFD, st->st_mode) < 0) - return errno; - } - - if (statMask & B_STAT_UID) { - if (fchown(realFD, st->st_uid, (gid_t)-1) < 0) - return errno; - } - - if (statMask & B_STAT_GID) { - if (fchown(realFD, (uid_t)-1, st->st_gid) < 0) - return errno; - } - - if (statMask & B_STAT_SIZE) { - if (ftruncate(realFD, st->st_size) < 0) - return errno; - } - - // The timestamps can only be set via utime(), but that requires a - // path we don't have. - if (statMask & (B_STAT_ACCESS_TIME | B_STAT_MODIFICATION_TIME - | B_STAT_CREATION_TIME | B_STAT_CHANGE_TIME)) { - return B_ERROR; - } - - return 0; - - } else { - if (statMask & B_STAT_MODE) { - if (chmod(realPath.c_str(), st->st_mode) < 0) - return errno; - } - - if (statMask & B_STAT_UID) { - if (chown(realPath.c_str(), st->st_uid, (gid_t)-1) < 0) - return errno; - } - - if (statMask & B_STAT_GID) { - if (chown(realPath.c_str(), (uid_t)-1, st->st_gid) < 0) - return errno; - } - - if (statMask & B_STAT_SIZE) { - if (truncate(realPath.c_str(), st->st_size) < 0) - return errno; - } - - if (statMask & (B_STAT_ACCESS_TIME | B_STAT_MODIFICATION_TIME)) { - // Grab the previous mod and access times so we only overwrite - // the specified time and not both - struct stat oldStat; - if (~statMask & (B_STAT_ACCESS_TIME | B_STAT_MODIFICATION_TIME)) { - if (stat(realPath.c_str(), &oldStat) < 0) - return errno; - } - - utimbuf buffer; - buffer.actime = (statMask & B_STAT_ACCESS_TIME) ? st->st_atime : oldStat.st_atime; - buffer.modtime = (statMask & B_STAT_MODIFICATION_TIME) ? st->st_mtime : oldStat.st_mtime; - if (utime(realPath.c_str(), &buffer) < 0) - return errno; - } - - // not supported - if (statMask & (B_STAT_CREATION_TIME | B_STAT_CHANGE_TIME)) - return B_ERROR; - } - - return B_OK; -} - - -// #pragma mark - - -// _kern_create_symlink -status_t -_kern_create_symlink(int fd, const char *path, const char *toPath, int mode) -{ - // Note: path must not be NULL, so this will always work. - // get a usable path - string realPath; - status_t error = get_path(fd, path, realPath); - if (error != B_OK) - return error; - - // symlink - if (symlink(toPath, realPath.c_str()) < 0) - return errno; - - return B_OK; -} - -// _kern_read_link -status_t -_kern_read_link(int fd, const char *path, char *buffer, size_t *_bufferSize) -{ - // get the descriptor - SymlinkDescriptor *descriptor - = dynamic_cast(get_descriptor(fd)); - if (!descriptor) - return B_FILE_ERROR; - - // readlink - ssize_t bytesRead = readlink(descriptor->path.c_str(), buffer, - *_bufferSize); - if (bytesRead < 0) - return errno; - - if (*_bufferSize > 0) { - if ((size_t)bytesRead == *_bufferSize) - bytesRead--; - - buffer[bytesRead] = '\0'; - } - - *_bufferSize = bytesRead; - - return B_OK; -} - -// _kern_unlink -status_t -_kern_unlink(int fd, const char *path) -{ - // get a usable path - string realPath; - status_t error = get_path(fd, path, realPath); - if (error != B_OK) - return error; - - // unlink - if (unlink(realPath.c_str()) < 0) - return errno; - - return B_OK; -} - -// _kern_rename -status_t -_kern_rename(int oldDir, const char *oldPath, int newDir, const char *newPath) -{ - // get usable paths - string realOldPath; - status_t error = get_path(oldDir, oldPath, realOldPath); - if (error != B_OK) - return error; - - string realNewPath; - error = get_path(newDir, newPath, realNewPath); - if (error != B_OK) - return error; - - // rename - if (rename(realOldPath.c_str(), realNewPath.c_str()) < 0) - return errno; - - return B_OK; -} - - -// #pragma mark - - -// _kern_lock_node -status_t -_kern_lock_node(int fd) -{ - return B_ERROR; -} - -// _kern_unlock_node -status_t -_kern_unlock_node(int fd) -{ - return B_ERROR; -} - - -// #pragma mark - - -// read_pos -ssize_t -read_pos(int fd, off_t pos, void *buffer, size_t bufferSize) -{ - // seek - off_t result = lseek(fd, pos, SEEK_SET); - if (result < 0) - return errno; - - // read - ssize_t bytesRead = read(fd, buffer, bufferSize); - if (bytesRead < 0) { - errno = bytesRead; - return -1; - } - - return bytesRead; -} - -// write_pos -ssize_t -write_pos(int fd, off_t pos, const void *buffer, size_t bufferSize) -{ - // seek - off_t result = lseek(fd, pos, SEEK_SET); - if (result < 0) - return errno; - - // read - ssize_t bytesWritten = write(fd, buffer, bufferSize); - if (bytesWritten < 0) { - errno = bytesWritten; - return -1; - } - - return bytesWritten; -} - -// readv_pos -ssize_t -readv_pos(int fd, off_t pos, const struct iovec *vec, size_t count) -{ - // seek - off_t result = lseek(fd, pos, SEEK_SET); - if (result < 0) - return errno; - - // read - ssize_t bytesRead = readv(fd, vec, count); - if (bytesRead < 0) { - errno = bytesRead; - return -1; - } - - return bytesRead; -} - -// writev_pos -ssize_t -writev_pos(int fd, off_t pos, const struct iovec *vec, size_t count) -{ - // seek - off_t result = lseek(fd, pos, SEEK_SET); - if (result < 0) - return errno; - - // read - ssize_t bytesWritten = writev(fd, vec, count); - if (bytesWritten < 0) { - errno = bytesWritten; - return -1; - } - - return bytesWritten; -} + +#include + +#include "fs_impl.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include // for B_STAT_* flags +#include + +#include "fs_descriptors.h" +#include "NodeRef.h" + +using namespace std; +using namespace BPrivate; + + +static status_t get_path(dev_t device, ino_t node, const char *name, + string &path); + + +// find_dir_entry +static status_t +find_dir_entry(DIR *dir, const char *path, NodeRef ref, string &name, + bool skipDot) +{ + // find the entry + bool found = false; + while (dirent *entry = readdir(dir)) { + if ((!skipDot && strcmp(entry->d_name, ".") == 0) + || strcmp(entry->d_name, "..") == 0) { + // skip "." and ".." + } else /*if (entry->d_ino == ref.node)*/ { + // Note: Linux doesn't seem to translate dirent::d_ino of + // mount points. Thus we always have to lstat(). + // We also need to compare the device, which is generally not + // included in the dirent structure. Hence we lstat(). + string entryPath(path); + entryPath += '/'; + entryPath += entry->d_name; + struct stat st; + if (lstat(entryPath.c_str(), &st) == 0) { + if (NodeRef(st) == ref) { + name = entry->d_name; + found = true; + break; + } + } + } + } + + if (!found) + return B_ENTRY_NOT_FOUND; + + return B_OK; +} + +// find_dir_entry +static status_t +find_dir_entry(const char *path, NodeRef ref, string &name, bool skipDot) +{ + // open dir + DIR *dir = opendir(path); + if (!dir) + return errno; + + status_t error = find_dir_entry(dir, path, ref, name, skipDot); + + // close dir + closedir(dir); + + return error; +} + +// normalize_dir_path +static status_t +normalize_dir_path(string path, NodeRef ref, string &normalizedPath) +{ + // get parent path + path += "/.."; + + // stat the parent dir + struct stat st; + if (lstat(path.c_str(), &st) < 0) + return errno; + + // root dir? + NodeRef parentRef(st); + if (parentRef == ref) { + normalizedPath = "/"; + return 0; + } + + // find the entry + string name; + status_t error = find_dir_entry(path.c_str(), ref, name, true) ; + if (error != B_OK) + return error; + + // recurse to get the parent dir path, if found + error = normalize_dir_path(path, parentRef, normalizedPath); + if (error != 0) + return error; + + // construct the normalizedPath + if (normalizedPath.length() > 1) // don't append "/", if parent is root + normalizedPath += '/'; + normalizedPath += name; + + return 0; +} + +// normalize_dir_path +static status_t +normalize_dir_path(const char *path, string &normalizedPath) +{ + // stat() the dir + struct stat st; + if (stat(path, &st) < 0) + return errno; + + return normalize_dir_path(path, NodeRef(st), normalizedPath); +} + +// normalize_entry_path +static status_t +normalize_entry_path(const char *path, string &normalizedPath) +{ + const char *dirPath = NULL; + const char *leafName = NULL; + + string dirPathString; + if (char *lastSlash = strrchr(path, '/')) { + // found a slash: decompose into dir path and leaf name + leafName = lastSlash + 1; + if (leafName[0] == '\0') { + // slash is at the end: the whole path is a dir name + leafName = NULL; + } else { + dirPathString = string(path, leafName - path); + dirPath = dirPathString.c_str(); + } + + } else { + // path contains no slash, so it is a path relative to the current dir + dirPath = "."; + leafName = path; + } + + // catch special case: no leaf, or leaf is a directory + if (!leafName || strcmp(leafName, ".") == 0 || strcmp(leafName, "..") == 0) + return normalize_dir_path(path, normalizedPath); + + // normalize the dir path + status_t error = normalize_dir_path(dirPath, normalizedPath); + if (error != B_OK) + return error; + + // append the leaf name + if (normalizedPath.length() > 1) // don't append "/", if parent is root + normalizedPath += '/'; + normalizedPath += leafName; + + return B_OK; +} + + +// #pragma mark - + +typedef map DirPathMap; +static DirPathMap sDirPathMap; + +// get_path +static status_t +get_path(const NodeRef *ref, const char *name, string &path) +{ + if (!ref && !name) + return B_BAD_VALUE; + + // no ref or absolute path + if (!ref || (name && name[0] == '/')) { + path = name; + return B_OK; + } + + // get the dir path + if (ref) { + DirPathMap::iterator it = sDirPathMap.find(*ref); + if (it == sDirPathMap.end()) + return B_ENTRY_NOT_FOUND; + + path = it->second; + + // stat the path to check, if it is still valid + struct stat st; + if (lstat(path.c_str(), &st) < 0) { + sDirPathMap.erase(it); + return errno; + } + + // compare the NodeRef + if (NodeRef(st) != *ref) { + sDirPathMap.erase(it); + return B_ENTRY_NOT_FOUND; + } + + // still a directory? + if (!S_ISDIR(st.st_mode)) { + sDirPathMap.erase(it); + return B_NOT_A_DIRECTORY; + } + } + + // if there's a name, append it + if (name) { + path += '/'; + path += name; + } + + return B_OK; +} + +// get_path +status_t +BPrivate::get_path(int fd, const char *name, string &path) +{ + // get the node ref for the fd, if any, and the path part is not absolute + if (fd >= 0 && !(name && name[0] == '/')) { + // get descriptor + Descriptor *descriptor = get_descriptor(fd); + if (!descriptor) + return B_FILE_ERROR; + + // get node ref for the descriptor + NodeRef ref; + status_t error = descriptor->GetNodeRef(ref); + if (error != B_OK) + return error; + + return ::get_path(&ref, name, path); + + } else // no descriptor or absolute path + return ::get_path((NodeRef*)NULL, name, path); +} + +// get_path +static status_t +get_path(dev_t device, ino_t directory, const char *name, string &path) +{ + NodeRef ref; + ref.device = device; + ref.node = directory; + + return get_path(&ref, name, path); +} + +// add_dir_path +static void +add_dir_path(const char *path, const NodeRef &ref) +{ + // add the normalized path + string normalizedPath; + if (normalize_dir_path(path, normalizedPath) == B_OK) + sDirPathMap[ref] = normalizedPath; +} + + +// #pragma mark - + +// _kern_entry_ref_to_path +status_t +_kern_entry_ref_to_path(dev_t device, ino_t node, const char *leaf, + char *userPath, size_t pathLength) +{ + // get the path + string path; + status_t error = get_path(device, node, leaf, path); + if (error != B_OK) + return error; + + // copy it back to the user buffer + if (strlcpy(userPath, path.c_str(), pathLength) >= pathLength) + return B_BUFFER_OVERFLOW; + + return B_OK; +} + + +// #pragma mark - + +// _kern_create_dir +status_t +_kern_create_dir(int fd, const char *path, int perms) +{ + // get a usable path + string realPath; + status_t error = get_path(fd, path, realPath); + if (error != B_OK) + return error; + + // mkdir + if (mkdir(realPath.c_str(), perms) < 0) + return errno; + + return B_OK; +} + +// _kern_create_dir_entry_ref +status_t +_kern_create_dir_entry_ref(dev_t device, ino_t node, const char *name, + int perms) +{ + // get a usable path + string realPath; + status_t error = get_path(device, node, name, realPath); + if (error != B_OK) + return error; + + // mkdir + if (mkdir(realPath.c_str(), perms) < 0) + return errno; + + return B_OK; +} + +// open_dir +static int +open_dir(const char *path) +{ + // open the dir + DIR *dir = opendir(path); + if (!dir) + return errno; + + // stat the entry + struct stat st; + if (stat(path, &st) < 0) { + closedir(dir); + return errno; + } + + if (!S_ISDIR(st.st_mode)) { + closedir(dir); + return B_NOT_A_DIRECTORY; + } + + // cache dir path + NodeRef ref(st); + add_dir_path(path, ref); + + // create descriptor + DirectoryDescriptor *descriptor = new DirectoryDescriptor(dir, ref); + return add_descriptor(descriptor); +} + +// _kern_open_dir +int +_kern_open_dir(int fd, const char *path) +{ + // get a usable path + string realPath; + status_t error = get_path(fd, path, realPath); + if (error != B_OK) + return error; + + return open_dir(realPath.c_str()); +} + +// _kern_open_dir_entry_ref +int +_kern_open_dir_entry_ref(dev_t device, ino_t node, const char *name) +{ + // get a usable path + string realPath; + status_t error = get_path(device, node, name, realPath); + if (error != B_OK) + return error; + + return open_dir(realPath.c_str()); +} + +// _kern_open_parent_dir +int +_kern_open_parent_dir(int fd, char *name, size_t nameLength) +{ + // get a usable path + string realPath; + status_t error = get_path(fd, name, realPath); + if (error != B_OK) + return error; + + // stat the entry + struct stat st; + if (stat(realPath.c_str(), &st) < 0) + return errno; + + if (!S_ISDIR(st.st_mode)) + return B_NOT_A_DIRECTORY; + + // get the entry name + realPath += "/.."; + string entryName; + error = find_dir_entry(realPath.c_str(), NodeRef(st), + entryName, false); + if (error != B_OK) + return error; + + if (strlcpy(name, entryName.c_str(), nameLength) >= nameLength) + return B_BUFFER_OVERFLOW; + + // open the parent directory + + return open_dir(realPath.c_str()); +} + +// _kern_read_dir +ssize_t +_kern_read_dir(int fd, struct dirent *buffer, size_t bufferSize, + uint32 maxCount) +{ + if (maxCount <= 0) + return B_BAD_VALUE; + + // get the descriptor + DirectoryDescriptor *descriptor + = dynamic_cast(get_descriptor(fd)); + if (!descriptor) + return B_FILE_ERROR; + + // get the next entry + dirent *entry; + if (dynamic_cast(descriptor)) + entry = fs_read_attr_dir(descriptor->dir); + else + entry = readdir(descriptor->dir); + if (!entry) + return errno; + + // copy the entry + int entryLen = &entry->d_name[strlen(entry->d_name) + 1] - (char*)entry; + if (entryLen > (int)bufferSize) + return B_BUFFER_OVERFLOW; + + memcpy(buffer, entry, entryLen); + + return 1; +} + +// _kern_rewind_dir +status_t +_kern_rewind_dir(int fd) +{ + // get the descriptor + DirectoryDescriptor *descriptor + = dynamic_cast(get_descriptor(fd)); + if (!descriptor) + return B_FILE_ERROR; + + // rewind + if (dynamic_cast(descriptor)) + fs_rewind_attr_dir(descriptor->dir); + else + rewinddir(descriptor->dir); + + return B_OK; +} + + +// #pragma mark - + +// open_file +static int +open_file(const char *path, int openMode, int perms) +{ + // stat the node + bool exists = true; + struct stat st; + if (lstat(path, &st) < 0) { + exists = false; + if (!(openMode & O_CREAT)) + return errno; + } + + Descriptor *descriptor; + if (exists && S_ISLNK(st.st_mode) && (openMode & O_NOTRAVERSE)) { + // a symlink not to be followed: create a special descriptor + // normalize path first + string normalizedPath; + status_t error = normalize_entry_path(path, normalizedPath); + if (error != B_OK) + return error; + + descriptor = new SymlinkDescriptor(normalizedPath.c_str()); + + } else { + // open the file + openMode &= ~O_NOTRAVERSE; + int newFD = open(path, openMode, perms); + if (newFD < 0) + return errno; + + descriptor = new FileDescriptor(newFD); + } + + // cache path, if this is a directory + if (exists && S_ISDIR(st.st_mode)) + add_dir_path(path, NodeRef(st)); + + return add_descriptor(descriptor); +} + +// _kern_open +int +_kern_open(int fd, const char *path, int openMode, int perms) +{ + // get a usable path + string realPath; + status_t error = get_path(fd, path, realPath); + if (error != B_OK) + return error; + + return open_file(realPath.c_str(), openMode, perms); +} + +// _kern_open_entry_ref +int +_kern_open_entry_ref(dev_t device, ino_t node, const char *name, + int openMode, int perms) +{ + // get a usable path + string realPath; + status_t error = get_path(device, node, name, realPath); + if (error != B_OK) + return error; + + return open_file(realPath.c_str(), openMode, perms); +} + +// _kern_seek +off_t +_kern_seek(int fd, off_t pos, int seekType) +{ + // get the descriptor + FileDescriptor *descriptor + = dynamic_cast(get_descriptor(fd)); + if (!descriptor) + return B_FILE_ERROR; + + // seek + off_t result = lseek(descriptor->fd, pos, seekType); + if (result < 0) + return errno; + + return result; +} + +// _kern_read +ssize_t +_kern_read(int fd, off_t pos, void *buffer, size_t bufferSize) +{ + // get the descriptor + FileDescriptor *descriptor + = dynamic_cast(get_descriptor(fd)); + if (!descriptor) + return B_FILE_ERROR; + + // seek + if (pos != -1) { + off_t result = lseek(descriptor->fd, pos, SEEK_SET); + if (result < 0) + return errno; + } + + // read + ssize_t bytesRead = read(descriptor->fd, buffer, bufferSize); + if (bytesRead < 0) + return errno; + + return bytesRead; +} + +// _kern_write +ssize_t +_kern_write(int fd, off_t pos, const void *buffer, size_t bufferSize) +{ + // get the descriptor + FileDescriptor *descriptor + = dynamic_cast(get_descriptor(fd)); + if (!descriptor) + return B_FILE_ERROR; + + // seek + if (pos != -1) { + off_t result = lseek(descriptor->fd, pos, SEEK_SET); + if (result < 0) + return errno; + } + + // read + ssize_t bytesWritten = write(descriptor->fd, buffer, bufferSize); + if (bytesWritten < 0) + return errno; + + return bytesWritten; +} + +// _kern_close +status_t +_kern_close(int fd) +{ + return delete_descriptor(fd); +} + +// _kern_dup +int +_kern_dup(int fd) +{ + // get the descriptor + Descriptor *descriptor = get_descriptor(fd); + if (!descriptor) + return B_FILE_ERROR; + + // clone it + Descriptor *clone; + status_t error = descriptor->Dup(clone); + if (error != B_OK) + return error; + + return add_descriptor(clone); +} + +// _kern_fsync +status_t +_kern_fsync(int fd) +{ + // get the descriptor + FileDescriptor *descriptor + = dynamic_cast(get_descriptor(fd)); + if (!descriptor) + return B_FILE_ERROR; + + // sync + if (fsync(descriptor->fd) < 0) + return errno; + + return B_OK; +} + +// _kern_read_stat +status_t +_kern_read_stat(int fd, const char *path, bool traverseLink, + struct stat *st, size_t statSize) +{ + if (path) { + // get a usable path + string realPath; + status_t error = get_path(fd, path, realPath); + if (error != B_OK) + return error; + + // stat + int result; + if (traverseLink) + result = stat(realPath.c_str(), st); + else + result = lstat(realPath.c_str(), st); + + if (result < 0) + return errno; + } else { + Descriptor *descriptor = get_descriptor(fd); + if (!descriptor) + return B_FILE_ERROR; + + return descriptor->GetStat(traverseLink, st); + } + + return B_OK; +} + +// _kern_write_stat +status_t +_kern_write_stat(int fd, const char *path, bool traverseLink, + const struct stat *st, size_t statSize, int statMask) +{ + // get a usable path + int realFD = -1; + string realPath; + status_t error; + bool isSymlink = false; + if (path) { + error = get_path(fd, path, realPath); + if (error != B_OK) + return error; + + // stat it to see, if it is a symlink + struct stat tmpStat; + if (lstat(realPath.c_str(), &tmpStat) < 0) + return errno; + + isSymlink = S_ISLNK(tmpStat.st_mode); + + } else { + Descriptor *descriptor = get_descriptor(fd); + if (!descriptor) + return B_FILE_ERROR; + + if (FileDescriptor *fileFD + = dynamic_cast(descriptor)) { + realFD = fileFD->fd; + + } else if (dynamic_cast(descriptor)) { + error = get_path(fd, NULL, realPath); + if (error != B_OK) + return error; + + } else if (SymlinkDescriptor *linkFD + = dynamic_cast(descriptor)) { + realPath = linkFD->path; + isSymlink = true; + + } else + return B_FILE_ERROR; + } + + // We're screwed, if the node to manipulate is a symlink. All the + // available functions traverse symlinks. + if (isSymlink && !traverseLink) + return B_ERROR; + + if (realFD >= 0) { + if (statMask & B_STAT_MODE) { + if (fchmod(realFD, st->st_mode) < 0) + return errno; + } + + if (statMask & B_STAT_UID) { + if (fchown(realFD, st->st_uid, (gid_t)-1) < 0) + return errno; + } + + if (statMask & B_STAT_GID) { + if (fchown(realFD, (uid_t)-1, st->st_gid) < 0) + return errno; + } + + if (statMask & B_STAT_SIZE) { + if (ftruncate(realFD, st->st_size) < 0) + return errno; + } + + // The timestamps can only be set via utime(), but that requires a + // path we don't have. + if (statMask & (B_STAT_ACCESS_TIME | B_STAT_MODIFICATION_TIME + | B_STAT_CREATION_TIME | B_STAT_CHANGE_TIME)) { + return B_ERROR; + } + + return 0; + + } else { + if (statMask & B_STAT_MODE) { + if (chmod(realPath.c_str(), st->st_mode) < 0) + return errno; + } + + if (statMask & B_STAT_UID) { + if (chown(realPath.c_str(), st->st_uid, (gid_t)-1) < 0) + return errno; + } + + if (statMask & B_STAT_GID) { + if (chown(realPath.c_str(), (uid_t)-1, st->st_gid) < 0) + return errno; + } + + if (statMask & B_STAT_SIZE) { + if (truncate(realPath.c_str(), st->st_size) < 0) + return errno; + } + + if (statMask & (B_STAT_ACCESS_TIME | B_STAT_MODIFICATION_TIME)) { + // Grab the previous mod and access times so we only overwrite + // the specified time and not both + struct stat oldStat; + if (~statMask & (B_STAT_ACCESS_TIME | B_STAT_MODIFICATION_TIME)) { + if (stat(realPath.c_str(), &oldStat) < 0) + return errno; + } + + utimbuf buffer; + buffer.actime = (statMask & B_STAT_ACCESS_TIME) ? st->st_atime : oldStat.st_atime; + buffer.modtime = (statMask & B_STAT_MODIFICATION_TIME) ? st->st_mtime : oldStat.st_mtime; + if (utime(realPath.c_str(), &buffer) < 0) + return errno; + } + + // not supported + if (statMask & (B_STAT_CREATION_TIME | B_STAT_CHANGE_TIME)) + return B_ERROR; + } + + return B_OK; +} + + +// #pragma mark - + +// _kern_create_symlink +status_t +_kern_create_symlink(int fd, const char *path, const char *toPath, int mode) +{ + // Note: path must not be NULL, so this will always work. + // get a usable path + string realPath; + status_t error = get_path(fd, path, realPath); + if (error != B_OK) + return error; + + // symlink + if (symlink(toPath, realPath.c_str()) < 0) + return errno; + + return B_OK; +} + +// _kern_read_link +status_t +_kern_read_link(int fd, const char *path, char *buffer, size_t *_bufferSize) +{ + // get the descriptor + SymlinkDescriptor *descriptor + = dynamic_cast(get_descriptor(fd)); + if (!descriptor) + return B_FILE_ERROR; + + // readlink + ssize_t bytesRead = readlink(descriptor->path.c_str(), buffer, + *_bufferSize); + if (bytesRead < 0) + return errno; + + if (*_bufferSize > 0) { + if ((size_t)bytesRead == *_bufferSize) + bytesRead--; + + buffer[bytesRead] = '\0'; + } + + *_bufferSize = bytesRead; + + return B_OK; +} + +// _kern_unlink +status_t +_kern_unlink(int fd, const char *path) +{ + // get a usable path + string realPath; + status_t error = get_path(fd, path, realPath); + if (error != B_OK) + return error; + + // unlink + if (unlink(realPath.c_str()) < 0) + return errno; + + return B_OK; +} + +// _kern_rename +status_t +_kern_rename(int oldDir, const char *oldPath, int newDir, const char *newPath) +{ + // get usable paths + string realOldPath; + status_t error = get_path(oldDir, oldPath, realOldPath); + if (error != B_OK) + return error; + + string realNewPath; + error = get_path(newDir, newPath, realNewPath); + if (error != B_OK) + return error; + + // rename + if (rename(realOldPath.c_str(), realNewPath.c_str()) < 0) + return errno; + + return B_OK; +} + + +// #pragma mark - + +// _kern_lock_node +status_t +_kern_lock_node(int fd) +{ + return B_ERROR; +} + +// _kern_unlock_node +status_t +_kern_unlock_node(int fd) +{ + return B_ERROR; +} + + +// #pragma mark - + +// read_pos +ssize_t +read_pos(int fd, off_t pos, void *buffer, size_t bufferSize) +{ + // seek + off_t result = lseek(fd, pos, SEEK_SET); + if (result < 0) + return errno; + + // read + ssize_t bytesRead = read(fd, buffer, bufferSize); + if (bytesRead < 0) { + errno = bytesRead; + return -1; + } + + return bytesRead; +} + +// write_pos +ssize_t +write_pos(int fd, off_t pos, const void *buffer, size_t bufferSize) +{ + // seek + off_t result = lseek(fd, pos, SEEK_SET); + if (result < 0) + return errno; + + // read + ssize_t bytesWritten = write(fd, buffer, bufferSize); + if (bytesWritten < 0) { + errno = bytesWritten; + return -1; + } + + return bytesWritten; +} + +// readv_pos +ssize_t +readv_pos(int fd, off_t pos, const struct iovec *vec, size_t count) +{ + // seek + off_t result = lseek(fd, pos, SEEK_SET); + if (result < 0) + return errno; + + // read + ssize_t bytesRead = readv(fd, vec, count); + if (bytesRead < 0) { + errno = bytesRead; + return -1; + } + + return bytesRead; +} + +// writev_pos +ssize_t +writev_pos(int fd, off_t pos, const struct iovec *vec, size_t count) +{ + // seek + off_t result = lseek(fd, pos, SEEK_SET); + if (result < 0) + return errno; + + // read + ssize_t bytesWritten = writev(fd, vec, count); + if (bytesWritten < 0) { + errno = bytesWritten; + return -1; + } + + return bytesWritten; +}