Пример #1
0
int
v7fs_update(struct vnode *vp, const struct timespec *acc,
    const struct timespec *mod, int flags)
{
	struct v7fs_node *v7node = vp->v_data;
	struct v7fs_inode *inode = &v7node->inode;
	struct v7fs_self *fs = v7node->v7fsmount->core;
	bool update = false;

	DPRINTF("%p %zu %d\n", vp, vp->v_size, v7fs_inode_filesize(inode));
	KDASSERT(vp->v_size == v7fs_inode_filesize(inode));

	if (v7node->update_atime) {
		inode->atime = acc ? acc->tv_sec : time_second;
		v7node->update_atime = false;
		update = true;
	}
	if (v7node->update_ctime) {
		inode->ctime = time_second;
		v7node->update_ctime = false;
		update = true;
	}
	if (v7node->update_mtime) {
		inode->mtime = mod ? mod->tv_sec : time_second;
		v7node->update_mtime = false;
		update = true;
	}

	if (update)
		v7fs_inode_writeback(fs, inode);

	return 0;
}
Пример #2
0
int
v7fs_symlink(void *v)
{
	struct vop_symlink_v3_args /* {
				   struct vnode		*a_dvp;
				   struct vnode		**a_vpp;
				   struct componentname	*a_cnp;
				   struct vattr		*a_vap;
				   char			*a_target;
				   } */ *a = v;
	struct v7fs_node *parent_node = a->a_dvp->v_data;
	struct v7fs_mount *v7fsmount = parent_node->v7fsmount;
	struct v7fs_self *fs = v7fsmount->core;
	struct vattr *va = a->a_vap;
	kauth_cred_t cr = a->a_cnp->cn_cred;
	struct componentname *cnp = a->a_cnp;
	struct v7fs_fileattr attr;
	v7fs_ino_t ino;
	const char *from = a->a_target;
	const char *to = cnp->cn_nameptr;
	size_t len = strlen(from) + 1;
	int error = 0;

	if (len > V7FS_BSIZE) { /* limited to 512byte pathname */
		DPRINTF("too long pathname.");
		return ENAMETOOLONG;
	}

	memset(&attr, 0, sizeof(attr));
	attr.uid = kauth_cred_geteuid(cr);
	attr.gid = kauth_cred_getegid(cr);
	attr.mode = va->va_mode | vtype_to_v7fs_mode(va->va_type);

	if ((error = v7fs_file_allocate
		(fs, &parent_node->inode, to, &attr, &ino))) {
		return error;
	}
	/* Sync dirent size change. */
	uvm_vnp_setsize(a->a_dvp, v7fs_inode_filesize(&parent_node->inode));

	/* Get myself vnode. */
	if ((error = v7fs_vget(v7fsmount->mountp, ino, a->a_vpp))) {
		DPRINTF("can't get vnode.\n");
	}

	struct v7fs_node *newnode = (*a->a_vpp)->v_data;
	struct v7fs_inode *p = &newnode->inode;
	v7fs_file_symlink(fs, p, from);
	uvm_vnp_setsize(*a->a_vpp, v7fs_inode_filesize(p));

	newnode->update_ctime = true;
	newnode->update_mtime = true;
	newnode->update_atime = true;

	if (error == 0)
		VOP_UNLOCK(*a->a_vpp);

	return error;
}
Пример #3
0
int
v7fs_rename(void *v)
{
	struct vop_rename_args /* {
				  struct vnode *a_fdvp;	from parent-directory
				  struct vnode *a_fvp;	from file
				  struct componentname *a_fcnp;
				  struct vnode *a_tdvp;	to parent-directory
				  struct vnode *a_tvp;	to file
				  struct componentname *a_tcnp;
				  } */ *a = v;
	struct vnode *fvp = a->a_fvp;
	struct vnode *tvp = a->a_tvp;
	struct vnode *fdvp = a->a_fdvp;
	struct vnode *tdvp = a->a_tdvp;
	struct v7fs_node *parent_from = fdvp->v_data;
	struct v7fs_node *parent_to = tdvp->v_data;
	struct v7fs_node *v7node = fvp->v_data;
	struct v7fs_self *fs = v7node->v7fsmount->core;
	const char *from_name = a->a_fcnp->cn_nameptr;
	const char *to_name = a->a_tcnp->cn_nameptr;
	int error;

	DPRINTF("%s->%s %p %p\n", from_name, to_name, fvp, tvp);

	if ((fvp->v_mount != tdvp->v_mount) ||
	    (tvp && (fvp->v_mount != tvp->v_mount))) {
		error = EXDEV;
		DPRINTF("cross-device link\n");
		goto out;
	}
	// XXXsource file lock?
	error = v7fs_file_rename(fs, &parent_from->inode, from_name,
	    &parent_to->inode, to_name);
	/* 'to file' inode may be changed. (hard-linked and it is cached.)
	   t_vnops rename_reg_nodir */
	if (error == 0 && tvp) {
		struct v7fs_inode *inode =
		    &((struct v7fs_node *)tvp->v_data)->inode;

		error = v7fs_inode_load(fs, inode, inode->inode_number);
		uvm_vnp_setsize(tvp, v7fs_inode_filesize(inode));
	}
	/* Sync dirent size change. */
	uvm_vnp_setsize(tdvp, v7fs_inode_filesize(&parent_to->inode));
	uvm_vnp_setsize(fdvp, v7fs_inode_filesize(&parent_from->inode));
out:
	if (tvp)
		vput(tvp);  /* locked on entry */
	if (tdvp == tvp)
		vrele(tdvp);
	else
		vput(tdvp);
	vrele(fdvp);
	vrele(fvp);

	return error;
}
int
v7fs_directory_add_entry(struct v7fs_self *fs, struct v7fs_inode *parent_dir,
    v7fs_ino_t ino, const char *srcname)
{
	struct v7fs_inode inode;
	struct v7fs_dirent *dir;
	int error = 0;
	v7fs_daddr_t blk;
	void *buf;
	char filename[V7FS_NAME_MAX + 1];

	/* Truncate filename. */
	v7fs_dirent_filename(filename, srcname);
	DPRINTF("%s(%s) %d\n", filename, srcname, ino);

	/* Target inode */
	if ((error = v7fs_inode_load(fs, &inode, ino)))
		return error;

	/* Expand datablock. */
	if ((error = v7fs_datablock_expand(fs, parent_dir, sizeof(*dir))))
		return error;

	/* Read last entry. */
	if (!(blk = v7fs_datablock_last(fs, parent_dir,
	    v7fs_inode_filesize(parent_dir))))
		return EIO;

	/* Load dirent block. This vnode(parent dir) is locked by VFS layer. */
	if (!(buf = scratch_read(fs, blk)))
		return EIO;

	size_t sz = v7fs_inode_filesize(parent_dir);
	sz = V7FS_RESIDUE_BSIZE(sz);	/* last block payload. */
	int n = sz / sizeof(*dir) - 1;
	/* Add dirent. */
	dir = (struct v7fs_dirent *)buf;
	dir[n].inode_number = V7FS_VAL16(fs, ino);
	memcpy((char *)dir[n].name, filename, V7FS_NAME_MAX);
	/* Write back datablock */
	if (!fs->io.write(fs->io.cookie, buf, blk))
		error = EIO;
	scratch_free(fs, buf);

	if (v7fs_inode_isdir(&inode)) {
		parent_dir->nlink++;
		v7fs_inode_writeback(fs, parent_dir);
	}

	DPRINTF("done. (dirent size=%dbyte)\n", parent_dir->filesize);

	return error;
}
Пример #5
0
int
v7fs_link(void *v)
{
	struct vop_link_v2_args /* {
				struct vnode *a_dvp;
				struct vnode *a_vp;
				struct componentname *a_cnp;
				} */ *a = v;
	struct vnode *dvp = a->a_dvp;
	struct vnode *vp = a->a_vp;
	struct v7fs_node *parent_node = dvp->v_data;
	struct v7fs_node *node = vp->v_data;
	struct v7fs_inode *parent = &parent_node->inode;
	struct v7fs_inode *p = &node->inode;
	struct v7fs_self *fs = node->v7fsmount->core;
	struct componentname *cnp = a->a_cnp;
	int error = 0;

	DPRINTF("%p\n", vp);
	/* Lock soruce file */
	if ((error = vn_lock(vp, LK_EXCLUSIVE))) {
		DPRINTF("lock failed. %p\n", vp);
		VOP_ABORTOP(dvp, cnp);
		goto unlock;
	}
	error = v7fs_file_link(fs, parent, p, cnp->cn_nameptr);
	/* Sync dirent size change. */
	uvm_vnp_setsize(dvp, v7fs_inode_filesize(&parent_node->inode));

	VOP_UNLOCK(vp);
unlock:
	return error;
}
Пример #6
0
int
v7fs_read(void *v)
{
	struct vop_read_args /* {
				struct vnode *a_vp;
				struct uio *a_uio;
				int a_ioflag;
				kauth_cred_t a_cred;
				} */ *a = v;
	struct vnode *vp = a->a_vp;
	struct uio *uio = a->a_uio;
	struct v7fs_node *v7node = vp->v_data;
	struct v7fs_inode *inode = &v7node->inode;
	vsize_t sz, filesz = v7fs_inode_filesize(inode);
	const int advice = IO_ADV_DECODE(a->a_ioflag);
	int error = 0;

	DPRINTF("type=%d inode=%d\n", vp->v_type, v7node->inode.inode_number);

	while (uio->uio_resid > 0) {
		if ((sz = MIN(filesz - uio->uio_offset, uio->uio_resid)) == 0)
			break;

		error = ubc_uiomove(&vp->v_uobj, uio, sz, advice, UBC_READ |
		    UBC_PARTIALOK | UBC_UNMAP_FLAG(v));
		if (error) {
			break;
		}
		DPRINTF("read %zubyte\n", sz);
	}
	v7node->update_atime = true;

	return error;
}
Пример #7
0
int
v7fs_create(void *v)
{
	struct vop_create_v3_args /* {
				  struct vnode *a_dvp;
				  struct vnode **a_vpp;
				  struct componentname *a_cnp;
				  struct vattr *a_vap;
				  } */ *a = v;
	struct v7fs_node *parent_node = a->a_dvp->v_data;
	struct v7fs_mount *v7fsmount = parent_node->v7fsmount;
	struct v7fs_self *fs = v7fsmount->core;
	struct mount *mp = v7fsmount->mountp;
	struct v7fs_fileattr attr;
	struct vattr *va = a->a_vap;
	kauth_cred_t cr = a->a_cnp->cn_cred;
	v7fs_ino_t ino;
	int error = 0;

	DPRINTF("%s parent#%d\n", a->a_cnp->cn_nameptr,
	    parent_node->inode.inode_number);
	KDASSERT((va->va_type == VREG) || (va->va_type == VSOCK));

	memset(&attr, 0, sizeof(attr));
	attr.uid = kauth_cred_geteuid(cr);
	attr.gid = kauth_cred_getegid(cr);
	attr.mode = va->va_mode | vtype_to_v7fs_mode (va->va_type);
	attr.device = 0;

	/* Allocate disk entry. and register its entry to parent directory. */
	if ((error = v7fs_file_allocate(fs, &parent_node->inode,
		    a->a_cnp->cn_nameptr, &attr, &ino))) {
		DPRINTF("v7fs_file_allocate failed.\n");
		return error;
	}
	/* Sync dirent size change. */
	uvm_vnp_setsize(a->a_dvp, v7fs_inode_filesize(&parent_node->inode));

	/* Get myself vnode. */
	*a->a_vpp = 0;
	if ((error = v7fs_vget(mp, ino, a->a_vpp))) {
		DPRINTF("v7fs_vget failed.\n");
		return error;
	}

	/* Scheduling update time. real update by v7fs_update */
	struct v7fs_node *newnode = (*a->a_vpp)->v_data;
	newnode->update_ctime = true;
	newnode->update_mtime = true;
	newnode->update_atime = true;
	DPRINTF("allocated %s->#%d\n", a->a_cnp->cn_nameptr, ino);

	if (error == 0)
		VOP_UNLOCK(*a->a_vpp);

	return error;
}
Пример #8
0
int
v7fs_mknod(void *v)
{
	struct vop_mknod_v3_args /* {
				 struct vnode		*a_dvp;
				 struct vnode		**a_vpp;
				 struct componentname	*a_cnp;
				 struct vattr		*a_vap;
				 } */ *a = v;
	struct componentname *cnp = a->a_cnp;
	kauth_cred_t cr = cnp->cn_cred;
	struct vnode *dvp = a->a_dvp;
	struct vattr *va = a->a_vap;
	struct v7fs_node *parent_node = dvp->v_data;
	struct v7fs_mount *v7fsmount = parent_node->v7fsmount;
	struct v7fs_self *fs = v7fsmount->core;
	struct mount *mp = v7fsmount->mountp;
	struct v7fs_fileattr attr;

	v7fs_ino_t ino;
	int error = 0;

	DPRINTF("%s %06o %lx %d\n", cnp->cn_nameptr, va->va_mode,
	    (long)va->va_rdev, va->va_type);
	memset(&attr, 0, sizeof(attr));
	attr.uid = kauth_cred_geteuid(cr);
	attr.gid = kauth_cred_getegid(cr);
	attr.mode = va->va_mode | vtype_to_v7fs_mode(va->va_type);
	attr.device = va->va_rdev;

	if ((error = v7fs_file_allocate(fs, &parent_node->inode,
	    cnp->cn_nameptr, &attr, &ino)))
		return error;
	/* Sync dirent size change. */
	uvm_vnp_setsize(dvp, v7fs_inode_filesize(&parent_node->inode));

	if ((error = v7fs_vget(mp, ino, a->a_vpp))) {
		DPRINTF("can't get vnode.\n");
		return error;
	}
	struct v7fs_node *newnode = (*a->a_vpp)->v_data;
	newnode->update_ctime = true;
	newnode->update_mtime = true;
	newnode->update_atime = true;

	if (error == 0)
		VOP_UNLOCK(*a->a_vpp);

	return error;
}
Пример #9
0
int
v7fs_rmdir(void *v)
{
	struct vop_rmdir_args /* {
				 struct vnode		*a_dvp;
				 struct vnode		*a_vp;
				 struct componentname	*a_cnp;
				 } */ *a = v;
	struct vnode *vp = a->a_vp;
	struct vnode *dvp = a->a_dvp;
	struct v7fs_node *parent_node = dvp->v_data;
	struct v7fs_mount *v7fsmount = parent_node->v7fsmount;
	struct v7fs_inode *inode = &((struct v7fs_node *)vp->v_data)->inode;
	struct v7fs_self *fs = v7fsmount->core;
	int error = 0;

	DPRINTF("delete %s\n", a->a_cnp->cn_nameptr);

	KDASSERT(vp->v_type == VDIR);

	if ((error = v7fs_file_deallocate(fs, &parent_node->inode,
	    a->a_cnp->cn_nameptr))) {
		DPRINTF("v7fs_directory_deallocate failed.\n");
		goto out;
	}
	error = v7fs_inode_load(fs, inode, inode->inode_number);
	if (error)
		goto out;
	uvm_vnp_setsize(vp, v7fs_inode_filesize(inode));
	/* Sync dirent size change. */
	uvm_vnp_setsize(dvp, v7fs_inode_filesize(&parent_node->inode));
out:
	vput(vp);
	vput(dvp);

	return error;
}
Пример #10
0
int
v7fs_write(void *v)
{
	struct vop_write_args /* {
				 struct vnode *a_vp;
				 struct uio *a_uio;
				 int  a_ioflag;
				 kauth_cred_t a_cred;
				 } */ *a = v;
	struct vnode *vp = a->a_vp;
	struct uio *uio = a->a_uio;
	int advice = IO_ADV_DECODE(a->a_ioflag);
	struct v7fs_node *v7node = vp->v_data;
	struct v7fs_inode *inode = &v7node->inode;
	struct v7fs_self *fs = v7node->v7fsmount->core;
	vsize_t sz;
	int error = 0;

	if (uio->uio_resid == 0)
		return 0;

	sz = v7fs_inode_filesize(inode);
	DPRINTF("(i)%ld (v)%zu ofs=%zu + res=%zu = %zu\n", sz, vp->v_size,
	    uio->uio_offset, uio->uio_resid, uio->uio_offset + uio->uio_resid);

	/* Append mode file offset is managed by kernel. */
	if (a->a_ioflag & IO_APPEND)
		uio->uio_offset = sz;

	/* If write region is over filesize, expand. */
	size_t newsize= uio->uio_offset + uio->uio_resid;
	ssize_t expand = newsize - sz;
 	if (expand > 0) {
		if ((error = v7fs_datablock_expand(fs, inode, expand)))
			return error;
		uvm_vnp_setsize(vp, newsize);
	}

	while (uio->uio_resid > 0) {
		sz = uio->uio_resid;
		if ((error = ubc_uiomove(&vp->v_uobj, uio, sz, advice,
			    UBC_WRITE | UBC_UNMAP_FLAG(v))))
			break;
		DPRINTF("write %zubyte\n", sz);
	}
	v7node->update_mtime = true;

	return error;
}
int
v7fs_directory_remove_entry(struct v7fs_self *fs, struct v7fs_inode *parent_dir,
    const char *name)
{
	struct v7fs_inode inode;
	int error;
	struct v7fs_dirent lastdirent;
	v7fs_daddr_t lastblk;
	size_t sz, lastsz;
	v7fs_off_t pos;
	void *buf;

	/* Setup replaced entry. */
	sz = parent_dir->filesize;
	lastblk = v7fs_datablock_last(fs, parent_dir,
	    v7fs_inode_filesize(parent_dir));
	lastsz = V7FS_RESIDUE_BSIZE(sz);
	pos = lastsz - sizeof(lastdirent);

	if (!(buf = scratch_read(fs, lastblk)))
		return EIO;
	lastdirent = *((struct v7fs_dirent *)((uint8_t *)buf + pos));
	scratch_free(fs, buf);
	DPRINTF("last dirent=%d %s pos=%d\n",
	    V7FS_VAL16(fs, lastdirent.inode_number), lastdirent.name, pos);

	struct v7fs_lookup_arg lookup_arg =
	    { .name = name, .replace = &lastdirent/*disk endian */ };
	/* Search entry that removed. replace it to last dirent. */
	if ((error = v7fs_datablock_foreach(fs, parent_dir, remove_subr,
	    &lookup_arg)) != V7FS_ITERATOR_BREAK)
		return ENOENT;

	/* Contract dirent entries. */
	v7fs_datablock_contract(fs, parent_dir, sizeof(lastdirent));
	DPRINTF("done. (dirent size=%dbyte)\n", parent_dir->filesize);

	/* Target inode */
	if ((error = v7fs_inode_load(fs, &inode, lookup_arg.inode_number)))
		return error;

	if (v7fs_inode_isdir(&inode)) {
		parent_dir->nlink--;
		v7fs_inode_writeback(fs, parent_dir);
	}

	return 0;
}
Пример #12
0
int
v7fs_advlock(void *v)
{
	struct vop_advlock_args /* {
				   struct vnode *a_vp;
				   void *a_id;
				   int a_op;
				   struct flock *a_fl;
				   int a_flags;
				   } */ *a = v;
	struct v7fs_node *v7node = a->a_vp->v_data;

	DPRINTF("op=%d\n", a->a_op);

	return lf_advlock(a, &v7node->lockf,
	    v7fs_inode_filesize(&v7node->inode));
}
Пример #13
0
int
v7fs_remove(void *v)
{
	struct vop_remove_args /* {
				  struct vnodeop_desc *a_desc;
				  struct vnode * a_dvp;
				  struct vnode * a_vp;
				  struct componentname * a_cnp;
				  } */ *a = v;
	struct v7fs_node *parent_node = a->a_dvp->v_data;
	struct v7fs_mount *v7fsmount = parent_node->v7fsmount;
	struct vnode *vp = a->a_vp;
	struct vnode *dvp = a->a_dvp;
	struct v7fs_inode *inode = &((struct v7fs_node *)vp->v_data)->inode;
	struct v7fs_self *fs = v7fsmount->core;
	int error = 0;

	DPRINTF("delete %s\n", a->a_cnp->cn_nameptr);

	if (vp->v_type == VDIR) {
		error = EPERM;
		goto out;
	}

	if ((error = v7fs_file_deallocate(fs, &parent_node->inode,
		    a->a_cnp->cn_nameptr))) {
		DPRINTF("v7fs_file_delete failed.\n");
		goto out;
	}
	error = v7fs_inode_load(fs, inode, inode->inode_number);
	if (error)
		goto out;
	/* Sync dirent size change. */
	uvm_vnp_setsize(dvp, v7fs_inode_filesize(&parent_node->inode));

out:
	if (dvp == vp)
		vrele(vp); /* v_usecount-- of unlocked vp */
	else
		vput(vp); /* unlock vp and then v_usecount-- */
	vput(dvp);

	return error;
}
Пример #14
0
int
v7fs_close(void *v)
{
	struct vop_close_args /* {
				 struct vnodeop_desc *a_desc;
				 struct vnode *a_vp;
				 int  a_fflag;
				 kauth_cred_t a_cred;
				 } */ *a = v;
	struct vnode *vp = a->a_vp;
#ifdef V7FS_VNOPS_DEBUG
	struct v7fs_node *v7node = vp->v_data;
	struct v7fs_inode *inode = &v7node->inode;
#endif
	DPRINTF("#%d (i)%dbyte (v)%zubyte\n", inode->inode_number,
	    v7fs_inode_filesize(inode), vp->v_size);

	/* Update timestamp */
	v7fs_update(vp, 0, 0, UPDATE_WAIT);

	return 0;
}
int
v7fs_file_lookup_by_name(struct v7fs_self *fs, struct v7fs_inode *parent_dir,
    const char *name, v7fs_ino_t *ino)
{
	char filename[V7FS_NAME_MAX + 1];
	char *q;
	int error;
	size_t len;

	if ((q = strchr(name, '/'))) {
		/* Zap following path. */
		len = MIN(V7FS_NAME_MAX, q - name);
		memcpy(filename, name, len);
		filename[len] = '\0';	/* '/' -> '\0' */
	} else {
		v7fs_dirent_filename(filename, name);
	}
	DPRINTF("%s(%s) dir=%d\n", filename, name, parent_dir->inode_number);

	struct v7fs_lookup_arg lookup_arg = { .name = filename,
					      .inode_number = 0 };
	if ((error = v7fs_datablock_foreach(fs, parent_dir, lookup_subr,
		    &lookup_arg)) != V7FS_ITERATOR_BREAK) {
		DPRINTF("not found.\n");
		return ENOENT;
	}

	*ino = lookup_arg.inode_number;
	DPRINTF("done. ino=%d\n", *ino);

	return 0;
}

