int sys_stat(char *f, struct stat *statbuf, bool lin) { if(!f || !statbuf) return -EINVAL; struct inode *i; int res; i = (struct inode *) (lin ? fs_path_resolve_inode(f, RESOLVE_NOLINK, &res) : fs_path_resolve_inode(f, 0, &res)); if(!i) return res; do_stat(i, statbuf); vfs_icache_put(i); return 0; }
int fs_filesystem_init_mount(struct filesystem *fs, char *point, char *node, char *type, int opts) { if(type) strncpy(fs->type, type, 128); fs->opts = opts; fs->pointname = kmalloc(strlen(point) + 1); strncpy(fs->pointname, point, strlen(point)); if(!strcmp(fs->type, "devfs") || !strcmp(fs->type, "tmpfs")) { fs->nodename = kmalloc(strlen(fs->type) + 1); strncpy(fs->nodename, fs->type, strlen(fs->type)); if(fs->type[0] == 'd') return 0; } else { fs->nodename = kmalloc(strlen(node) + 1); strncpy(fs->nodename, node, strlen(node)); } int err; struct inode *i = fs_path_resolve_inode(node, 0, &err); if(!i) return err; fs->dev = i->phys_dev; fs->node = i; if(!strcmp(fs->type, "tmpfs")) return ramfs_mount(fs); struct fsdriver *fd = 0; if(type) { if((fd = hash_lookup(&fsdrivershash, type, strlen(type))) == NULL) return -EINVAL; fs->driver = fd; return fd->mount(fs); } else { if(linkedlist_find(&fsdriverslist, __fs_init_mount_find_driver, fs)) return 0; } return -EINVAL; }
/* This is possibly the lengthiest function in the VFS (possibly in the entire kernel!). * It resolves a path until the last name in the path string, and then tries to create * a new file with that name. It requires a lot of in-sequence checks for permission, * existance, is-a-directory, and so forth. */ struct inode *fs_path_resolve_create_get(const char *path, int flags, mode_t mode, int *result, struct dirent **dirent) { // Step 1: Split the path up into directory to create in, and name of new file. int len = strlen(path) + 1; char tmp[len]; memcpy(tmp, path, len); char *del = strrchr(tmp, '/'); if(del) *del = 0; char *dirpath = del ? tmp : "."; char *name = del ? del + 1 : tmp; if(dirpath[0] == 0) dirpath = "/"; if(dirent) *dirent = 0; if(result) *result = 0; // Step 2: Resolve the target directory. struct inode *dir = fs_path_resolve_inode(dirpath, flags, result); if(!dir) return 0; if(!S_ISDIR(dir->mode)) { if(result) *result = -ENOTDIR; return 0; } // Step 3: Try to look up the file that we're trying to create. struct dirent *test = fs_dirent_lookup(dir, name, strlen(name)); if(test) { // If it was found, return it and its inode. if(dirent) *dirent = test; struct inode *ret = fs_dirent_readinode(test, true); if(ret) ret = fs_resolve_mount(ret); if(!ret) { if(dirent) *dirent = 0; if(result) *result = -EIO; vfs_dirent_release(test); } else { if(!dirent) vfs_dirent_release(test); if(result) *result = 0; } vfs_icache_put(dir); return ret; } // Didn't find the entry. Step 4: Create one. if(!vfs_inode_check_permissions(dir, MAY_WRITE, 0)) { if(result) *result = -EACCES; vfs_icache_put(dir); return 0; } if(dir->nlink == 1) { if(result) *result = -ENOSPC; vfs_icache_put(dir); return 0; } uint32_t id; // Step 4a: Allocate an inode. int r = fs_callback_fs_alloc_inode(dir->filesystem, &id); if(r) { if(result) *result = r; vfs_icache_put(dir); return 0; } // Step 4b: Read in that inode, and set some initial values (like creation time). struct inode *node = vfs_icache_get(dir->filesystem, id); if(!node) { vfs_icache_put(dir); if(result) *result = -EIO; return 0; } node->mode = mode; node->length = 0; node->ctime = node->mtime = time_get_epoch(); vfs_inode_set_dirty(node); // If we're making a directory, create the . and .. entries. if(S_ISDIR(mode)) { // Create . and .. if(fs_link(node, node, ".", 1, true)) r = -EPERM; if(fs_link(node, dir, "..", 2, true)) r = -EMLINK; } // Step 4c: Create the link for the directory entry to the inode. r = fs_link(dir, node, name, strlen(name), false); if(result) *result = !r ? 1 : r; if(dirent && !r) { *dirent = fs_dirent_lookup(dir, name, strlen(name)); if(!*dirent && node) { vfs_icache_put(node); vfs_icache_put(dir); if(result) *result = -EIO; return 0; } } vfs_icache_put(dir); return r ? 0 : node; }