/* * This file contains the open system call. It handles creating missing files, * and installing the file descriptor. Most of the actual code to find the * inode by name is in the lookup() routine. */ #include #include #include #include #include #include #include #include #include #include "namespace.h" /* Lookup a file path */ Inode * lookup(const char *path, ObjectList *newcustody) { if (!current->fs->root) return NULL; char buf[PATH_MAX], *p = buf; strncpy(buf, path, PATH_MAX); Inode *inode; DirEntry *entry = NULL; ObjectList *custody; /* Resolve to absolute/relative root */ if (*p == '/') { inode = get(current->fs->root); while (*++p == '/'); custody = create_list(&dirEntryType, LIST_NORMAL); } else { inode = get(current->fs->cwd); custody = copy_list(current->fs->cwdPath); } /* Drop through directories */ char *curr, *prev = p; for (curr = p; *curr; curr++) { if (*curr != '/') continue; *curr = '\0'; /* Path part */ if (!strcmp(prev, ".")) { entry = NULL; } else if (!strcmp(prev, "..")) { entry = NULL; if (inode != current->fs->root) { entry = pop_from_end(custody); if (!entry) swap_ref(inode, current->fs->root); else put(entry); } } else { entry = inode_lookup(inode, prev); if (!entry) { swap_ref(inode, NULL); goto end; } add(custody, entry); put(entry); } if (entry) swap_ref(inode, entry->inode); while (*++curr == '/'); prev = curr; } /* Base name */ if (!strcmp(prev, ".") || !strcmp(prev, "")) { if (!S_ISDIR(inode->mode)) { swap_ref(inode, NULL); swap_ref(entry, NULL); } } else if (!strcmp(prev, "..")) { if (inode != current->fs->root) { entry = pop_from_end(custody); if (!entry) swap_ref(inode, current->fs->root); else put(entry); } } else { entry = inode_lookup(inode, prev); if (!entry) { entry = new(&dirEntryType); strncpy(entry->name, prev, NAME_MAX); entry->super = inode->super; } add(custody, entry); put(entry); } if (entry) swap_ref(inode, entry->inode); /* Copy path */ if (newcustody) concat_list(custody, newcustody); end: destroy_list(custody); return inode; } /* Open a file */ int open(const char *name, int flags, ...) { if (!name) return -EFAULT; if (!verify_access(name, strnlen(name, PATH_MAX), PROT_READ)) return -EFAULT; /* Allocate a file descriptor */ int fd = allocate_fd(); if (fd < 0) return -EMFILE; /* Find inode */ ObjectList *custody = create_list(&dirEntryType, LIST_NORMAL); Inode *inode = lookup(name, custody); DirEntry *entry; va_list args; if (!inode) { if (!(flags & O_CREATE)) { destroy_list(custody); return -ENOENT; } /* Create file */ if (!count(custody)) { destroy_list(custody); return -ENOENT; } entry = get_nth_item(custody, count(custody) - 2); if (entry) inode = entry->inode; else inode = current->fs->root; if (!permission(inode, PROT_WRITE)) { destroy_list(custody); return -EACCES; } va_start(args, flags); inode_create(inode, get_nth_item(custody, count(custody) - 1), va_arg(args, mode_t)); inode = lookup(name, NULL); va_end(args); } /* Check permissions */ int perm = 0; if ((flags & O_ACCMODE) == O_RDONLY) perm = PROT_READ; else if ((flags & O_ACCMODE) == O_WRONLY) perm = PROT_WRITE; else if ((flags & O_ACCMODE) == O_RDWR) perm = PROT_READ | PROT_WRITE; if (!permission(inode, perm)) { put(inode); destroy_list(custody); return -EACCES; } /* Open file */ File *file = new(&fileType); file->inode = get(inode); file->flags = flags; file->ops = inode->fileOps; file->path = custody; int err = file_open(file); if (err) { put(file); put(inode); return err; } install_fd(fd, file); put(inode); return fd; } /* Make a directory */ int mkdir(const char *pathname, mode_t mode) { if (!pathname) return -EFAULT; if (!verify_access(pathname, strnlen(pathname, PATH_MAX), PROT_READ)) return -EFAULT; int err; ObjectList *custody = create_list(&dirEntryType, LIST_NORMAL); Inode *inode = lookup(pathname, custody); if (inode) { err = -EEXIST; goto end; } if (!count(custody)) { err = -ENOENT; goto end; } /* Check write permission */ DirEntry *entry = get_nth_item(custody, count(custody) - 2); if (entry) inode = entry->inode; else inode = current->fs->root; if (!permission(inode, PROT_WRITE)) { err = -EACCES; goto end; } /* Create directory */ err = inode_mkdir(inode, get_nth_item(custody, count(custody) - 1), mode); end: destroy_list(custody); return err; } /* Make a special node */ int mknod(const char *pathname, mode_t mode, dev_t dev) { if (!pathname) return -EFAULT; if (!verify_access(pathname, strnlen(pathname, PATH_MAX), PROT_READ)) return -EFAULT; int err; ObjectList *custody = create_list(&dirEntryType, LIST_NORMAL); Inode *inode = lookup(pathname, custody); if (inode) { err = -EEXIST; goto end; } if (!count(custody)) { err = -ENOENT; goto end; } /* Check write permission */ DirEntry *entry = get_nth_item(custody, count(custody) - 2); if (entry) inode = entry->inode; else inode = current->fs->root; if (!permission(inode, PROT_WRITE)) { err = -EACCES; goto end; } /* Create node */ err = inode_mknod(inode, get_nth_item(custody, count(custody) - 1), mode, dev); end: destroy_list(custody); return err; }