static int
lookup_subr(struct v7fs_self *fs, void *ctx, v7fs_daddr_t blk, size_t sz)
{
	struct v7fs_lookup_arg *p = (struct v7fs_lookup_arg *)ctx;
	struct v7fs_dirent *dir;
	const char *name = p->name;
	void *buf;
	size_t i, n;
	int ret = 0;

	if (!(buf = scratch_read(fs, blk)))
		return EIO;

	dir = (struct v7fs_dirent *)buf;
	n = sz / sizeof(*dir);
	v7fs_dirent_endian_convert(fs, dir, n);

	for (i = 0; i < n; i++, dir++) {
		if (dir->inode_number < 1) {
			DPRINTF("*** bad inode #%d ***\n", dir->inode_number);
			continue;
		}

		if (strncmp((const char *)dir->name, name, V7FS_NAME_MAX) == 0)
		{
			p->inode_number = dir->inode_number;
			ret =  V7FS_ITERATOR_BREAK; /* found */
			break;
		}
	}
	scratch_free(fs, buf);

	return ret;
}

int
v7fs_file_allocate(struct v7fs_self *fs, struct v7fs_inode *parent_dir,
    const char *srcname, struct v7fs_fileattr *attr, v7fs_ino_t *ino)
{
	struct v7fs_inode inode;
	char filename[V7FS_NAME_MAX + 1];
	struct v7fs_dirent *dir;
	int error;

	/* Truncate filename. */
	v7fs_dirent_filename(filename, srcname);
	DPRINTF("%s(%s)\n", filename, srcname);

	/* Check filename. */
	if (v7fs_file_lookup_by_name(fs, parent_dir, filename, ino) == 0) {
		DPRINTF("%s exists\n", filename);
		return EEXIST;
	}

	/* Get new inode. */
	if ((error = v7fs_inode_allocate(fs, ino)))
		return error;

	/* Set initial attribute. */
	memset(&inode, 0, sizeof(inode));
	inode.inode_number = *ino;
	inode.mode = attr->mode;
	inode.uid = attr->uid;
	inode.gid = attr->gid;
	if (attr->ctime)
		inode.ctime = attr->ctime;
	if (attr->mtime)
		inode.mtime = attr->mtime;
	if (attr->atime)
		inode.atime = attr->atime;

	switch (inode.mode & V7FS_IFMT)	{
	default:
		DPRINTF("Can't allocate %o type.\n", inode.mode);
		v7fs_inode_deallocate(fs, *ino);
		return EINVAL;
	case V7FS_IFCHR:
		/* FALLTHROUGH */
	case V7FS_IFBLK:
		inode.nlink = 1;
		inode.device = attr->device;
		inode.addr[0] = inode.device;
		break;
	case V7FSBSD_IFFIFO:
		/* FALLTHROUGH */
	case V7FSBSD_IFSOCK:
		/* FALLTHROUGH */
	case V7FSBSD_IFLNK:
		/* FALLTHROUGH */
	case V7FS_IFREG:
		inode.nlink = 1;
		break;
	case V7FS_IFDIR:
		inode.nlink = 2;	/* . + .. */
		if ((error = v7fs_datablock_expand(fs, &inode, sizeof(*dir) * 2
		    ))) {
			v7fs_inode_deallocate(fs, *ino);
			return error;
		}
		v7fs_daddr_t blk = inode.addr[0];
		void *buf;
		if (!(buf = scratch_read(fs, blk))) {
			v7fs_inode_deallocate(fs, *ino);
			return EIO;
		}
		dir = (struct v7fs_dirent *)buf;
		strcpy(dir[0].name, ".");
		dir[0].inode_number = V7FS_VAL16(fs, *ino);
		strcpy(dir[1].name, "..");
		dir[1].inode_number = V7FS_VAL16(fs, parent_dir->inode_number);
		if (!fs->io.write(fs->io.cookie, buf, blk)) {
			scratch_free(fs, buf);
			return EIO;
		}
		scratch_free(fs, buf);
		break;
	}

	v7fs_inode_writeback(fs, &inode);

	/* Link this inode to parent directory. */
	if ((error = v7fs_directory_add_entry(fs, parent_dir, *ino, filename)))
	{
		DPRINTF("can't add dirent.\n");
		return error;
	}

	return 0;
}

