/* * This file implements the Inode object and associated inode operations. Most * of the functions here are just wrappers for the file system specific inode * operations. They generally check if the operation exists and use it if it * does. If one does not exist, a function may implement a generic action, or * just simply return. They also perform the necessary validation to ensure the * operation can be called on the particular inode. */ #include #include #include #include #include #include #include static void inode_new(Object *); static void inode_delete(Object *); static void inode_copy(Object *, Object *); /* Inode object type */ ObjectType inodeType = { .name = "INODE", .size = sizeof(Inode), .new = inode_new, .delete = inode_delete, .copy = inode_copy, }; /* Create a new Inode */ static void inode_new(Object *obj) { Inode *inode = (void *) obj; inode->dirEntries = create_list(&dirEntryType, LIST_NORMAL); inode->pages = create_list(&pageType, LIST_NORMAL); } /* Destroy an Inode */ static void inode_delete(Object *obj) { Inode *inode = (void *) obj; /* Remove inode from the SuperBlock's list */ if (inode->super) { remove(inode->super->inodes, inode); put(inode->super); } /* Clean cache */ destroy_list(inode->pages); } /* Copy an Inode */ static void inode_copy(Object *a, Object *b) { Inode *parent = (void *) a, *child = (void *) b; child->ino = parent->ino; child->uid = parent->uid; child->gid = parent->gid; child->mode = parent->mode; child->nlink = parent->nlink; child->size = parent->size; child->dev = parent->dev; child->ops = parent->ops; child->fileOps = parent->fileOps; if (parent->super) child->super = get(parent->super); if (parent->dirEntries) child->dirEntries = copy_list(parent->dirEntries); if (parent->pages) child->pages = copy_list(parent->pages); } /* Check if a process has permission to access an inode */ int permission(Inode *inode, int mask) { if (!inode) return 0; int mode = inode->mode; if (current->euid == inode->uid) mode >>= 6; else if (current->egid == inode->gid) mode >>= 3; if (((mode & mask & 0007) == mask) || super_user()) return 1; return 0; } /* Create an inode wrapper */ int inode_create(Inode *inode, DirEntry *entry, mode_t mode) { if (!inode->ops || !inode->ops->create) return -EINVAL; lock(inode); int err = inode->ops->create(inode, entry, mode); if (!err) { add(inode->dirEntries, entry); entry->inode = super_alloc_inode(inode->super); entry->inode->mode = mode | S_IFREG; } unlock(inode); return err; } /* Find a named entry in a directory inode */ DirEntry * inode_lookup(Inode *inode, const char *name) { if (!S_ISDIR(inode->mode)) return NULL; lock(inode); /* Check cache first */ DirEntry *entry = find_direntry(inode->dirEntries, name); if (entry) { get(entry); if (entry->inode) goto end; } /* Try file system lookup */ if (!inode->ops || !inode->ops->lookup) { entry = NULL; goto end; } Inode *child = inode->ops->lookup(inode, name); /* The file doesn't exist */ if (!child) { if (entry) { remove(inode->dirEntries, entry); put(entry); } entry = NULL; goto end; } /* Fill in DirEntry */ if (!entry) { entry = new(&dirEntryType); strncpy(entry->name, name, NAME_MAX); entry->super = inode->super; add(inode->dirEntries, entry); } entry->inode = get(child); end: unlock(inode); return entry; } /* Make a directory wrapper */ int inode_mkdir(Inode *inode, DirEntry *entry, mode_t mode) { if (!inode->ops || !inode->ops->mkdir) return -EINVAL; lock(inode); int err = inode->ops->mkdir(inode, entry, mode); if (!err) { add(inode->dirEntries, entry); entry->inode = super_alloc_inode(inode->super); entry->inode->mode = mode | S_IFDIR; } unlock(inode); return err; } /* Remove a directory wrapper */ int inode_rmdir(Inode *inode, DirEntry *entry) { if (!inode->ops || !inode->ops->mkdir) return -EINVAL; lock(inode); int err = inode->ops->rmdir(inode, entry); if (!err) remove(inode->dirEntries, entry); unlock(inode); return err; } /* Make a special node wrapper */ int inode_mknod(Inode *inode, DirEntry *entry, mode_t mode, dev_t dev) { if (!inode->ops || !inode->ops->mknod) return -EINVAL; lock(inode); int err = inode->ops->mknod(inode, entry, mode, dev); if (!err) { add(inode->dirEntries, entry); entry->inode = super_alloc_inode(inode->super); entry->inode->mode = mode; entry->inode->dev = dev; } unlock(inode); return err; }