/*! \brief Closes the node's file descriptor(s). To be implemented by subclasses to close the file descriptor using the proper system call for the given file-type. This implementation calls _kern_close(fFd) and also _kern_close(fAttrDir) if necessary. */ void BNode::close_fd() { if (fAttrFd >= 0) { _kern_close(fAttrFd); fAttrFd = -1; } if (fFd >= 0) { _kern_close(fFd); fFd = -1; } }
static int fuse_readdir(const char* path, void* buf, fuse_fill_dir_t filler, off_t offset, struct fuse_file_info* fi) { PRINTD("##readdir\n"); int dfp = _kern_open_dir(-1, path); if (dfp < FSSH_B_OK) return _ERR(dfp); fssh_ssize_t entriesRead = 0; struct fssh_stat f_st; struct stat st; char buffer[sizeof(fssh_dirent) + FSSH_B_FILE_NAME_LENGTH]; fssh_dirent* dirEntry = (fssh_dirent*)buffer; while ((entriesRead = _kern_read_dir(dfp, dirEntry, sizeof(buffer), 1)) == 1) { fssh_memset(&st, 0, sizeof(st)); fssh_memset(&f_st, 0, sizeof(f_st)); fssh_status_t status = _kern_read_stat(dfp, dirEntry->d_name, false, &f_st, sizeof(f_st)); if (status >= FSSH_B_OK) { fromFsshStatToStat(&f_st, &st); if (filler(buf, dirEntry->d_name, &st, 0)) break; } } _kern_close(dfp); //TODO: check _kern_close return 0; }
static fssh_status_t command_ls(int argc, const char* const* argv) { const char* const currentDirFiles[] = { ".", NULL }; const char* const* files; if (argc >= 2) files = argv + 1; else files = currentDirFiles; for (; *files; files++) { const char* file = *files; // stat file struct fssh_stat st; fssh_status_t error = _kern_read_stat(-1, file, false, &st, sizeof(st)); if (error != FSSH_B_OK) { fprintf(stderr, "Error: Failed to stat() \"%s\": %s\n", file, fssh_strerror(error)); continue; } // if it is a directory, print its entries if (FSSH_S_ISDIR(st.fssh_st_mode)) { printf("%s:\n", file); // open dir int fd = _kern_open_dir(-1, file); if (fd < 0) { fprintf(stderr, "Error: Failed to open dir \"%s\": %s\n", file, fssh_strerror(fd)); continue; } // iterate through the entries 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) { list_entry(file, entry->d_name); } if (entriesRead < 0) { fprintf(stderr, "Error: reading dir \"%s\" failed: %s\n", file, fssh_strerror(entriesRead)); } // close dir error = _kern_close(fd); if (error != FSSH_B_OK) { fprintf(stderr, "Error: Closing dir \"%s\" (fd: %d) failed: " "%s\n", file, fd, fssh_strerror(error)); continue; } } else list_entry(file); } return FSSH_B_OK; }
//! Closes the BDirectory's file descriptor. void BDirectory::close_fd() { if (fDirFd >= 0) { _kern_close(fDirFd); fDirFd = -1; } BNode::close_fd(); }
static fssh_status_t command_query(int argc, const char* const* argv) { if (argc != 2) { fprintf(stderr, "Usage: %s <query string>\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 (%8" FSSH_B_PRIdINO ", \"%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 int fuse_open(const char* path, struct fuse_file_info* fi) { PRINTD("##open\n"); // TODO: Do we have a syscall similar to the open syscall in linux which // takes only two args: path and flags with no mask/perms? int fd = _kern_open(-1, path, fi->flags, (FSSH_S_IRWXU | FSSH_S_IRWXG | FSSH_S_IRWXO) & ~sUmask); _kern_close(fd); if (fd < FSSH_B_OK) return _ERR(fd); else return 0; }
static int fuse_mknod(const char* path, mode_t mode, dev_t rdev) { PRINTD("##mknod\n"); if (S_ISREG(mode)) { int fd = _kern_open(-1, path, FSSH_O_CREAT | FSSH_O_EXCL | FSSH_O_WRONLY, mode); if (fd >= FSSH_B_OK) return _ERR(_kern_close(fd)); return _ERR(fd); } else if (S_ISFIFO(mode)) return _ERR(FSSH_EINVAL); else return _ERR(FSSH_EINVAL); }
static int fuse_write(const char* path, const char* buf, size_t size, off_t offset, struct fuse_file_info* fi) { PRINTD("##write\n"); int fd = _kern_open(-1, path, FSSH_O_WRONLY, (FSSH_S_IRWXU | FSSH_S_IRWXG | FSSH_S_IRWXO) & ~sUmask); if (fd < FSSH_B_OK) return _ERR(fd); int res = _kern_write(fd, offset, buf, size); _kern_close(fd); if (res < FSSH_B_OK) res = _ERR(res); return res; }
int closedir(DIR* dir) { int status; if (dir == NULL) { __set_errno(B_BAD_VALUE); return -1; } status = _kern_close(dir->fd); free(dir); RETURN_AND_SET_ERRNO(status); }
DIR* opendir(const char* path) { DIR* dir; int fd = _kern_open_dir(-1, path); if (fd < 0) { __set_errno(fd); return NULL; } // allocate the DIR structure if ((dir = __create_dir_struct(fd)) == NULL) { _kern_close(fd); return NULL; } return dir; }
DIR * fs_open_index_dir(dev_t device) { DIR *dir; int fd = _kern_open_index_dir(device); if (fd < 0) { __set_errno(fd); return NULL; } // allocate the DIR structure if ((dir = __create_dir_struct(fd)) == NULL) { _kern_close(fd); return NULL; } return dir; }
static int search_executable_in_path_list(const char *name, const char *pathList, int pathListLen, const char *programPath, const char *compatibilitySubDir, char *pathBuffer, size_t pathBufferLength) { const char *pathListEnd = pathList + pathListLen; status_t status = B_ENTRY_NOT_FOUND; TRACE(("runtime_loader: search_container_in_path_list() %s in %.*s\n", name, pathListLen, pathList)); while (pathListLen > 0) { const char *pathEnd = pathList; int fd; // find the next ':' or run till the end of the string while (pathEnd < pathListEnd && *pathEnd != ':') pathEnd++; fd = try_open_executable(pathList, pathEnd - pathList, name, programPath, compatibilitySubDir, pathBuffer, pathBufferLength); if (fd >= 0) { // see if it's a dir struct stat stat; status = _kern_read_stat(fd, NULL, true, &stat, sizeof(struct stat)); if (status == B_OK) { if (!S_ISDIR(stat.st_mode)) return fd; status = B_IS_A_DIRECTORY; } _kern_close(fd); } pathListLen = pathListEnd - pathEnd - 1; pathList = pathEnd + 1; } return status; }
static fssh_status_t remove_dir_contents(int parentDir, const char *name, bool force) { // open the dir int dir = _kern_open_dir(parentDir, name); if (dir < 0) { fprintf(stderr, "Error: Failed to open dir \"%s\": %s\n", name, fssh_strerror(dir)); return dir; } fssh_status_t error = FSSH_B_OK; // iterate through the entries fssh_ssize_t numRead; char buffer[sizeof(fssh_dirent) + FSSH_B_FILE_NAME_LENGTH]; fssh_dirent *entry = (fssh_dirent*)buffer; while ((numRead = _kern_read_dir(dir, entry, sizeof(buffer), 1)) > 0) { // skip "." and ".." if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) continue; error = remove_entry(dir, entry->d_name, true, force); if (error != FSSH_B_OK) break; } if (numRead < 0) { fprintf(stderr, "Error: Failed to read directory \"%s\": %s\n", name, fssh_strerror(numRead)); error = numRead; } // close _kern_close(dir); return error; }
/*! \brief Re-initializes the BDirectory to the directory referred to by the supplied path name relative to the specified BDirectory. \param dir the BDirectory, relative to which the directory's path name is given \param path the directory's path name relative to \a dir \return - \c B_OK: Everything went fine. - \c B_BAD_VALUE: \c NULL \a dir or \a path, or \a path is absolute. - \c B_ENTRY_NOT_FOUND: Directory not found. - \c B_PERMISSION_DENIED: Directory permissions didn't allow operation. - \c B_NO_MEMORY: Insufficient memory for operation. - \c B_NAME_TOO_LONG: The supplied path name (\a path) is too long. - \c B_LINK_LIMIT: Indicates a cyclic loop within the file system. - \c B_BUSY: A node was busy. - \c B_FILE_ERROR: A general file error. - \c B_NO_MORE_FDS: The application has run out of file descriptors. - \c B_NOT_A_DIRECTORY: \a path includes a non-directory. */ status_t BDirectory::SetTo(const BDirectory* dir, const char* path) { if (!dir || !path || BPrivate::Storage::is_absolute_path(path)) { Unset(); return (fCStatus = B_BAD_VALUE); } int dirFD = dir->fDirFd; if (dir == this) { // prevent that our file descriptor goes away in _SetTo() fDirFd = -1; } // open node status_t error = _SetTo(dirFD, path, true); if (error != B_OK) return error; // open dir fDirFd = _kern_open_dir(dirFD, path); if (fDirFd < 0) { status_t error = fDirFd; Unset(); return (fCStatus = error); } if (dir == this) { // cleanup after _SetTo() _kern_close(dirFD); } // set close on exec flag on dir FD fcntl(fDirFd, F_SETFD, FD_CLOEXEC); return B_OK; }
/*! Tests if there is an executable file at the provided path. It will also test if the file has a valid ELF header or is a shell script. Even if the runtime loader does not need to be able to deal with both types, the caller will give scripts a proper treatment. */ status_t test_executable(const char *name, char *invoker) { char path[B_PATH_NAME_LENGTH]; char buffer[B_FILE_NAME_LENGTH]; // must be large enough to hold the ELF header status_t status; ssize_t length; int fd; if (name == NULL) return B_BAD_VALUE; strlcpy(path, name, sizeof(path)); fd = open_executable(path, B_APP_IMAGE, NULL, NULL, NULL); if (fd < B_OK) return fd; // see if it's executable at all status = _kern_access(-1, path, X_OK, false); if (status != B_OK) goto out; // read and verify the ELF header length = _kern_read(fd, 0, buffer, sizeof(buffer)); if (length < 0) { status = length; goto out; } status = elf_verify_header(buffer, length); if (status == B_NOT_AN_EXECUTABLE) { // test for shell scripts if (!strncmp(buffer, "#!", 2)) { char *end; buffer[min_c((size_t)length, sizeof(buffer) - 1)] = '\0'; end = strchr(buffer, '\n'); if (end == NULL) { status = E2BIG; goto out; } else end[0] = '\0'; if (invoker) strcpy(invoker, buffer + 2); status = B_OK; } } else if (status == B_OK) { elf_ehdr *elfHeader = (elf_ehdr *)buffer; if (elfHeader->e_entry == 0) { // we don't like to open shared libraries status = B_NOT_AN_EXECUTABLE; } else if (invoker) invoker[0] = '\0'; } out: _kern_close(fd); return status; }
static fssh_status_t command_mv(int argc, const char* const* argv) { bool force = 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 'f': force = true; break; default: fprintf(stderr, "Error: Unknown option \"-%c\"\n", arg[i]); return FSSH_B_BAD_VALUE; } } } // check params int count = argc - 1 - argi; if (count <= 0) { fprintf(stderr, "Usage: %s [-f] <file>... <target>\n", argv[0]); return FSSH_B_BAD_VALUE; } const char* target = argv[argc - 1]; // stat the target struct fssh_stat st; fssh_status_t status = _kern_read_stat(-1, target, true, &st, sizeof(st)); if (status != FSSH_B_OK && count != 1) { fprintf(stderr, "Error: Failed to stat target \"%s\": %s\n", target, fssh_strerror(status)); return status; } if (status == FSSH_B_OK && FSSH_S_ISDIR(st.fssh_st_mode)) { // move several entries int targetDir = _kern_open_dir(-1, target); if (targetDir < 0) { fprintf(stderr, "Error: Failed to open dir \"%s\": %s\n", target, fssh_strerror(targetDir)); return targetDir; } // move loop for (; argi < argc - 1; argi++) { status = move_entry(-1, argv[argi], targetDir, argv[argi], force); if (status != FSSH_B_OK) { _kern_close(targetDir); return status; } } _kern_close(targetDir); return FSSH_B_OK; } // rename single entry return move_entry(-1, argv[argi], -1, target, force); }
status_t load_image(char const* name, image_type type, const char* rpath, const char* requestingObjectPath, image_t** _image) { int32 pheaderSize, sheaderSize; char path[PATH_MAX]; ssize_t length; char pheaderBuffer[4096]; int32 numRegions; image_t* found; image_t* image; status_t status; int fd; elf_ehdr eheader; // Have we already loaded that image? Don't check for add-ons -- we always // reload them. if (type != B_ADD_ON_IMAGE) { found = find_loaded_image_by_name(name, APP_OR_LIBRARY_TYPE); if (found == NULL && type != B_APP_IMAGE && gProgramImage != NULL) { // Special case for add-ons that link against the application // executable, with the executable not having a soname set. if (const char* lastSlash = strrchr(name, '/')) { if (strcmp(gProgramImage->name, lastSlash + 1) == 0) found = gProgramImage; } } if (found) { atomic_add(&found->ref_count, 1); *_image = found; KTRACE("rld: load_container(\"%s\", type: %d, rpath: \"%s\") " "already loaded", name, type, rpath); return B_OK; } } KTRACE("rld: load_container(\"%s\", type: %d, rpath: \"%s\")", name, type, rpath); strlcpy(path, name, sizeof(path)); // find and open the file fd = open_executable(path, type, rpath, get_program_path(), requestingObjectPath, sSearchPathSubDir); if (fd < 0) { FATAL("Cannot open file %s: %s\n", name, strerror(fd)); KTRACE("rld: load_container(\"%s\"): failed to open file", name); return fd; } // normalize the image path status = _kern_normalize_path(path, true, path); if (status != B_OK) goto err1; // Test again if this image has been registered already - this time, // we can check the full path, not just its name as noted. // You could end up loading an image twice with symbolic links, else. if (type != B_ADD_ON_IMAGE) { found = find_loaded_image_by_name(path, APP_OR_LIBRARY_TYPE); if (found) { atomic_add(&found->ref_count, 1); *_image = found; _kern_close(fd); KTRACE("rld: load_container(\"%s\"): already loaded after all", name); return B_OK; } } length = _kern_read(fd, 0, &eheader, sizeof(eheader)); if (length != sizeof(eheader)) { status = B_NOT_AN_EXECUTABLE; FATAL("%s: Troubles reading ELF header\n", path); goto err1; } status = parse_elf_header(&eheader, &pheaderSize, &sheaderSize); if (status < B_OK) { FATAL("%s: Incorrect ELF header\n", path); goto err1; } // ToDo: what to do about this restriction?? if (pheaderSize > (int)sizeof(pheaderBuffer)) { FATAL("%s: Cannot handle program headers bigger than %lu\n", path, sizeof(pheaderBuffer)); status = B_UNSUPPORTED; goto err1; } length = _kern_read(fd, eheader.e_phoff, pheaderBuffer, pheaderSize); if (length != pheaderSize) { FATAL("%s: Could not read program headers: %s\n", path, strerror(length)); status = B_BAD_DATA; goto err1; } numRegions = count_regions(path, pheaderBuffer, eheader.e_phnum, eheader.e_phentsize); if (numRegions <= 0) { FATAL("%s: Troubles parsing Program headers, numRegions = %" B_PRId32 "\n", path, numRegions); status = B_BAD_DATA; goto err1; } image = create_image(name, path, numRegions); if (image == NULL) { FATAL("%s: Failed to allocate image_t object\n", path); status = B_NO_MEMORY; goto err1; } status = parse_program_headers(image, pheaderBuffer, eheader.e_phnum, eheader.e_phentsize); if (status < B_OK) goto err2; if (!assert_dynamic_loadable(image)) { FATAL("%s: Dynamic segment must be loadable (implementation " "restriction)\n", image->path); status = B_UNSUPPORTED; goto err2; } status = map_image(fd, path, image, eheader.e_type == ET_EXEC); if (status < B_OK) { FATAL("%s: Could not map image: %s\n", image->path, strerror(status)); status = B_ERROR; goto err2; } if (!parse_dynamic_segment(image)) { FATAL("%s: Troubles handling dynamic section\n", image->path); status = B_BAD_DATA; goto err3; } if (eheader.e_entry != 0) image->entry_point = eheader.e_entry + image->regions[0].delta; analyze_image_haiku_version_and_abi(fd, image, eheader, sheaderSize, pheaderBuffer, sizeof(pheaderBuffer)); // If this is the executable image, we init the search path // subdir, if the compiler version doesn't match ours. if (type == B_APP_IMAGE) { #if __GNUC__ == 2 if ((image->abi & B_HAIKU_ABI_MAJOR) == B_HAIKU_ABI_GCC_4) sSearchPathSubDir = "x86"; #elif __GNUC__ >= 4 if ((image->abi & B_HAIKU_ABI_MAJOR) == B_HAIKU_ABI_GCC_2) sSearchPathSubDir = "x86_gcc2"; #endif } set_abi_version(image->abi); // init gcc version dependent image flags // symbol resolution strategy if (image->abi == B_HAIKU_ABI_GCC_2_ANCIENT) image->find_undefined_symbol = find_undefined_symbol_beos; // init version infos status = init_image_version_infos(image); image->type = type; register_image(image, fd, path); image_event(image, IMAGE_EVENT_LOADED); _kern_close(fd); enqueue_loaded_image(image); *_image = image; KTRACE("rld: load_container(\"%s\"): done: id: %" B_PRId32 " (ABI: %#" B_PRIx32 ")", name, image->id, image->abi); return B_OK; err3: unmap_image(image); err2: delete_image_struct(image); err1: _kern_close(fd); KTRACE("rld: load_container(\"%s\"): failed: %s", name, strerror(status)); return status; }