int
v7fs_file_deallocate(struct v7fs_self *fs, struct v7fs_inode *parent_dir,
    const char *name)
{
	v7fs_ino_t ino;
	struct v7fs_inode inode;
	int error;

	DPRINTF("%s\n", name);
	if ((error = v7fs_file_lookup_by_name(fs, parent_dir, name, &ino))) {
		DPRINTF("no such a file: %s\n", name);
		return error;
	}
	DPRINTF("%s->#%d\n", name, ino);
	if ((error = v7fs_inode_load(fs, &inode, ino)))
		return error;

	if (v7fs_inode_isdir(&inode)) {
		char filename[V7FS_NAME_MAX + 1];
		v7fs_dirent_filename(filename, name);
		/* Check parent */
		if (strncmp(filename, "..", V7FS_NAME_MAX) == 0) {
			DPRINTF("can not remove '..'\n");
			return EINVAL; /* t_vnops rename_dotdot */
		}
		/* Check empty */
		if (v7fs_inode_filesize(&inode) !=
		    sizeof(struct v7fs_dirent) * 2 /*"." + ".."*/) {
			DPRINTF("directory not empty.\n");
			return ENOTEMPTY;/* t_vnops dir_noempty, rename_dir(6)*/
		}
		error = v7fs_datablock_size_change(fs, 0, &inode);
		if (error)
			return error;
		inode.nlink = 0;	/* remove this. */
	} else {
		/* Decrement reference count. */
		--inode.nlink;	/* regular file. */
		DPRINTF("%s nlink=%d\n", name, inode.nlink);
	}


	if ((error = v7fs_directory_remove_entry(fs, parent_dir, name)))
		return error;
	DPRINTF("remove dirent\n");

	v7fs_inode_writeback(fs, &inode);

	return 0;
}
Пример #16
0
int
v7fs_vget(struct mount *mp, ino_t ino, struct vnode **vpp)
{
    struct v7fs_mount *v7fsmount = mp->mnt_data;
    struct v7fs_self *fs = v7fsmount->core;
    struct vnode *vp;
    struct v7fs_node *v7fs_node;
    struct v7fs_inode inode;
    int error;

    /* Lookup requested i-node */
    if ((error = v7fs_inode_load(fs, &inode, ino))) {
        DPRINTF("v7fs_inode_load failed.\n");
        return error;
    }

retry:
    mutex_enter(&mntvnode_lock);
    for (v7fs_node = LIST_FIRST(&v7fsmount->v7fs_node_head);
            v7fs_node != NULL; v7fs_node = LIST_NEXT(v7fs_node, link)) {
        if (v7fs_node->inode.inode_number == ino) {
            vp = v7fs_node->vnode;
            mutex_enter(vp->v_interlock);
            mutex_exit(&mntvnode_lock);
            if (vget(vp, LK_EXCLUSIVE) == 0) {
                *vpp = vp;
                return 0;
            } else {
                DPRINTF("retry!\n");
                goto retry;
            }
        }
    }
    mutex_exit(&mntvnode_lock);

    /* Allocate v-node. */
    if ((error = getnewvnode(VT_V7FS, mp, v7fs_vnodeop_p, NULL, &vp))) {
        DPRINTF("getnewvnode error.\n");
        return error;
    }
    /* Lock vnode here */
    vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);

    /* Allocate i-node */
    vp->v_data = pool_get(&v7fs_node_pool, PR_WAITOK);
    memset(vp->v_data, 0, sizeof(*v7fs_node));
    v7fs_node = vp->v_data;
    mutex_enter(&mntvnode_lock);
    LIST_INSERT_HEAD(&v7fsmount->v7fs_node_head, v7fs_node, link);
    mutex_exit(&mntvnode_lock);
    v7fs_node->vnode = vp;
    v7fs_node->v7fsmount = v7fsmount;
    v7fs_node->inode = inode;/*structure copy */
    v7fs_node->lockf = NULL; /* advlock */

    genfs_node_init(vp, &v7fs_genfsops);
    uvm_vnp_setsize(vp, v7fs_inode_filesize(&inode));

    if (ino == V7FS_ROOT_INODE) {
        vp->v_type = VDIR;
        vp->v_vflag |= VV_ROOT;
    } else {
        vp->v_type = v7fs_mode_to_vtype(inode.mode);

        if (vp->v_type == VBLK || vp->v_type == VCHR) {
            dev_t rdev = inode.device;
            vp->v_op = v7fs_specop_p;
            spec_node_init(vp, rdev);
        } else if (vp->v_type == VFIFO) {
            vp->v_op = v7fs_fifoop_p;
        }
    }

    *vpp = vp;

    return 0;
}