Example #1
0
void inode_free(FAR struct inode *node)
{
  if (node)
    {
      inode_free(node->i_peer);
      inode_free(node->i_child);
      kfree(node);
    }
}
Example #2
0
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;
  }
}
Example #3
0
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;
}
Example #4
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();
        }
    }
}
Example #5
0
File: dir.c Project: jgarzik/nfs4d
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;
}
Example #6
0
File: main.c Project: mattjakob/s3d
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);
}
Example #7
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;
}
Example #8
0
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();
}
Example #9
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)
        {
           inode_semgive();
           inode_free(node->i_child);
           kfree(node);
        }
      else
        {
           inode_semgive();
        }
    }
}
Example #10
0
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;
}
Example #12
0
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;
}
Example #13
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;
}
Example #14
0
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;
}
Example #15
0
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;
}
Example #16
0
File: dir.c Project: jgarzik/nfs4d
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;
}
Example #17
0
File: dir.c Project: jgarzik/nfs4d
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;
}
Example #18
0
File: dir.c Project: jgarzik/nfs4d
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;
}
Example #19
0
File: dir.c Project: jgarzik/nfs4d
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;
}
Example #20
0
File: dir.c Project: jgarzik/nfs4d
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;
}
Example #21
0
File: dir.c Project: jgarzik/nfs4d
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;
}