struct inode *FS_lookup(struct inode *dir, char *name) { struct dir_entry *de; int ret = FS_lookup_internal(dir, name); if (ret == -1) return 0; de = Directory_entry(dir, ret); return fetch_inode(de->inum); }
struct inode *FS_fhandle_to_inode(fhandle *fh) { struct inode *ret; struct nfs_fhandle *nfh = (struct nfs_fhandle *)fh; /* Check bounds */ if (nfh->inum < 0 || nfh->inum >= fs->num_inodes) { /* Stale file handle */ return 0; } ret = fetch_inode(nfh->inum); if (nfh->generation != gen(ret)) { /* Stale file handle */ return 0; } return ret; }
int read_inode(struct inode *i_node, struct dir_extent *extent, size_t offset, size_t *new_offset) { struct iso9660_dir_record *dir_rec; struct buf *bp; /* Find inode. */ bp = fetch_inode(extent, &offset); if (bp == NULL) return EOF; dir_rec = (struct iso9660_dir_record*)(b_data(bp) + offset % v_pri.logical_block_size_l); /* Parse basic ISO 9660 specs. */ if (check_dir_record(dir_rec, offset % v_pri.logical_block_size_l) != OK) { lmfs_put_block(bp, FULL_DATA_BLOCK); return EINVAL; } memset(&i_node->i_stat, 0, sizeof(struct stat)); i_node->i_stat.st_ino = get_extent_absolute_block_id(extent, offset / v_pri.logical_block_size_l) * v_pri.logical_block_size_l + offset % v_pri.logical_block_size_l; read_inode_iso9660(i_node, dir_rec); /* Parse extensions. */ read_inode_susp(i_node, dir_rec, bp, offset % v_pri.logical_block_size_l); offset += dir_rec->length; read_inode_extents(i_node, dir_rec, extent, &offset); lmfs_put_block(bp, FULL_DATA_BLOCK); if (new_offset != NULL) *new_offset = offset; return OK; }
nfsstat FS_unlink(struct inode *dir, char *name, int remove_dir) { struct inode *child; int child_num; int child_inum; struct dir_entry *d1, *d2; int refcnt; assert(dir->attr.type == NFDIR); if (strlen(name) > MAX_NAME_LEN) { return NFSERR_NAMETOOLONG; } child_num = FS_lookup_internal(dir, name); if (child_num == -1) { return NFSERR_NOENT; } child_inum = Directory_entry(dir, child_num)->inum; child = fetch_inode(child_inum); if (!remove_dir && child->attr.type == NFDIR) { return NFSERR_ISDIR; } if (remove_dir && child->attr.type != NFDIR) { return NFSERR_NOTDIR; } if (!strcmp(name, ".") || !strcmp(name, "..")) { return NFSERR_ACCES; } #if 0 /* TODO: Need to check acces control */ if (~write_access ()) { return (NFSERR_PERM); } #endif if (remove_dir && child->attr.size != 2 && child->attr.nlink == 2) { return NFSERR_NOTEMPTY; } d1 = Directory_entry(dir, child_num); d2 = Directory_entry(dir, dir->attr.size-1); if (d1 != d2) { Byz_modify2(d1, sizeof(struct dir_entry)); bcopy((char*)d2, (char*)d1, sizeof(struct dir_entry)); } Byz_modify2(&(dir->attr), sizeof(dir->attr)); dir->attr.size--; if (dir->attr.blocks > 0) { if (dir->attr.size <= NUM_INLINE_DIR_ENTRIES) { /* Can free first indirect block */ FS_free_block(fetch_block(dir_block(dir))); dir_block(dir) = -1; dir->attr.blocks = 0; } else { if (dir->attr.blocks > 1 && dir->attr.size <= NUM_INLINE_DIR_ENTRIES+NUM_INDIRECT_DIR_ENTRIES) { /* Can free second indirect block */ FS_free_block(fetch_block(dir_block1(dir))); dir_block1(dir) = -1; dir->attr.blocks = 1; } } } dir->attr.ctime.seconds = cur_time.tv_sec; dir->attr.ctime.useconds = cur_time.tv_usec; dir->attr.mtime = dir->attr.ctime; Byz_modify2(&(child->attr), sizeof(child->attr)); refcnt = decr_refcnt(child); if (refcnt == 0) { /* Free child and its associated storage */ if (child->attr.type == NFREG) FS_truncate(child, 0); FS_free_inode(child); return NFS_OK; } else { /* Update time of last status change for child */ child->attr.ctime = dir->attr.ctime; } /* If it is a directory "." points to self so refcnt == 1 means it can be removed. We checked for emptyness before. */ if (refcnt == 1 && child->attr.type == NFDIR) { /* Decrement reference count of parent */ struct inode *parent = FS_lookup(child, ".."); if (parent != dir) { Byz_modify1(&(parent->attr.nlink)); } decr_refcnt(parent); FS_free_inode(child); } return NFS_OK; }
void read_inode_extents(struct inode *i, const struct iso9660_dir_record *dir_rec, struct dir_extent *extent, size_t *offset) { struct buf *bp; struct iso9660_dir_record *extent_rec; struct dir_extent *cur_extent = i->extent; int done = FALSE; /* * No need to search extents if file is empty or has final directory * record flag set. */ if (cur_extent == NULL || ((dir_rec->file_flags & D_NOT_LAST_EXTENT) == 0)) return; while (!done) { bp = fetch_inode(extent, offset); if (bp == NULL) return; bp = read_extent_block(extent, *offset / v_pri.logical_block_size_l); extent_rec = (struct iso9660_dir_record*)(b_data(bp) + *offset % v_pri.logical_block_size_l); if (check_dir_record(dir_rec, *offset % v_pri.logical_block_size_l) != OK) { lmfs_put_block(bp, FULL_DATA_BLOCK); return; } /* Extent entries should share the same name. */ if ((dir_rec->length_file_id == extent_rec->length_file_id) && (memcmp(dir_rec->file_id, extent_rec->file_id, dir_rec->length_file_id) == 0)) { /* Add the extent at the end of the linked list. */ assert(cur_extent->next == NULL); cur_extent->next = alloc_extent(); cur_extent->next->location = dir_rec->loc_extent_l + dir_rec->ext_attr_rec_length; cur_extent->next->length = dir_rec->data_length_l / v_pri.logical_block_size_l; if (dir_rec->data_length_l % v_pri.logical_block_size_l) cur_extent->next->length++; i->i_stat.st_size += dir_rec->data_length_l; i->i_stat.st_blocks += cur_extent->next->length; cur_extent = cur_extent->next; *offset += extent_rec->length; } else done = TRUE; /* Check if not last extent bit is not set. */ if ((dir_rec->file_flags & D_NOT_LAST_EXTENT) == 0) done = TRUE; lmfs_put_block(bp, FULL_DATA_BLOCK); } }