Exemplo n.º 1
0
int
fs_rmdir(const char *path)
{
	struct inode *dir;
	struct dirent *dent;
	uint32_t nblock, i, j;
	char *blk;
	int r;

	if ((r = inode_open(path, &dir)) < 0)
		return r;
	if (dir == diskaddr(super->s_root))
		return -EPERM;
	if (!S_ISDIR(dir->i_mode))
		return -ENOTDIR;

	nblock = dir->i_size / BLKSIZE;
	for (i = 0; i < nblock; i++) {
		if ((r = inode_get_block(dir, i, &blk)) < 0)
			return r;
		dent = (struct dirent *)blk;
		for (j = 0; j < BLKDIRENTS; ++j)
			if (dent[j].d_name[0] != '\0')
				return -ENOTEMPTY;
	}
	return inode_unlink(path);
}
Exemplo n.º 2
0
int
fs_rename(const char *srcpath, const char *dstpath)
{
	int r;

link_retry:
	if ((r = inode_link(srcpath, dstpath)) < 0)
		switch(-r) {
		case EEXIST:
			if (strcmp(srcpath, dstpath) == 0)
				return 0;
			if ((r = inode_unlink(dstpath)) < 0)
				return r;
			goto link_retry;
		default:
			return r;
		}
	return inode_unlink(srcpath);
}
Exemplo n.º 3
0
int
fs_unlink(const char *path)
{
	struct inode *ino;
	int r;

	if ((r = inode_open(path, &ino)) < 0)
		return r;
	if (S_ISDIR(ino->i_mode))
		return -EISDIR;
	ino->i_ctime = time(NULL);
	return inode_unlink(path);
}
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;
}
Exemplo n.º 5
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;
}
Exemplo n.º 6
0
int
fs_symlink(const char *dstpath, const char *srcpath)
{
	struct inode *ino;
	struct fuse_context *ctxt;
	time_t curtime;
	size_t dstlen;
	char *blk;
	int r;

	if ((dstlen = strlen(dstpath)) >= PATH_MAX)
		return -ENAMETOOLONG;
	if ((r = inode_create(srcpath, &ino)) < 0) {
		return r;
	}
	ino->i_size = dstlen;
	ino->i_mode = S_IFLNK | 0777;
	ino->i_nlink = 1;

	curtime = time(NULL);
	ino->i_atime = curtime;
	ino->i_ctime = curtime;
	ino->i_mtime = curtime;

	ctxt = fuse_get_context();
	ino->i_owner = ctxt->uid;
	ino->i_group = ctxt->gid;

	if ((r = inode_get_block(ino, 0, &blk)) < 0) {
		inode_unlink(srcpath);
		return r;
	}
	memcpy(blk, dstpath, dstlen);
	inode_flush(ino);

	return 0;
}
Exemplo n.º 7
0
Arquivo: dir.c Projeto: 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;
}
Exemplo n.º 8
0
Arquivo: dir.c Projeto: 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;
}
Exemplo n.º 9
0
void
fs_test(void)
{
	struct inode *ino, *ino2;
	int r;
	char *blk;
	uint32_t bits[4096];

	// back up bitmap
	memmove(bits, bitmap, 4096);
	// allocate block
	if ((r = alloc_block()) < 0)
		panic("alloc_block: %s", strerror(-r));
	// check that block was free
	assert(bits[r/32] & (1 << (r%32)));
	// and is not free any more
	assert(!(bitmap[r/32] & (1 << (r%32))));
	free_block(r);
	printf("alloc_block is good\n");

	if ((r = inode_open("/not-found", &ino)) < 0 && r != -ENOENT)
		panic("inode_open /not-found: %s", strerror(-r));
	else if (r == 0)
		panic("inode_open /not-found succeeded!");
	if ((r = inode_open("/msg", &ino)) < 0)
		panic("inode_open /msg: %s", strerror(-r));
	printf("inode_open is good\n");

	if ((r = inode_get_block(ino, 0, &blk)) < 0)
		panic("inode_get_block: %s", strerror(-r));
	if (strcmp(blk, msg) != 0)
		panic("inode_get_block returned wrong data");
	printf("inode_get_block is good\n");

	if ((r = inode_set_size(ino, 0)) < 0)
		panic("inode_set_size: %s", strerror(-r));
	assert(ino->i_direct[0] == 0);
	printf("inode_truncate is good\n");

	if ((r = inode_set_size(ino, strlen(msg))) < 0)
		panic("inode_set_size 2: %s", strerror(-r));
	if ((r = inode_get_block(ino, 0, &blk)) < 0)
		panic("inode_get_block 2: %s", strerror(-r));
	strcpy(blk, msg);
	printf("file rewrite is good\n");

	if ((r = inode_link("/msg", "/linkmsg")) < 0)
		panic("inode_link /msg /linkmsg: %s", strerror(-r));
	if ((r = inode_open("/msg", &ino)) < 0)
		panic("inode_open /msg: %s", strerror(-r));
	if ((r = inode_open("/linkmsg", &ino2)) < 0)
		panic("inode_open /linkmsg: %s", strerror(-r));
	if (ino != ino2)
		panic("linked files do not point to same inode");
	if (ino->i_nlink != 2)
		panic("link count incorrect: %u, expected 2", ino->i_nlink);
	printf("inode_link is good\n");

	if ((r = inode_unlink("/linkmsg")) < 0)
		panic("inode_unlink /linkmsg: %s", strerror(-r));
	if ((r = inode_open("/linkmsg", &ino2)) < 0 && r != -ENOENT)
		panic("inode_open /linkmsg after unlink: %s", strerror(-r));
	else if (r == 0)
		panic("inode_open /linkmsg after unlink succeeded!");
	if ((r = inode_open("/msg", &ino)) < 0)
		panic("inode_open /msg after /linkmsg unlinked: %s", strerror(-r));
	if (ino->i_nlink != 1)
		panic("link count incorrect: %u, expected 1", ino->i_nlink);
	printf("inode_unlink is good\n");
}