From 45eb999ec8f4d9bf86648ab94cfa96accadde3d8 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Sun, 9 Mar 2008 17:41:42 +0000 Subject: [PATCH] Added "query" and "chmod" (octal, non-recursive only) commands. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@24331 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/tools/fs_shell/fssh.cpp | 173 +++++++++++++++++++++++++++++++--- src/tools/fs_shell/syscalls.h | 7 ++ src/tools/fs_shell/vfs.cpp | 102 ++++++++++++++++++++ 3 files changed, 270 insertions(+), 12 deletions(-) diff --git a/src/tools/fs_shell/fssh.cpp b/src/tools/fs_shell/fssh.cpp index c25748d4c0..8f0a7a73b0 100644 --- a/src/tools/fs_shell/fssh.cpp +++ b/src/tools/fs_shell/fssh.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2007, Ingo Weinhold, bonefish@cs.tu-berlin.de. + * Copyright 2007-2008, Ingo Weinhold, ingo_weinhold@gmx.de. * Distributed under the terms of the MIT License. */ @@ -278,6 +278,87 @@ command_cd(int argc, const char* const* argv) } +static bool +get_permissions(const char* modeString, fssh_mode_t& _permissions) +{ + // currently only octal mode is supported + if (strlen(modeString) != 3) + return false; + + fssh_mode_t permissions = 0; + for (int i = 0; i < 3; i++) { + char c = modeString[i]; + if (c < '0' || c > '7') + return false; + permissions = (permissions << 3) | (c - '0'); + } + + _permissions = permissions; + return true; +} + + +static fssh_status_t +command_chmod(int argc, const char* const* argv) +{ + bool recursive = false; + + // parse parameters + int argi = 1; + for (argi = 1; argi < argc; argi++) { + const char *arg = argv[argi]; + if (arg[0] != '-') + break; + + if (arg[1] == '\0') { + fprintf(stderr, "Error: Invalid option \"-\"\n"); + return FSSH_B_BAD_VALUE; + } + + for (int i = 1; arg[i]; i++) { + switch (arg[i]) { + case 'R': + recursive = true; + fprintf(stderr, "Sorry, recursive mode not supported " + "yet.\n"); + return FSSH_B_BAD_VALUE; + default: + fprintf(stderr, "Error: Unknown option \"-%c\"\n", arg[i]); + return FSSH_B_BAD_VALUE; + } + } + } + + // get mode + fssh_mode_t permissions; + if (argi + 1 >= argc || !get_permissions(argv[argi++], permissions)) { + printf("Usage: %s [ -R ] ...\n", argv[0]); + return FSSH_B_BAD_VALUE; + } + + fssh_struct_stat st; + st.fssh_st_mode = permissions; + + // chmod loop + for (; argi < argc; argi++) { + const char *file = argv[argi]; + if (strlen(file) == 0) { + fprintf(stderr, "Error: An empty path is not a valid argument!\n"); + return FSSH_B_BAD_VALUE; + } + + fssh_status_t error = _kern_write_stat(-1, file, false, &st, sizeof(st), + FSSH_FS_WRITE_STAT_MODE); + if (error != FSSH_B_OK) { + fprintf(stderr, "Error: Failed to change mode of \"%s\"!\n", file); + return error; + } + } + + return FSSH_B_OK; +} + + static fssh_status_t command_help(int argc, const char* const* argv) { @@ -539,7 +620,6 @@ command_ls(int argc, const char* const* argv) "%s\n", file, fd, fssh_strerror(error)); continue; } - } else list_entry(file); } @@ -667,6 +747,22 @@ command_mkdir(int argc, const char* const* argv) } +static fssh_dev_t +get_volume_id() +{ + struct fssh_stat st; + fssh_status_t error = _kern_read_stat(-1, kMountPoint, false, &st, + sizeof(st)); + if (error != FSSH_B_OK) { + fprintf(stderr, "Error: Failed to stat() mount point: %s\n", + fssh_strerror(error)); + return error; + } + + return st.fssh_st_dev; +} + + static fssh_status_t command_mkindex(int argc, const char* const* argv) { @@ -677,18 +773,14 @@ command_mkindex(int argc, const char* const* argv) const char* indexName = argv[1]; - // get the device ID - struct fssh_stat st; - fssh_status_t error = _kern_read_stat(-1, kMountPoint, false, &st, - sizeof(st)); - if (error != FSSH_B_OK) { - fprintf(stderr, "Error: Failed to stat() mount point: %s\n", - fssh_strerror(error)); - return error; - } + // get the volume ID + fssh_dev_t volumeID = get_volume_id(); + if (volumeID < 0) + return volumeID; // create the index - error =_kern_create_index(st.fssh_st_dev, indexName, FSSH_B_STRING_TYPE, 0); + fssh_status_t error =_kern_create_index(volumeID, indexName, + FSSH_B_STRING_TYPE, 0); if (error != FSSH_B_OK) { fprintf(stderr, "Error: Failed to create index \"%s\": %s\n", indexName, fssh_strerror(error)); @@ -699,6 +791,61 @@ command_mkindex(int argc, const char* const* argv) } +static fssh_status_t +command_query(int argc, const char* const* argv) +{ + if (argc != 2) { + fprintf(stderr, "Usage: %s \n", argv[0]); + return FSSH_B_BAD_VALUE; + } + + const char* query = argv[1]; + + // get the volume ID + fssh_dev_t volumeID = get_volume_id(); + if (volumeID < 0) + return volumeID; + + // open query + int fd = _kern_open_query(volumeID, query, strlen(query), 0, -1, -1); + if (fd < 0) { + fprintf(stderr, "Error: Failed to open query: %s\n", fssh_strerror(fd)); + return fd; + } + + // iterate through the entries + fssh_status_t error = FSSH_B_OK; + char buffer[sizeof(fssh_dirent) + FSSH_B_FILE_NAME_LENGTH]; + fssh_dirent* entry = (fssh_dirent*)buffer; + fssh_ssize_t entriesRead = 0; + while ((entriesRead = _kern_read_dir(fd, entry, sizeof(buffer), 1)) == 1) { + char path[FSSH_B_PATH_NAME_LENGTH]; + error = _kern_entry_ref_to_path(volumeID, entry->d_pino, entry->d_name, + path, sizeof(path)); + if (error == FSSH_B_OK) { + printf(" %s\n", path); + } else { + fprintf(stderr, " failed to resolve entry (%8lld, \"%s\")\n", + entry->d_pino, entry->d_name); + } + } + + if (entriesRead < 0) { + fprintf(stderr, "Error: reading query failed: %s\n", + fssh_strerror(entriesRead)); + } + + // close query + error = _kern_close(fd); + if (error != FSSH_B_OK) { + fprintf(stderr, "Error: Closing query (fd: %d) failed: %s\n", + fd, fssh_strerror(error)); + } + + return error; +} + + static fssh_status_t command_quit(int argc, const char* const* argv) { @@ -866,12 +1013,14 @@ register_commands() { CommandManager::Default()->AddCommands( command_cd, "cd", "change current directory", + command_chmod, "chmod", "change file permissions", command_cp, "cp", "copy files and directories", command_help, "help", "list supported commands", command_ln, "ln", "create a hard or symbolic link", command_ls, "ls", "list files or directories", command_mkdir, "mkdir", "create directories", command_mkindex, "mkindex", "create an index", + command_query, "query", "query for files", command_quit, "quit/exit", "quit the shell", command_rm, "rm", "remove files and directories", command_sync, "sync", "syncs the file system", diff --git a/src/tools/fs_shell/syscalls.h b/src/tools/fs_shell/syscalls.h index 4d3338e391..f48e3f99a4 100644 --- a/src/tools/fs_shell/syscalls.h +++ b/src/tools/fs_shell/syscalls.h @@ -6,6 +6,7 @@ #define _FSSH_SYSCALLS_H #include "fssh_defs.h" +#include "fssh_os.h" struct fssh_iovec; @@ -24,6 +25,8 @@ fssh_status_t _kern_read_fs_info(fssh_dev_t device, fssh_status_t _kern_write_fs_info(fssh_dev_t device, const struct fssh_fs_info *info, int mask); fssh_status_t _kern_sync(void); +fssh_status_t _kern_entry_ref_to_path(fssh_dev_t device, fssh_ino_t inode, + const char *leaf, char *userPath, fssh_size_t pathLength); fssh_dev_t _kern_next_device(int32_t *_cookie); int _kern_open_entry_ref(fssh_dev_t device, fssh_ino_t inode, const char *name, int openMode, int perms); @@ -73,6 +76,10 @@ fssh_status_t _kern_initialize_volume(const char* fileSystem, const char *partition, const char *name, const char *parameters); +extern int _kern_open_query(fssh_dev_t device, const char* query, + fssh_size_t queryLength, uint32_t flags, fssh_port_id port, + int32_t token); + // defined in fd.cpp fssh_ssize_t _kern_read(int fd, fssh_off_t pos, void *buffer, fssh_size_t length); diff --git a/src/tools/fs_shell/vfs.cpp b/src/tools/fs_shell/vfs.cpp index 613df9ad94..7b48bf71da 100644 --- a/src/tools/fs_shell/vfs.cpp +++ b/src/tools/fs_shell/vfs.cpp @@ -2587,6 +2587,49 @@ vfs_get_vnode_name(void *_vnode, char *name, fssh_size_t nameSize) } +fssh_status_t +vfs_entry_ref_to_path(fssh_dev_t device, fssh_ino_t inode, const char *leaf, + char *path, fssh_size_t pathLength) +{ + struct vnode *vnode; + fssh_status_t status; + + // filter invalid leaf names + if (leaf != NULL && (leaf[0] == '\0' || fssh_strchr(leaf, '/'))) + return FSSH_B_BAD_VALUE; + + // get the vnode matching the dir's node_ref + if (leaf && (fssh_strcmp(leaf, ".") == 0 || fssh_strcmp(leaf, "..") == 0)) { + // special cases "." and "..": we can directly get the vnode of the + // referenced directory + status = entry_ref_to_vnode(device, inode, leaf, &vnode); + leaf = NULL; + } else + status = get_vnode(device, inode, &vnode, false); + if (status < FSSH_B_OK) + return status; + + // get the directory path + status = dir_vnode_to_path(vnode, path, pathLength); + put_vnode(vnode); + // we don't need the vnode anymore + if (status < FSSH_B_OK) + return status; + + // append the leaf name + if (leaf) { + // insert a directory separator if this is not the file system root + if ((fssh_strcmp(path, "/") && fssh_strlcat(path, "/", pathLength) + >= pathLength) + || fssh_strlcat(path, leaf, pathLength) >= pathLength) { + return FSSH_B_NAME_TOO_LONG; + } + } + + return FSSH_B_OK; +} + + /** If the given descriptor locked its vnode, that lock will be released. */ @@ -4283,6 +4326,48 @@ out: } +/*! ToDo: the query FS API is still the pretty much the same as in R5. + It would be nice if the FS would find some more kernel support + for them. + For example, query parsing should be moved into the kernel. +*/ +static int +query_open(fssh_dev_t device, const char *query, uint32_t flags, + fssh_port_id port, int32_t token, bool kernel) +{ + struct fs_mount *mount; + fssh_fs_cookie cookie; + + FUNCTION(("query_open(device = %ld, query = \"%s\", kernel = %d)\n", device, query, kernel)); + + fssh_status_t status = get_mount(device, &mount); + if (status < FSSH_B_OK) + return status; + + if (FS_MOUNT_CALL(mount, open_query) == NULL) { + status = FSSH_EOPNOTSUPP; + goto out; + } + + status = FS_MOUNT_CALL(mount, open_query)(mount->cookie, query, flags, port, token, &cookie); + if (status < FSSH_B_OK) + goto out; + + // get fd for the index directory + status = get_new_fd(FDTYPE_QUERY, mount, NULL, cookie, 0, kernel); + if (status >= 0) + goto out; + + // something went wrong + FS_MOUNT_CALL(mount, close_query)(mount->cookie, cookie); + FS_MOUNT_CALL(mount, free_query_cookie)(mount->cookie, cookie); + +out: + put_mount(mount); + return status; +} + + static fssh_status_t query_close(struct file_descriptor *descriptor) { @@ -5502,4 +5587,21 @@ _kern_initialize_volume(const char* fsName, const char *partition, return status; } + +fssh_status_t +_kern_entry_ref_to_path(fssh_dev_t device, fssh_ino_t inode, const char *leaf, + char* path, fssh_size_t pathLength) +{ + return vfs_entry_ref_to_path(device, inode, leaf, path, pathLength); +} + + +int +_kern_open_query(fssh_dev_t device, const char *query, fssh_size_t queryLength, + uint32_t flags, fssh_port_id port, int32_t token) +{ + return query_open(device, query, flags, port, token, false); +} + + } // namespace FSShell