static int testfs_checkfs(struct super_block *sb, struct bitmap *i_freemap, struct bitmap *b_freemap, int inode_nr) { struct inode *in = testfs_get_inode(sb, inode_nr); int size; int size_roundup = ROUNDUP(testfs_inode_get_size(in), BLOCK_SIZE); assert((testfs_inode_get_type(in) == I_FILE) || (testfs_inode_get_type(in) == I_DIR)); /* inode processing */ bitmap_mark(i_freemap, inode_nr); if (testfs_inode_get_type(in) == I_DIR) { int offset = 0; struct dirent *d; for (; (d = testfs_next_dirent(in, &offset)); free(d)) { if ((d->d_inode_nr < 0) || (strcmp(D_NAME(d), ".") == 0) || (strcmp(D_NAME(d), "..") == 0)) continue; testfs_checkfs(sb, i_freemap, b_freemap, d->d_inode_nr); } } /* block processing */ size = testfs_check_inode(sb, b_freemap, in); assert(size == size_roundup); testfs_put_inode(in); return 0; }
/* return 0 on success. * return negative value on error. */ static int testfs_add_dirent(struct inode *dir, char *name, int inode_nr) { struct dirent *d; int p_offset = 0, offset = 0; int found = 0; int ret = 0; int len = strlen(name) + 1; fslice_name(name, len); assert(dir); assert(testfs_inode_get_type(dir) == I_DIR); assert(name); for (; ret == 0 && found == 0; free(d)) { p_offset = offset; if ((d = testfs_next_dirent(dir, &offset)) == NULL) break; if ((d->d_inode_nr >= 0) && (strcmp(D_NAME(d), name) == 0)) { ret = -EEXIST; continue; } if ((d->d_inode_nr >= 0) || (d->d_name_len != len)) continue; found = 1; } if (ret < 0) return ret; assert(found || (p_offset == testfs_inode_get_size(dir))); return testfs_write_dirent(dir, name, len, inode_nr, p_offset); }
/* allocates memory, caller should free */ struct dirent * testfs_next_dirent(struct inode *dir, int *offset) { int ret; struct dirent d, *dp; assert(dir); assert(testfs_inode_get_type(dir) == I_DIR); if (*offset >= testfs_inode_get_size(dir)) return NULL; ret = testfs_read_data(dir, *offset, (char *)&d, sizeof(struct dirent)); if (ret < 0) return NULL; assert(d.d_name_len > 0); dp = malloc(sizeof(struct dirent) + d.d_name_len); if (!dp) return NULL; *dp = d; *offset += sizeof(struct dirent); ret = testfs_read_data(dir, *offset, D_NAME(dp), d.d_name_len); if (ret < 0) { free(dp); return NULL; } *offset += d.d_name_len; return dp; }
int cmd_write(struct super_block *sb, struct context *c) { int inode_nr; struct inode *in; int size; int ret = 0; char * filename = c->cmd[1]; char * content = c->cmd[2]; if (c->nargs != 3) { return -EINVAL; } inode_nr = testfs_dir_name_to_inode_nr(c->cur_dir, filename); if (inode_nr < 0) return inode_nr; in = testfs_get_inode(sb, inode_nr); if (testfs_inode_get_type(in) == I_DIR) { ret = -EISDIR; goto out; } size = strlen(content); testfs_tx_start(sb, TX_WRITE); ret = testfs_write_data(in, 0, content, size); if (ret >= 0) { testfs_truncate_data(in, size); } testfs_sync_inode(in); testfs_tx_commit(sb, TX_WRITE); out: testfs_put_inode(in); return ret; }
static int testfs_ls(struct inode *in, int recursive) { int offset = 0; struct dirent *d; for (; (d = testfs_next_dirent(in, &offset)); free(d)) { struct inode *cin; if (d->d_inode_nr < 0) continue; cin = testfs_get_inode(testfs_inode_get_sb(in), d->d_inode_nr); printf("%s%s\n", D_NAME(d), (testfs_inode_get_type(cin) == I_DIR) ? "/":""); if (recursive && testfs_inode_get_type(cin) == I_DIR && (strcmp(D_NAME(d), ".") != 0) && (strcmp(D_NAME(d), "..") != 0)) { testfs_ls(cin, recursive); } testfs_put_inode(cin); } return 0; }
/* returns dirent associated with inode_nr in dir. * returns NULL on error. * allocates memory, caller should free. */ static struct dirent * testfs_find_dirent(struct inode *dir, int inode_nr) { struct dirent *d; int offset = 0; assert(dir); assert(testfs_inode_get_type(dir) == I_DIR); assert(inode_nr >= 0); for (; (d = testfs_next_dirent(dir, &offset)); free(d)) { if (d->d_inode_nr == inode_nr) return d; } return NULL; }
static int testfs_create_empty_dir(struct super_block *sb, int p_inode_nr, struct inode *cdir) { int ret; assert(testfs_inode_get_type(cdir) == I_DIR); ret = testfs_add_dirent(cdir, ".", testfs_inode_get_nr(cdir)); if (ret < 0) return ret; ret = testfs_add_dirent(cdir, "..", p_inode_nr); if (ret < 0) { testfs_remove_dirent(sb, cdir, "."); return ret; } return 0; }
/* returns negative value if name is not found */ int testfs_dir_name_to_inode_nr(struct inode *dir, char *name) { struct dirent *d; int offset = 0; int ret = -ENOENT; assert(dir); assert(name); assert(testfs_inode_get_type(dir) == I_DIR); for (; ret < 0 && (d = testfs_next_dirent(dir, &offset)); free(d)) { if ((d->d_inode_nr < 0) || (strcmp(D_NAME(d), name) != 0)) continue; ret = d->d_inode_nr; } return ret; }
int cmd_cat(struct super_block *sb, struct context *c) { char *buf; int inode_nr; struct inode *in; int ret = 0; int sz; int i; if (c->nargs < 2) { return -EINVAL; } for (i = 1; ret == 0 && i < c->nargs; i++ ) { inode_nr = testfs_dir_name_to_inode_nr(c->cur_dir, c->cmd[i]); if (inode_nr < 0) return inode_nr; in = testfs_get_inode(sb, inode_nr); if (testfs_inode_get_type(in) == I_DIR) { ret = -EISDIR; goto out; } sz = testfs_inode_get_size(in); if (sz > 0) { buf = malloc(sz + 1); if (!buf) { ret = -ENOMEM; goto out; } testfs_read_data(in, 0, buf, sz); buf[sz] = 0; printf("%s\n", buf); free(buf); } out: testfs_put_inode(in); } return ret; }
int cmd_cd(struct super_block *sb, struct context *c) { int inode_nr; struct inode *dir_inode; if (c->nargs != 2) { return -EINVAL; } inode_nr = testfs_dir_name_to_inode_nr(c->cur_dir, c->cmd[1]); if (inode_nr < 0) return inode_nr; dir_inode = testfs_get_inode(sb, inode_nr); if (testfs_inode_get_type(dir_inode) != I_DIR) { testfs_put_inode(dir_inode); return -ENOTDIR; } testfs_put_inode(c->cur_dir); c->cur_dir = dir_inode; return 0; }
/* returns negative value if name within dir is not empty */ static int testfs_remove_dirent_allowed(struct super_block *sb, int inode_nr) { struct inode *dir; int offset = 0; struct dirent *d; int ret = 0; dir = testfs_get_inode(sb, inode_nr); if (testfs_inode_get_type(dir) != I_DIR) goto out; for (; ret == 0 && (d = testfs_next_dirent(dir, &offset)); free(d)) { if ((d->d_inode_nr < 0) || (strcmp(D_NAME(d), ".") == 0) || (strcmp(D_NAME(d), "..") == 0)) continue; ret = -ENOTEMPTY; } out: testfs_put_inode(dir); return ret; }
int cmd_stat(struct super_block *sb, struct context *c) { int inode_nr; struct inode *in; int i; if (c->nargs < 2) { return -EINVAL; } for (i = 1; i < c->nargs; i++ ) { inode_nr = testfs_dir_name_to_inode_nr(c->cur_dir, c->cmd[i]); if (inode_nr < 0) return inode_nr; in = testfs_get_inode(sb, inode_nr); printf("%s: i_nr = %d, i_type = %d, i_size = %d\n", c->cmd[i], testfs_inode_get_nr(in), testfs_inode_get_type(in), testfs_inode_get_size(in)); testfs_put_inode(in); } return 0; }