void inode_free(FAR struct inode *node) { if (node) { inode_free(node->i_peer); inode_free(node->i_child); kfree(node); } }
Color ray_shade(int level, Real w, Ray v, RContext *rc, Object *ol) { Inode *i = ray_intersect(ol, v); if (i != NULL) { Light *l; Real wf; Material *m = i->m; Vector3 p = ray_point(v, i->t); Cone recv = cone_make(p, i->n, PIOVER2); Color c = c_mult(m->c, c_scale(m->ka, ambient(rc))); rc->p = p; for (l = rc->l; l != NULL; l = l->next) if ((*l->transport)(l, recv, rc) && (wf = shadow(l, p, ol)) > RAY_WF_MIN) c = c_add(c, c_mult(m->c, c_scale(wf * m->kd * v3_dot(l->outdir,i->n), l->outcol))); if (level++ < MAX_RAY_LEVEL) { if ((wf = w * m->ks) > RAY_WF_MIN) { Ray r = ray_make(p, reflect_dir(v.d, i->n)); c = c_add(c, c_mult(m->s, c_scale(m->ks, ray_shade(level, wf, r, rc, ol)))); } if ((wf = w * m->kt) > RAY_WF_MIN) { Ray t = ray_make(p, refract_dir(v.d, i->n, (i->enter)? 1/m->ir: m->ir)); if (v3_sqrnorm(t.d) > 0) { c = c_add(c, c_mult(m->s, c_scale(m->kt, ray_shade(level, wf, t, rc, ol)))); } } } inode_free(i); return c; } else { return BG_COLOR; } }
int inode_rm (super_block_t *sb, char *pathname) { // assert (sb != NULL); // assert (pathname != NULL); // assume parent exists int parent = inode_lookup_parent (sb, pathname); // assert (parent >= 0); // assume child exists, and it is an empty entry int child = inode_lookup_full (sb, pathname); // assert (child >= 0); // assert (inode_isdir_isempty (sb, child) || inode_isreg (sb, child)); // get dirname char buffer[MAX_FILE_SIZE]; int count = path_explode (pathname, buffer); char *p = path_get_component (buffer, count - 1); // search for parent dir dentry int index = inode_lookup_dentry (sb, parent, p); // remove it inode_remove_dentry (sb, parent, index); // chlid dir inode inode_free (sb, child); return 0; }
void inode_release(FAR struct inode *node) { if (node) { /* Decrement the references of the inode */ inode_semtake(); if (node->i_crefs) { node->i_crefs--; } /* If the subtree was previously deleted and the reference * count has decrement to zero, then delete the inode * now. */ if (node->i_crefs <= 0 && (node->i_flags & FSNODEFLAG_DELETED) != 0) { /* If the inode has been properly unlinked, then the peer pointer * should be NULL. */ inode_semgive(); DEBUGASSERT(node->i_peer == NULL); inode_free(node); } else { inode_semgive(); } } }
nfsstat4 nfs_op_lookupp(struct nfs_cxn *cxn, struct list_head *writes, struct rpc_write **wr) { nfsstat4 status = NFS4_OK; struct nfs_inode *ino = NULL; if (debugging) applog(LOG_INFO, "op LOOKUPP"); status = dir_curfh(NULL, cxn, &ino, 0); if (status != NFS4_OK) goto out; if (ino->inum == INO_ROOT) { /* root inode, no parents */ status = NFS4ERR_NOENT; goto out; } fh_set(&cxn->current_fh, ino->parent); out: WR32(status); inode_free(ino); return status; }
main(int argc, char **argv) { Prim *o; Color c; int u, v; Ray r; Inode *l; o = sphere_instance(&sphere_funcs); init_sdl(); s = scene_read(); init_render(); for (v = s->view->sc.ll.y; v < s->view->sc.ur.y; v += 1) { for (u = s->view->sc.ll.x; u < s->view->sc.ur.x; u += 1) { r = ray_unit(ray_transform(ray_view(u, v), mclip)); if ((l = ray_intersect(s->objs, r)) != NULL) c = point_tshade(ray_point(r, l->t), l->n, s->view->center, rc, l->m, o); else c = bgcolor; inode_free(l); img_putc(s->img, u, v, col_dpymap(c)); } } img_write(s->img,"stdout",0); exit(0); }
Inode* fs_load_inode(FileSystem *fs, int page_num) { int i = 0; Inode *inode = NULL; int magic_number = 0; for (i = 0; i < fs->ninode; ++i) { if (fs->inodes[i]->page_num == page_num) { return fs->inodes[i]; } } magic_number = storage_readint(fs->stor, page_num, CONTENT_BYTES_PER_PAGE); if (magic_number != INODE_MAGIC_NUMBER) { return NULL; } if (fs->ninode == INODE_NUM) { inode_free(&(fs->inodes[0])); fs->ninode--; for (i = 0; i < fs->ninode; ++i) { fs->inodes[i] = fs->inodes[i + 1]; } } fs->inodes[fs->ninode++] = inode = inode_new(page_num); inode->type = storage_readint(fs->stor, page_num, 0); inode->filesize = storage_readint(fs->stor, page_num, 4); inode->firstpage = storage_readint(fs->stor, page_num, 16); return inode; }
void mq_inode_release(FAR struct inode *inode) { /* Decrement the reference count on the inode */ inode_semtake(); if (inode->i_crefs > 0) { inode->i_crefs--; } /* If the message queue was previously unlinked and the reference count * has decremented to zero, then release the message queue and delete * the inode now. */ if (inode->i_crefs <= 0 && (inode->i_flags & FSNODEFLAG_DELETED) != 0) { FAR struct mqueue_inode_s *msgq = inode->u.i_mqueue; DEBUGASSERT(msgq); /* Free the message queue (and any messages left in it) */ mq_msgqfree(msgq); inode->u.i_mqueue = NULL; /* Release and free the inode container */ inode_semgive(); inode_free(inode->i_child); kmm_free(inode); return; } inode_semgive(); }
void inode_release(FAR struct inode *node) { if (node) { /* Decrement the references of the inode */ inode_semtake(); if (node->i_crefs) { node->i_crefs--; } /* If the subtree was previously deleted and the reference * count has decrement to zero, then delete the inode * now. */ if (node->i_crefs <= 0 && (node->i_flags & FSNODEFLAG_DELETED) != 0) { inode_semgive(); inode_free(node->i_child); kfree(node); } else { inode_semgive(); } } }
static void free_ext4_db(struct inode *inode) { struct db_handle *db_handle = inode->i_db; struct block_device *bdev = inode->i_sb->s_bdev; inode_free(inode); db_close(db_handle); bdev_free(bdev); fs_bh_showstat(); }
int inode_remove(FAR const char *path) { const char *name = path; FAR struct inode *node; FAR struct inode *left; FAR struct inode *parent; if (!*path || path[0] != '/') { return -EINVAL; } /* Find the node to delete */ node = inode_search(&name, &left, &parent, (const char **)NULL); if (node) { /* Found it, now remove it from the tree */ inode_unlink(node, left, parent); /* We cannot delete it if there reference to the inode */ if (node->i_crefs) { /* In that case, we will mark it deleted, when the FS * releases the inode, we will then, finally delete * the subtree. */ node->i_flags |= FSNODEFLAG_DELETED; return -EBUSY; } else { /* And delete it now -- recursively to delete all of its children */ inode_free(node->i_child); kfree(node); return OK; } } /* The node does not exist or it has references */ return -ENOENT; }
Real shadow(Light *l, Vector3 p, Object *ol) { Real t, kt; Inode *i; Vector3 d; if (l->type == LIGHT_AMBIENT) return 1.0; d = (l->type == LIGHT_DISTANT)? l->dir : v3_sub(l->loc, p); if ((i = ray_intersect(ol, ray_make(p, d))) == NULL) return 1.0; t = i->t; kt = i->m->kt; inode_free(i); if (l->type == LIGHT_DISTANT && t > RAY_EPS) return kt; else if (l->type != LIGHT_DISTANT && t > RAY_EPS && t < 1) return kt; else return 1.0; }
int inode_remove(FAR const char *path) { FAR struct inode *node; /* Find the inode and unlink it from the in-memory inode tree */ node = inode_unlink(path); if (node) { /* Found it! But we cannot delete the inode if there are references * to it */ if (node->i_crefs) { /* In that case, we will mark it deleted, when the filesystem * releases the inode, we will then, finally delete the subtree */ node->i_flags |= FSNODEFLAG_DELETED; return -EBUSY; } else { /* And delete it now -- recursively to delete all of its children. * Since it has been unlinked, then the peer pointer should be NULL. */ DEBUGASSERT(node->i_peer == NULL); inode_free(node); return OK; } } /* The node does not exist */ return -ENOENT; }
int fs_mkdir(FileSystem *fs, const char *d) { int p = 0; Inode *inode = NULL; Folder *fd = NULL; char ppath[4096] = ""; char cname[4096] = ""; Folder *pfd = NULL; int parent_page_num = 0; p = freelist_allocate(fs->freelist); if (p <= 1) return ERROR; inode = inode_new(p); if (!inode) return ERROR; inode->type = INODE_FOLDER; inode->filesize = 0; inode->lastmod = time(NULL); inode->firstpage = 0; fs_save_inode(fs, inode); inode_free(&inode); fs_split_path(d, ppath, cname); #ifdef DEBUG fprintf(stderr, "fs_mkdir, d=`%s`, ppath=`%s`, cname=`%s`\n", d, ppath, cname); #endif pfd = folder_open(fs, folder_lookup(fs, fs->cur, ppath)); parent_page_num = AS_FILE(pfd)->inode->page_num; folder_add_child(pfd, cname, p); folder_close(&pfd); fd = folder_open(fs, fs_load_inode(fs, p)); fs_split_path(d, ppath, cname); folder_add_child(fd, "", ROOT_PAGE_NUM()); folder_add_child(fd, ".", p); folder_add_child(fd, "..", parent_page_num); folder_close(&fd); return OK; }
int fs_create(FileSystem *fs, const char *f) { int p = 0; Inode *inode = NULL; char ppath[4096] = ""; char cname[4096] = ""; Folder *pfd = NULL; p = freelist_allocate(fs->freelist); if (p <= 1) return ERROR; inode = inode_new(p); if (!inode) return ERROR; inode->type = INODE_FILE; inode->filesize = 0; inode->firstpage = 0; fs_save_inode(fs, inode); inode_free(&inode); fs_split_path(f, ppath, cname); pfd = folder_open(fs, folder_lookup(fs, fs->cur, ppath)); folder_add_child(pfd, cname, p); folder_close(&pfd); return OK; }
nfsstat4 nfs_op_readdir(struct nfs_cxn *cxn, const READDIR4args *args, struct list_head *writes, struct rpc_write **wr) { nfsstat4 status = NFS4_OK; struct nfs_inode *ino = NULL; uint32_t dircount, maxcount, *status_p; struct readdir_info ri; uint64_t cookie, attr_request; const verifier4 *cookie_verf; DB_TXN *txn = NULL; DB *dirent = srv.fsdb.dirent; DB_ENV *dbenv = srv.fsdb.env; DBT pkey, pval; struct fsdb_de_key key; int cget_flags; DBC *curs = NULL; int rc; uint64_t dirent_inum, db_de; struct fsdb_de_key *rkey; cookie = args->cookie; cookie_verf = &args->cookieverf; dircount = args->dircount; maxcount = args->maxcount; attr_request = bitmap4_decode(&args->attr_request); status_p = WRSKIP(4); if (debugging) { applog(LOG_INFO, "op READDIR (COOKIE:%Lu DIR:%u MAX:%u MAP:%Lx)", (unsigned long long) cookie, dircount, maxcount, (unsigned long long) attr_request); print_fattr_bitmap("op READDIR", attr_request); } /* traditionally "." and "..", hardcoded */ if (cookie == 1 || cookie == 2) { status = NFS4ERR_BAD_COOKIE; goto out; } /* don't permit request of write-only attrib */ if (attr_request & fattr_write_only_mask) { status = NFS4ERR_INVAL; goto out; } /* FIXME: very, very, very poor verifier */ if (cookie && memcmp(cookie_verf, &srv.instance_verf, sizeof(verifier4))) { status = NFS4ERR_NOT_SAME; goto out; } /* read inode of directory being read */ status = dir_curfh(NULL, cxn, &ino, 0); if (status != NFS4_OK) goto out; if (ino->mode == 0) { status = NFS4ERR_ACCESS; goto out; } /* subtract READDIR4resok header and footer size */ if (maxcount < 16) { status = NFS4ERR_TOOSMALL; goto out; } maxcount -= (8 + 4 + 4); /* verify within server limits */ if (dircount > SRV_MAX_READ || maxcount > SRV_MAX_READ) { status = NFS4ERR_INVAL; goto out; } /* open transaction */ rc = dbenv->txn_begin(dbenv, NULL, &txn, 0); if (rc) { status = NFS4ERR_IO; dbenv->err(dbenv, rc, "DB_ENV->txn_begin"); goto out; } /* set up directory iteration */ memset(&ri, 0, sizeof(ri)); ri.cookie = cookie; ri.dircount = dircount; ri.maxcount = maxcount; ri.attr_request = attr_request; ri.status = NFS4_OK; ri.writes = writes; ri.wr = wr; ri.dir_pos = 3; ri.first_time = true; /* if dir is empty, skip directory interation loop completely */ if (dir_is_empty(txn, ino)) { WRMEM(&srv.instance_verf, sizeof(verifier4)); /* cookieverf */ ri.val_follows = WRSKIP(4); if (debugging) applog(LOG_DEBUG, " READDIR: empty directory"); goto the_finale; } /* otherwise, loop through each dirent attached to ino->inum */ rc = dirent->cursor(dirent, txn, &curs, 0); if (rc) { status = NFS4ERR_IO; dirent->err(dirent, rc, "dirent->cursor"); goto out_abort; } key.inum = inum_encode(ino->inum); memset(&pkey, 0, sizeof(pkey)); pkey.data = &key; pkey.size = sizeof(key); pkey.flags = DB_DBT_MALLOC; memset(&pval, 0, sizeof(pval)); pval.data = &db_de; pval.ulen = sizeof(db_de); pval.flags = DB_DBT_USERMEM; cget_flags = DB_SET_RANGE; while (1) { bool iter_rc; rc = curs->get(curs, &pkey, &pval, cget_flags); if (rc) { if (rc != DB_NOTFOUND) dirent->err(dirent, rc, "readdir curs->get"); break; } cget_flags = DB_NEXT; rkey = pkey.data; if (inum_decode(rkey->inum) != ino->inum) { free(rkey); break; } dirent_inum = inum_decode(db_de); iter_rc = readdir_iter(txn, rkey, pkey.size, dirent_inum, &ri); free(rkey); if (iter_rc) break; } if (!ri.n_results) { if (debugging) applog(LOG_INFO, " zero results, status %s", ri.status <= NFS4ERR_CB_PATH_DOWN ? status2str(ri.status) : "n/a"); if (ri.status == NFS4_OK) { WRMEM(&srv.instance_verf, sizeof(verifier4)); /* cookieverf */ ri.val_follows = WRSKIP(4); } } rc = curs->close(curs); if (rc) { status = NFS4ERR_IO; dirent->err(dirent, rc, "dirent->cursor close"); goto out_abort; } the_finale: /* terminate final entry4.nextentry and dirlist4.entries */ if (ri.val_follows) *ri.val_follows = htonl(0); if (ri.cookie_found && !ri.n_results && ri.hit_limit) { status = NFS4ERR_TOOSMALL; goto out_abort; } /* close transaction */ rc = txn->commit(txn, 0); if (rc) { dbenv->err(dbenv, rc, "DB_ENV->txn_commit"); status = NFS4ERR_IO; goto out; } WR32(ri.hit_limit ? 0 : 1); /* reply eof */ out: *status_p = htonl(status); inode_free(ino); return status; out_abort: if (txn->abort(txn)) dbenv->err(dbenv, rc, "DB_ENV->txn_abort"); goto out; }
nfsstat4 nfs_op_lookup(struct nfs_cxn *cxn, const LOOKUP4args *args, struct list_head *writes, struct rpc_write **wr) { nfsstat4 status = NFS4_OK; struct nfs_inode *ino = NULL; bool printed = false; struct nfs_buf objname; nfsino_t inum; DB_TXN *txn = NULL; DB_ENV *dbenv = srv.fsdb.env; int rc; objname.len = args->objname.utf8string_len; objname.val = args->objname.utf8string_val; if (!objname.len) { status = NFS4ERR_INVAL; goto out; } if (!objname.val) { status = NFS4ERR_BADXDR; goto out; } if (objname.len > SRV_MAX_NAME) { status = NFS4ERR_NAMETOOLONG; goto out; } rc = dbenv->txn_begin(dbenv, NULL, &txn, 0); if (rc) { status = NFS4ERR_IO; dbenv->err(dbenv, rc, "DB_ENV->txn_begin"); goto out; } status = dir_curfh(txn, cxn, &ino, 0); if (status != NFS4_OK) { if ((status == NFS4ERR_NOTDIR) && (ino->type == NF4LNK)) status = NFS4ERR_SYMLINK; goto out_abort; } status = dir_lookup(txn, ino, &objname, 0, &inum); if (status != NFS4_OK) goto out_abort; rc = txn->commit(txn, 0); if (rc) { dbenv->err(dbenv, rc, "DB_ENV->txn_commit"); status = NFS4ERR_IO; goto out; } fh_set(&cxn->current_fh, inum); if (debugging) { applog(LOG_INFO, "op LOOKUP ('%.*s') -> %016llX", objname.len, objname.val, (unsigned long long) cxn->current_fh.inum); printed = true; } out: if (!printed) { if (debugging) applog(LOG_INFO, "op LOOKUP ('%.*s')", objname.len, objname.val); } WR32(status); inode_free(ino); return status; out_abort: if (txn->abort(txn)) dbenv->err(dbenv, rc, "DB_ENV->txn_abort"); goto out; }
nfsstat4 nfs_op_link(struct nfs_cxn *cxn, const LINK4args *args, struct list_head *writes, struct rpc_write **wr) { nfsstat4 status; struct nfs_inode *dir_ino = NULL, *src_ino = NULL; struct nfs_buf newname; uint64_t before = 0, after = 0; DB_TXN *txn; DB_ENV *dbenv = srv.fsdb.env; int rc; newname.len = args->newname.utf8string_len; newname.val = args->newname.utf8string_val; if (debugging) applog(LOG_INFO, "op LINK (%.*s)", newname.len, newname.val); /* verify input parameters */ if (!valid_fh(cxn->current_fh) || !valid_fh(cxn->save_fh)) { status = NFS4ERR_NOFILEHANDLE; goto out; } if (newname.len > SRV_MAX_NAME) { status = NFS4ERR_NAMETOOLONG; goto out; } /* open transaction */ rc = dbenv->txn_begin(dbenv, NULL, &txn, 0); if (rc) { status = NFS4ERR_IO; dbenv->err(dbenv, rc, "DB_ENV->txn_begin"); goto out; } /* read source inode's directory inode */ dir_ino = inode_fhdec(txn, cxn->current_fh, 0); if (!dir_ino) { status = NFS4ERR_NOFILEHANDLE; goto out_abort; } /* make sure target is a directory */ if (dir_ino->type != NF4DIR) { status = NFS4ERR_NOTDIR; goto out_abort; } /* read source inode */ src_ino = inode_fhdec(txn, cxn->save_fh, 0); if (!src_ino) { status = NFS4ERR_NOFILEHANDLE; goto out_abort; } /* make sure source is a not a directory */ if (src_ino->type == NF4DIR) { status = NFS4ERR_ISDIR; goto out_abort; } before = dir_ino->version; /* add directory entry */ status = dir_add(txn, dir_ino, &newname, src_ino); if (status != NFS4_OK) goto out_abort; after = dir_ino->version; /* update source inode */ src_ino->n_link++; if (inode_touch(txn, src_ino)) { status = NFS4ERR_IO; goto out_abort; } /* close transaction */ rc = txn->commit(txn, 0); if (rc) { dbenv->err(dbenv, rc, "DB_ENV->txn_commit"); status = NFS4ERR_IO; goto out; } out: WR32(status); if (status == NFS4_OK) { WR32(1); /* cinfo.atomic */ WR64(before); /* cinfo.before */ WR64(after); /* cinfo.after */ } inode_free(src_ino); inode_free(dir_ino); return status; out_abort: if (txn->abort(txn)) dbenv->err(dbenv, rc, "DB_ENV->txn_abort"); goto out; }
nfsstat4 nfs_op_remove(struct nfs_cxn *cxn, const REMOVE4args *args, struct list_head *writes, struct rpc_write **wr) { nfsstat4 status = NFS4_OK; struct nfs_inode *dir_ino = NULL, *target_ino = NULL; struct nfs_buf target; change_info4 cinfo = { true, 0, 0 }; DB_TXN *txn = NULL; DB_ENV *dbenv = srv.fsdb.env; int rc; nfsino_t de_inum; target.len = args->target.utf8string_len; target.val = args->target.utf8string_val; if (debugging) applog(LOG_INFO, "op REMOVE ('%.*s')", target.len, target.val); if (target.len > SRV_MAX_NAME) { status = NFS4ERR_NAMETOOLONG; goto out; } if (!valid_utf8string(&target)) { status = NFS4ERR_INVAL; goto out; } if (has_dots(&target)) { status = NFS4ERR_BADNAME; goto out; } rc = dbenv->txn_begin(dbenv, NULL, &txn, 0); if (rc) { status = NFS4ERR_IO; dbenv->err(dbenv, rc, "DB_ENV->txn_begin"); goto out; } /* reference container directory */ status = dir_curfh(txn, cxn, &dir_ino, DB_RMW); if (status != NFS4_OK) goto out_abort; /* lookup target name in directory */ status = dir_lookup(txn, dir_ino, &target, 0, &de_inum); if (status != NFS4_OK) goto out_abort; /* reference target inode */ target_ino = inode_getdec(txn, de_inum, DB_RMW); if (!target_ino) { status = NFS4ERR_NOENT; goto out_abort; } /* prevent root dir deletion */ if (target_ino->inum == INO_ROOT) { status = NFS4ERR_INVAL; goto out_abort; } /* prevent removal of non-empty dirs */ if ((target_ino->type == NF4DIR) && !dir_is_empty(txn, target_ino)) { status = NFS4ERR_NOTEMPTY; goto out_abort; } /* remove target inode from directory */ rc = fsdb_dirent_del(&srv.fsdb, txn, dir_ino->inum, &target, 0); if (rc) { status = NFS4ERR_IO; goto out_abort; } /* record directory change info */ cinfo.before = dir_ino->version; rc = inode_touch(txn, dir_ino); if (rc) { status = NFS4ERR_IO; goto out_abort; } cinfo.after = dir_ino->version; /* remove link, possibly deleting inode */ rc = inode_unlink(txn, target_ino); if (rc) { status = NFS4ERR_IO; goto out_abort; } rc = txn->commit(txn, 0); if (rc) { dbenv->err(dbenv, rc, "DB_ENV->txn_commit"); status = NFS4ERR_IO; goto out; } out: WR32(status); if (status == NFS4_OK) { WR32(cinfo.atomic ? 1 : 0); /* cinfo.atomic */ WR64(cinfo.before); /* cinfo.before */ WR64(cinfo.after); /* cinfo.after */ } inode_free(dir_ino); inode_free(target_ino); return status; out_abort: if (txn->abort(txn)) dbenv->err(dbenv, rc, "DB_ENV->txn_abort"); goto out; }
nfsstat4 nfs_op_rename(struct nfs_cxn *cxn, const RENAME4args *args, struct list_head *writes, struct rpc_write **wr) { nfsstat4 status = NFS4_OK; struct nfs_inode *src_dir = NULL, *target_dir = NULL; struct nfs_inode *old_file = NULL, *new_file = NULL; struct nfs_buf oldname, newname; change_info4 src = { true, 0, 0 }; change_info4 target = { true, 0, 0 }; DB_TXN *txn = NULL; DB_ENV *dbenv = srv.fsdb.env; int rc; nfsino_t old_dirent, new_dirent; oldname.len = args->oldname.utf8string_len; oldname.val = args->oldname.utf8string_val; newname.len = args->newname.utf8string_len; newname.val = args->newname.utf8string_val; if (debugging) applog(LOG_INFO, "op RENAME (OLD:%.*s, NEW:%.*s)", oldname.len, oldname.val, newname.len, newname.val); /* validate text input */ if ((!valid_utf8string(&oldname)) || (!valid_utf8string(&newname))) { status = NFS4ERR_INVAL; goto out; } if (has_dots(&oldname) || has_dots(&newname)) { status = NFS4ERR_BADNAME; goto out; } rc = dbenv->txn_begin(dbenv, NULL, &txn, 0); if (rc) { status = NFS4ERR_IO; dbenv->err(dbenv, rc, "DB_ENV->txn_begin"); goto out; } /* reference source, target directories. * NOTE: src_dir and target_dir may point to the same object */ src_dir = inode_fhdec(txn, cxn->save_fh, DB_RMW); if (fh_equal(cxn->save_fh, cxn->current_fh)) target_dir = src_dir; else target_dir = inode_fhdec(txn, cxn->current_fh, DB_RMW); if (!src_dir || !target_dir) { status = NFS4ERR_NOFILEHANDLE; goto out_abort; } if ((src_dir->type != NF4DIR) || (target_dir->type != NF4DIR)) { status = NFS4ERR_NOTDIR; goto out_abort; } /* lookup source, target names */ status = dir_lookup(txn, src_dir, &oldname, 0, &old_dirent); if (status != NFS4_OK) goto out_abort; old_file = inode_getdec(txn, old_dirent, 0); if (!old_file) { status = NFS4ERR_NOENT; goto out_abort; } status = dir_lookup(txn, target_dir, &newname, 0, &new_dirent); if (status != NFS4_OK && status != NFS4ERR_NOENT) goto out_abort; /* if target (newname) is present, attempt to remove */ if (status == NFS4_OK) { bool ok_to_remove = false; /* read to-be-deleted inode */ new_file = inode_getdec(txn, new_dirent, DB_RMW); if (!new_file) { status = NFS4ERR_NOENT; goto out_abort; } /* do oldname and newname refer to same file? */ if (old_file->inum == new_file->inum) { src.after = src.before = src_dir->version; target.after = target.before = target_dir->version; goto out_abort; } if (old_file->type != NF4DIR && new_file->type != NF4DIR) ok_to_remove = true; else if (old_file->type == NF4DIR && new_file->type == NF4DIR && dir_is_empty(txn, new_file)) ok_to_remove = true; if (!ok_to_remove) { status = NFS4ERR_EXIST; goto out_abort; } /* remove target inode from directory */ rc = fsdb_dirent_del(&srv.fsdb, txn, target_dir->inum, &newname, 0); if (rc == 0) rc = inode_unlink(txn, new_file); if (rc) { status = NFS4ERR_IO; goto out_abort; } } else status = NFS4_OK; new_dirent = old_dirent; /* delete entry from source directory; add to target directory */ rc = fsdb_dirent_del(&srv.fsdb, txn, src_dir->inum, &oldname, 0); if (rc == 0) rc = fsdb_dirent_put(&srv.fsdb, txn, target_dir->inum, &newname, 0, new_dirent); if (rc) { status = NFS4ERR_IO; goto out_abort; } /* if renamed file is a directory, ensure its 'parent' is updated */ if (old_file->type == NF4DIR) { old_file->parent = target_dir->inum; if (inode_touch(txn, old_file)) { status = NFS4ERR_IO; goto out_abort; } } /* record directory change info */ src.before = src_dir->version; target.before = target_dir->version; /* update last-modified stamps of directory inodes */ rc = inode_touch(txn, src_dir); if (rc == 0 && src_dir != target_dir) rc = inode_touch(txn, target_dir); if (rc) { status = NFS4ERR_IO; goto out_abort; } /* close the transaction */ rc = txn->commit(txn, 0); if (rc) { dbenv->err(dbenv, rc, "DB_ENV->txn_commit"); status = NFS4ERR_IO; goto out; } src.after = src_dir->version; target.after = target_dir->version; out: WR32(status); if (status == NFS4_OK) { WR32(src.atomic ? 1 : 0); /* src cinfo.atomic */ WR64(src.before); /* src cinfo.before */ WR64(src.after); /* src cinfo.after */ WR32(target.atomic ? 1 : 0); /* target cinfo.atomic */ WR64(target.before); /* target cinfo.before */ WR64(target.after); /* target cinfo.after */ } inode_free(src_dir); if (src_dir != target_dir) inode_free(target_dir); inode_free(old_file); inode_free(new_file); return status; out_abort: if (txn->abort(txn)) dbenv->err(dbenv, rc, "DB_ENV->txn_abort"); goto out; }
static bool readdir_iter(DB_TXN *txn, const struct fsdb_de_key *key, size_t key_len, nfsino_t dirent, struct readdir_info *ri) { uint64_t bitmap_out = 0; uint32_t dirlen, maxlen; struct nfs_fattr_set attr; struct nfs_inode *ino = NULL; struct list_head *writes = ri->writes; struct rpc_write **wr = ri->wr; size_t name_len; struct nfs_buf de_name; if (ri->stop) return true; if (!ri->cookie_found) { if (ri->cookie && (ri->dir_pos <= ri->cookie)) { ri->dir_pos++; return false; } ri->cookie_found = true; } ino = inode_getdec(txn, dirent, 0); if (!ino) { applog(LOG_WARNING, " WARNING: inode %016llX not found", (unsigned long long) dirent); /* FIXME: return via rdattr-error */ ri->stop = true; ri->status = NFS4ERR_NOENT; return true; } memset(&attr, 0, sizeof(attr)); fattr_fill(ino, &attr); name_len = key_len - sizeof(*key); dirlen = 8 + 4 + (XDR_QUADLEN(name_len) * 4); if (dirlen > ri->dircount) { ri->hit_limit = true; ri->stop = true; if (debugging > 1) applog(LOG_DEBUG, " iter: hit dir limit"); goto out; } maxlen = 8 + 4 + (XDR_QUADLEN(name_len) * 4) + 16 + fattr_size(&attr) + 4; if (maxlen > ri->maxcount) { ri->hit_limit = true; ri->stop = true; if (debugging > 1) applog(LOG_DEBUG, " iter: hit max limit"); goto out; } if (ri->first_time) { ri->first_time = false; /* FIXME: server verifier isn't the best for dir verf */ WRMEM(&srv.instance_verf, sizeof(verifier4)); /* cookieverf */ ri->val_follows = WRSKIP(4); } ri->dircount -= dirlen; ri->maxcount -= maxlen; /* write value to previous entry4.nextentry */ *ri->val_follows = htonl(1); ri->val_follows = NULL; WR64(ri->dir_pos); /* entry4.cookie */ de_name.len = name_len; de_name.val = (void *) key->name; /* cast is ok: RO data is copied */ WRBUF(&de_name); /* entry4.name */ /* entry4.attrs */ attr.bitmap = ri->attr_request; ri->status = wr_fattr(&attr, &bitmap_out, writes, wr); if (ri->status != NFS4_OK) ri->stop = true; if (debugging) applog(LOG_DEBUG, " READDIR ent: '%.*s' (INO:%016llX MAP:%Lx WRLEN:%u)", (int) name_len, key->name, (unsigned long long) dirent, (unsigned long long) bitmap_out, (*wr)->len); ri->val_follows = WRSKIP(4); /* entry4.nextentry */ ri->n_results++; ri->dir_pos++; out: inode_free(ino); fattr_free(&attr); if (ri->stop) return true; return false; }