* Copyright (c) 1982, 1986, 1989 Regents of the University of California.
* Redistribution is only permitted until one year after the first shipment
* of 4.4BSD by the Regents. Otherwise, redistribution and use in source and
* binary forms are permitted provided that: (1) source distributions retain
* this entire copyright notice and comment, and (2) distributions including
* binaries display the following acknowledgement: This product includes
* software developed by the University of California, Berkeley and its
* contributors'' in the documentation or other materials provided with the
* distribution and in all advertising materials mentioning features or use
* of this software. Neither the name of the University nor the names of
* its contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
* @(#)ufs_vnops.c 7.45 (Berkeley) 6/28/90
#include "../ufs/quota.h"
#include "../ufs/inode.h"
* Global vfs data structures for ufs
struct vnodeops ufs_vnodeops
= {
ufs_getattr
, /* getattr */
ufs_setattr
, /* setattr */
ufs_symlink
, /* symlink */
ufs_readdir
, /* readdir */
ufs_readlink
, /* readlink */
ufs_abortop
, /* abortop */
ufs_inactive
, /* inactive */
ufs_reclaim
, /* reclaim */
ufs_strategy
, /* strategy */
ufs_islocked
, /* islocked */
struct vnodeops spec_inodeops
= {
spec_lookup
, /* lookup */
ufsspec_close
, /* close */
ufs_getattr
, /* getattr */
ufs_setattr
, /* setattr */
ufsspec_write
, /* write */
spec_select
, /* select */
spec_badop
, /* symlink */
spec_badop
, /* readdir */
spec_badop
, /* readlink */
spec_badop
, /* abortop */
ufs_inactive
, /* inactive */
ufs_reclaim
, /* reclaim */
spec_strategy
, /* strategy */
ufs_islocked
, /* islocked */
struct vnodeops fifo_inodeops
= {
fifo_lookup
, /* lookup */
ufsfifo_close
, /* close */
ufs_getattr
, /* getattr */
ufs_setattr
, /* setattr */
ufsfifo_write
, /* write */
fifo_select
, /* select */
fifo_badop
, /* symlink */
fifo_badop
, /* readdir */
fifo_badop
, /* readlink */
fifo_badop
, /* abortop */
ufs_inactive
, /* inactive */
ufs_reclaim
, /* reclaim */
fifo_badop
, /* strategy */
ufs_islocked
, /* islocked */
enum vtype iftovt_tab
[16] = {
VNON
, VFIFO
, VCHR
, VNON
, VDIR
, VNON
, VBLK
, VNON
,
VREG
, VNON
, VLNK
, VNON
, VSOCK
, VNON
, VNON
, VBAD
,
0, IFREG
, IFDIR
, IFBLK
, IFCHR
, IFLNK
, IFSOCK
, IFIFO
, IFMT
,
if (error
= maknode(MAKEIMODE(vap
->va_type
, vap
->va_mode
), ndp
, &ip
))
ufs_mknod(ndp
, vap
, cred
)
register struct vnode
*vp
;
if (error
= maknode(MAKEIMODE(vap
->va_type
, vap
->va_mode
), ndp
, &ip
))
ip
->i_flag
|= IACC
|IUPD
|ICHG
;
if (vap
->va_rdev
!= VNOVAL
) {
* Want to be able to use this to make badblock
* inodes, so don't truncate the dev number.
ip
->i_rdev
= vap
->va_rdev
;
* Remove inode so that it will be reloaded by iget and
* checked to see if it is an alias of an existing entry
* Update the times on the inode.
ufs_close(vp
, fflag
, cred
)
register struct inode
*ip
= VTOI(vp
);
if (vp
->v_usecount
> 1 && !(ip
->i_flag
& ILOCKED
))
ITIMES(ip
, &time
, &time
);
* Check mode permission on inode pointer. Mode is READ, WRITE or EXEC.
* The mode is shifted to select the owner/group/other fields. The
* super user is granted all permissions.
ufs_access(vp
, mode
, cred
)
register struct inode
*ip
= VTOI(vp
);
vprint("ufs_access: not locked", vp
);
panic("ufs_access: not locked");
case VREG
: case VDIR
: case VLNK
:
if (error
= getinoquota(ip
))
* If you're the super-user, you always get access.
* Access check is based on only one of owner, group, public.
* If not owner, then check group. If not a member of the
* group, then check public access.
if (cred
->cr_uid
!= ip
->i_uid
) {
for (i
= 0; i
< cred
->cr_ngroups
; i
++, gp
++)
if ((ip
->i_mode
& mode
) != 0)
ufs_getattr(vp
, vap
, cred
)
register struct vattr
*vap
;
register struct inode
*ip
= VTOI(vp
);
ITIMES(ip
, &time
, &time
);
vap
->va_fsid
= ip
->i_dev
;
vap
->va_fileid
= ip
->i_number
;
vap
->va_mode
= ip
->i_mode
& ~IFMT
;
vap
->va_nlink
= ip
->i_nlink
;
vap
->va_rdev
= (dev_t
)ip
->i_rdev
;
vap
->va_size
= ip
->i_size
;
vap
->va_qsize
= ip
->i_din
.di_qsize
;
vap
->va_atime
.tv_sec
= ip
->i_atime
;
vap
->va_atime
.tv_usec
= 0;
vap
->va_mtime
.tv_sec
= ip
->i_mtime
;
vap
->va_mtime
.tv_usec
= 0;
vap
->va_ctime
.tv_sec
= ip
->i_ctime
;
vap
->va_ctime
.tv_usec
= 0;
vap
->va_flags
= ip
->i_flags
;
/* this doesn't belong here */
vap
->va_blocksize
= BLKDEV_IOSIZE
;
else if (vp
->v_type
== VCHR
)
vap
->va_blocksize
= MAXBSIZE
;
vap
->va_blocksize
= ip
->i_fs
->fs_bsize
;
vap
->va_bytes
= dbtob(ip
->i_blocks
);
vap
->va_type
= vp
->v_type
;
* Set attribute vnode op. called from several syscalls
ufs_setattr(vp
, vap
, cred
)
register struct vnode
*vp
;
register struct vattr
*vap
;
register struct ucred
*cred
;
register struct inode
*ip
= VTOI(vp
);
* Check for unsetable attributes.
if ((vap
->va_type
!= VNON
) || (vap
->va_nlink
!= VNOVAL
) ||
(vap
->va_fsid
!= VNOVAL
) || (vap
->va_fileid
!= VNOVAL
) ||
(vap
->va_blocksize
!= VNOVAL
) || (vap
->va_rdev
!= VNOVAL
) ||
((int)vap
->va_bytes
!= VNOVAL
) || (vap
->va_gen
!= VNOVAL
)) {
* Go through the fields and update iff not VNOVAL.
if (vap
->va_uid
!= (u_short
)VNOVAL
|| vap
->va_gid
!= (u_short
)VNOVAL
)
if (error
= chown1(vp
, vap
->va_uid
, vap
->va_gid
, cred
))
if (vap
->va_size
!= VNOVAL
) {
if (error
= itrunc(ip
, vap
->va_size
, 0)) /* XXX IO_SYNC? */
if (vap
->va_atime
.tv_sec
!= VNOVAL
|| vap
->va_mtime
.tv_sec
!= VNOVAL
) {
if (cred
->cr_uid
!= ip
->i_uid
&&
(error
= suser(cred
, &u
.u_acflag
)))
if (vap
->va_atime
.tv_sec
!= VNOVAL
)
if (vap
->va_mtime
.tv_sec
!= VNOVAL
)
if (error
= iupdat(ip
, &vap
->va_atime
, &vap
->va_mtime
, 1))
if (vap
->va_mode
!= (u_short
)VNOVAL
)
error
= chmod1(vp
, (int)vap
->va_mode
, cred
);
if (vap
->va_flags
!= VNOVAL
) {
if (cred
->cr_uid
!= ip
->i_uid
&&
(error
= suser(cred
, &u
.u_acflag
)))
ip
->i_flags
= vap
->va_flags
;
ip
->i_flags
&= 0xffff0000;
ip
->i_flags
|= (vap
->va_flags
& 0xffff);
* Change the mode on a file.
* Inode must be locked before calling.
register struct vnode
*vp
;
register struct inode
*ip
= VTOI(vp
);
if (cred
->cr_uid
!= ip
->i_uid
&&
(error
= suser(cred
, &u
.u_acflag
)))
if (!groupmember(ip
->i_gid
, cred
))
ip
->i_mode
|= mode
& 07777;
if ((vp
->v_flag
& VTEXT
) && (ip
->i_mode
& ISVTX
) == 0)
* Perform chown operation on inode ip;
* inode must be locked prior to call.
chown1(vp
, uid
, gid
, cred
)
register struct vnode
*vp
;
register struct inode
*ip
= VTOI(vp
);
if (uid
== (u_short
)VNOVAL
)
if (gid
== (u_short
)VNOVAL
)
* If we don't own the file, are trying to change the owner
* of the file, or are not a member of the target group,
* the caller must be superuser or the call fails.
if ((cred
->cr_uid
!= ip
->i_uid
|| uid
!= ip
->i_uid
||
!groupmember((gid_t
)gid
, cred
)) &&
(error
= suser(cred
, &u
.u_acflag
)))
if (error
= getinoquota(ip
))
dqrele(vp
, ip
->i_dquot
[USRQUOTA
]);
ip
->i_dquot
[USRQUOTA
] = NODQUOT
;
dqrele(vp
, ip
->i_dquot
[GRPQUOTA
]);
ip
->i_dquot
[GRPQUOTA
] = NODQUOT
;
(void) chkdq(ip
, -change
, cred
, CHOWN
);
(void) chkiq(ip
, -1, cred
, CHOWN
);
for (i
= 0; i
< MAXQUOTAS
; i
++) {
dqrele(vp
, ip
->i_dquot
[i
]);
ip
->i_dquot
[i
] = NODQUOT
;
if ((error
= getinoquota(ip
)) == 0) {
dqrele(vp
, ip
->i_dquot
[USRQUOTA
]);
ip
->i_dquot
[USRQUOTA
] = NODQUOT
;
dqrele(vp
, ip
->i_dquot
[GRPQUOTA
]);
ip
->i_dquot
[GRPQUOTA
] = NODQUOT
;
if ((error
= chkdq(ip
, change
, cred
, CHOWN
)) == 0) {
if ((error
= chkiq(ip
, 1, cred
, CHOWN
)) == 0)
(void) chkdq(ip
, -change
, cred
, CHOWN
|FORCE
);
for (i
= 0; i
< MAXQUOTAS
; i
++) {
dqrele(vp
, ip
->i_dquot
[i
]);
ip
->i_dquot
[i
] = NODQUOT
;
if (getinoquota(ip
) == 0) {
dqrele(vp
, ip
->i_dquot
[USRQUOTA
]);
ip
->i_dquot
[USRQUOTA
] = NODQUOT
;
dqrele(vp
, ip
->i_dquot
[GRPQUOTA
]);
ip
->i_dquot
[GRPQUOTA
] = NODQUOT
;
(void) chkdq(ip
, change
, cred
, FORCE
|CHOWN
);
(void) chkiq(ip
, 1, cred
, FORCE
|CHOWN
);
panic("chown: lost quota");
if (ouid
!= uid
|| ogid
!= gid
)
if (ouid
!= uid
&& cred
->cr_uid
!= 0)
if (ogid
!= gid
&& cred
->cr_uid
!= 0)
ufs_read(vp
, uio
, ioflag
, cred
)
register struct uio
*uio
;
register struct inode
*ip
= VTOI(vp
);
daddr_t lbn
, bn
, rablock
;
int size
, diff
, error
= 0;
if (uio
->uio_rw
!= UIO_READ
)
type
= ip
->i_mode
& IFMT
;
if (type
!= IFDIR
&& type
!= IFREG
&& type
!= IFLNK
)
lbn
= lblkno(fs
, uio
->uio_offset
);
on
= blkoff(fs
, uio
->uio_offset
);
n
= MIN((unsigned)(fs
->fs_bsize
- on
), uio
->uio_resid
);
diff
= ip
->i_size
- uio
->uio_offset
;
size
= blksize(fs
, ip
, lbn
);
if (vp
->v_lastr
+ 1 == lbn
&&
lblktosize(fs
, rablock
) < ip
->i_size
)
error
= breada(ITOV(ip
), lbn
, size
, rablock
,
blksize(fs
, ip
, rablock
), NOCRED
, &bp
);
error
= bread(ITOV(ip
), lbn
, size
, NOCRED
, &bp
);
n
= MIN(n
, size
- bp
->b_resid
);
error
= uiomove(bp
->b_un
.b_addr
+ on
, (int)n
, uio
);
if (n
+ on
== fs
->fs_bsize
|| uio
->uio_offset
== ip
->i_size
)
} while (error
== 0 && uio
->uio_resid
> 0 && n
!= 0);
ufs_write(vp
, uio
, ioflag
, cred
)
register struct vnode
*vp
;
register struct inode
*ip
= VTOI(vp
);
int count
, size
, resid
, error
= 0;
if (uio
->uio_rw
!= UIO_WRITE
)
uio
->uio_offset
= ip
->i_size
;
if ((ioflag
& IO_SYNC
) == 0)
panic("ufs_write nonsync dir write");
* Maybe this should be above the vnode op call, but so long as
* file servers have no limits, i don't think it matters
if (vp
->v_type
== VREG
&&
uio
->uio_offset
+ uio
->uio_resid
>
u
.u_rlimit
[RLIMIT_FSIZE
].rlim_cur
) {
psignal(u
.u_procp
, SIGXFSZ
);
lbn
= lblkno(fs
, uio
->uio_offset
);
on
= blkoff(fs
, uio
->uio_offset
);
n
= MIN((unsigned)(fs
->fs_bsize
- on
), uio
->uio_resid
);
if (error
= balloc(ip
, lbn
, (int)(on
+ n
), &bp
, flags
))
if (uio
->uio_offset
+ n
> ip
->i_size
)
ip
->i_size
= uio
->uio_offset
+ n
;
size
= blksize(fs
, ip
, lbn
);
count
= howmany(size
, CLBYTES
);
for (i
= 0; i
< count
; i
++)
munhash(ip
->i_devvp
, bn
+ i
* CLBYTES
/ DEV_BSIZE
);
n
= MIN(n
, size
- bp
->b_resid
);
error
= uiomove(bp
->b_un
.b_addr
+ on
, n
, uio
);
else if (n
+ on
== fs
->fs_bsize
) {
ip
->i_mode
&= ~(ISUID
|ISGID
);
} while (error
== 0 && uio
->uio_resid
> 0 && n
!= 0);
if (error
&& (ioflag
& IO_UNIT
)) {
(void) itrunc(ip
, osize
, ioflag
& IO_SYNC
);
uio
->uio_offset
-= resid
- uio
->uio_resid
;
if (!error
&& (ioflag
& IO_SYNC
))
error
= iupdat(ip
, &time
, &time
, 1);
ufs_ioctl(vp
, com
, data
, fflag
, cred
)
ufs_select(vp
, which
, fflags
, cred
)
* NB Currently unsupported.
ufs_mmap(vp
, fflags
, cred
)
ufs_fsync(vp
, fflags
, cred
, waitfor
)
struct inode
*ip
= VTOI(vp
);
vflushbuf(vp
, waitfor
== MNT_WAIT
? B_SYNC
: 0);
return (iupdat(ip
, &time
, &time
, waitfor
== MNT_WAIT
));
* Nothing to do, so just return.
ufs_seek(vp
, oldoff
, newoff
, cred
)
* Hard to avoid races here, especially
* in unlinking directories.
register struct inode
*ip
, *dp
;
register struct vnode
*vp
;
register struct nameidata
*ndp
;
register struct inode
*ip
= VTOI(vp
);
if (ip
->i_nlink
== LINK_MAX
- 1) {
error
= iupdat(ip
, &time
, &time
, 1);
error
= direnter(ip
, ndp
);
* but ``atomically''. Can't do full commit without saving state in the
* inode on disk which isn't feasible at this time. Best we can do is
* always guarantee the target exists.
* 1) Bump link count on source while we're linking it to the
* target. This also ensure the inode won't be deleted out
* from underneath us while we work (it may be truncated by
* a concurrent `trunc' or `open' for creation).
* 2) Link source to destination. If destination already exists,
* 3) Unlink source reference to inode if still around. If a
* directory was moved and the parent of the destination
* is different from the source, patch the ".." entry in the
register struct nameidata
*fndp
, *tndp
;
register struct inode
*ip
, *xp
, *dp
;
struct dirtemplate dirbuf
;
int doingdirectory
= 0, oldparent
= 0, newparent
= 0;
if ((ip
->i_mode
&IFMT
) == IFDIR
) {
register struct direct
*d
= &fndp
->ni_dent
;
* Avoid ".", "..", and aliases of "." for obvious reasons.
if ((d
->d_namlen
== 1 && d
->d_name
[0] == '.') || dp
== ip
||
fndp
->ni_isdotdot
|| (ip
->i_flag
& IRENAME
)) {
oldparent
= dp
->i_number
;
* 1) Bump link count while we're moving stuff
* around. If we crash somewhere before
* completing our work, the link count
* may be wrong, but correctable.
error
= iupdat(ip
, &time
, &time
, 1);
* When the target exists, both the directory
* and target vnodes are returned locked.
* If ".." must be changed (ie the directory gets a new
* parent) then the source directory must not be in the
* directory heirarchy above the target, as this would
* orphan everything below the source directory. Also
* the user must have write permission in the source so
* as to be able to change "..". We must repeat the call
* to namei, as the parent directory is unlocked by the
if (oldparent
!= dp
->i_number
)
newparent
= dp
->i_number
;
if (doingdirectory
&& newparent
) {
error
= ufs_access(fndp
->ni_vp
, VWRITE
, tndp
->ni_cred
);
tndp
->ni_nameiop
= RENAME
| LOCKPARENT
| LOCKLEAF
| NOCACHE
;
if (error
= checkpath(ip
, dp
, tndp
->ni_cred
))
} while (dp
!= VTOI(tndp
->ni_dvp
));
* 2) If target doesn't exist, link the target
* to the source and unlink the source.
* Otherwise, rewrite the target directory
* entry to reference the source inode and
* expunge the original entry's existence.
if (dp
->i_dev
!= ip
->i_dev
)
* Account for ".." in new directory.
* When source and destination have the same
* parent we don't fool with the link count.
if (doingdirectory
&& newparent
) {
error
= iupdat(dp
, &time
, &time
, 1);
if (error
= direnter(ip
, tndp
))
if (xp
->i_dev
!= dp
->i_dev
|| xp
->i_dev
!= ip
->i_dev
)
* Short circuit rename(foo, foo).
if (xp
->i_number
== ip
->i_number
)
panic("rename: same file");
* If the parent directory is "sticky", then the user must
* own the parent directory, or the destination of the rename,
* otherwise the destination may not be changed (except by
* root). This implements append-only directories.
if ((dp
->i_mode
& ISVTX
) && tndp
->ni_cred
->cr_uid
!= 0 &&
tndp
->ni_cred
->cr_uid
!= dp
->i_uid
&&
xp
->i_uid
!= tndp
->ni_cred
->cr_uid
) {
* Target must be empty if a directory
* and have no links to it.
* Also, insure source and target are
* compatible (both directories, or both
if ((xp
->i_mode
&IFMT
) == IFDIR
) {
if (!dirempty(xp
, dp
->i_number
, tndp
->ni_cred
) ||
} else if (doingdirectory
) {
if (error
= dirrewrite(dp
, ip
, tndp
))
* Adjust the link count of the target to
* reflect the dirrewrite above. If this is
* a directory it is empty and there are
* no links to it, so we can squash the inode and
* any space associated with it. We disallowed
* renaming over top of a directory with links to
* it above, as the remaining link would point to
* a directory without "." or ".." entries.
panic("rename: linked directory");
error
= itrunc(xp
, (u_long
)0, IO_SYNC
);
fndp
->ni_nameiop
= DELETE
| LOCKPARENT
| LOCKLEAF
;
if (fndp
->ni_vp
!= NULL
) {
if (fndp
->ni_dvp
!= NULL
)
* Ensure that the directory entry still exists and has not
* changed while the new name has been entered. If the source is
* a file then the entry may have been unlinked or renamed. In
* either case there is no further work to be done. If the source
* is a directory then it cannot have been rmdir'ed; its link
* count of three would cause a rmdir to fail with ENOTEMPTY.
* The IRENAME flag ensures that it cannot be moved by another
panic("rename: lost dir entry");
* If the source is a directory with a
* new parent, the link count of the old
* parent directory must be decremented
* and ".." set to point to the new parent.
if (doingdirectory
&& newparent
) {
error
= vn_rdwr(UIO_READ
, ITOV(xp
), (caddr_t
)&dirbuf
,
sizeof (struct dirtemplate
), (off_t
)0,
UIO_SYSSPACE
, IO_NODELOCKED
,
tndp
->ni_cred
, (int *)0);
if (dirbuf
.dotdot_namlen
!= 2 ||
dirbuf
.dotdot_name
[0] != '.' ||
dirbuf
.dotdot_name
[1] != '.') {
dirbad(xp
, 12, "rename: mangled dir");
dirbuf
.dotdot_ino
= newparent
;
(void) vn_rdwr(UIO_WRITE
, ITOV(xp
),
sizeof (struct dirtemplate
),
tndp
->ni_cred
, (int *)0);
* A virgin directory (no blushing please).
struct dirtemplate mastertemplate
= {
0, DIRBLKSIZ
- 12, 2, ".."
register struct inode
*ip
, *dp
;
struct dirtemplate dirtemplate
;
dmode
= vap
->va_mode
&0777;
* Must simulate part of maknode here
* in order to acquire the inode, but
* not have it entered in the parent
* directory. The entry is made later
* after writing "." and ".." entries out.
if (error
= ialloc(dp
, dirpref(dp
->i_fs
), dmode
, ndp
->ni_cred
, &tip
)) {
ip
->i_uid
= ndp
->ni_cred
->cr_uid
;
if ((error
= getinoquota(ip
)) ||
(error
= chkiq(ip
, 1, ndp
->ni_cred
, 0))) {
ifree(ip
, ip
->i_number
, dmode
);
ip
->i_flag
|= IACC
|IUPD
|ICHG
;
ITOV(ip
)->v_type
= VDIR
; /* Rest init'd in iget() */
error
= iupdat(ip
, &time
, &time
, 1);
* Bump link count in parent directory
* to reflect work done below. Should
* be done before reference is created
* so reparation is possible if we crash.
error
= iupdat(dp
, &time
, &time
, 1);
* Initialize directory with "."
* and ".." from static template.
dirtemplate
= mastertemplate
;
dirtemplate
.dot_ino
= ip
->i_number
;
dirtemplate
.dotdot_ino
= dp
->i_number
;
error
= vn_rdwr(UIO_WRITE
, ITOV(ip
), (caddr_t
)&dirtemplate
,
sizeof (dirtemplate
), (off_t
)0, UIO_SYSSPACE
,
IO_NODELOCKED
|IO_SYNC
, ndp
->ni_cred
, (int *)0);
if (DIRBLKSIZ
> dp
->i_fs
->fs_fsize
) {
panic("mkdir: blksize"); /* XXX - should grow w/balloc() */
* Directory all set up, now
* install the entry for it in
error
= direnter(ip
, ndp
);
ndp
->ni_nameiop
= LOOKUP
| NOCACHE
;
* No need to do an explicit itrunc here,
* vrele will do this for us because we set
register struct nameidata
*ndp
;
register struct inode
*ip
, *dp
;
* Verify the directory is empty (and valid).
* (Rmdir ".." won't be valid since
* ".." will contain a reference to
* the current directory and thus be
if (ip
->i_nlink
!= 2 || !dirempty(ip
, dp
->i_number
, ndp
->ni_cred
)) {
* Delete reference to directory before purging
* inode. If we crash in between, the directory
* will be reattached to lost+found,
if (error
= dirremove(ndp
))
* Truncate inode. The only stuff left
* in the directory is "." and "..". The
* "." reference is inconsequential since
* we're quashing it. The ".." reference
* has already been adjusted above. We've
* removed the "." reference and the reference
* in the parent directory, but there may be
* other hard links so decrement by 2 and
* worry about them later.
error
= itrunc(ip
, (u_long
)0, IO_SYNC
);
* symlink -- make a symbolic link
ufs_symlink(ndp
, vap
, target
)
error
= maknode(IFLNK
| vap
->va_mode
, ndp
, &ip
);
error
= vn_rdwr(UIO_WRITE
, ITOV(ip
), target
, strlen(target
), (off_t
)0,
UIO_SYSSPACE
, IO_NODELOCKED
, ndp
->ni_cred
, (int *)0);
* Vnode op for read and write
ufs_readdir(vp
, uio
, cred
, eofflagp
)
register struct uio
*uio
;
count
&= ~(DIRBLKSIZ
- 1);
lost
= uio
->uio_resid
- count
;
if (count
< DIRBLKSIZ
|| (uio
->uio_offset
& (DIRBLKSIZ
-1)))
uio
->uio_iov
->iov_len
= count
;
error
= ufs_read(vp
, uio
, 0, cred
);
if ((VTOI(vp
)->i_size
- uio
->uio_offset
) <= 0)
* Return target name of a symbolic link
ufs_readlink(vp
, uiop
, cred
)
return (ufs_read(vp
, uiop
, 0, cred
));
* Ufs abort op, called after namei() when a CREATE/DELETE isn't actually
* done. Nothing to do at the moment.
register struct inode
*ip
= VTOI(vp
);
register struct inode
*ip
= VTOI(vp
);
if (!(ip
->i_flag
& ILOCKED
))
panic("ufs_unlock NOT LOCKED");
* Check for a locked inode.
if (VTOI(vp
)->i_flag
& ILOCKED
)
ufs_bmap(vp
, bn
, vpp
, bnp
)
struct inode
*ip
= VTOI(vp
);
return (bmap(ip
, bn
, bnp
));
* Calculate the logical to physical mapping if not done already,
* then call the device strategy routine.
register struct inode
*ip
= VTOI(bp
->b_vp
);
if (bp
->b_vp
->v_type
== VBLK
|| bp
->b_vp
->v_type
== VCHR
)
panic("ufs_strategy: spec");
if (bp
->b_blkno
== bp
->b_lblkno
) {
if (error
= bmap(ip
, bp
->b_lblkno
, &bp
->b_blkno
))
if ((long)bp
->b_blkno
== -1)
if ((long)bp
->b_blkno
== -1) {
last
= start
+ btodb(bp
->b_bcount
) - 1;
for (ep
= buf
; ep
< ebp
; ep
++) {
if (ep
== bp
|| (ep
->b_flags
& B_INVAL
) ||
if (VOP_BMAP(ep
->b_vp
, (daddr_t
)0, &vp
, (daddr_t
)0))
if (ep
->b_bcount
== 0 || ep
->b_blkno
> last
||
ep
->b_blkno
+ btodb(ep
->b_bcount
) <= start
)
vprint("Disk overlap", vp
);
printf("\tstart %d, end %d overlap start %d, end %d\n",
start
, last
, ep
->b_blkno
,
ep
->b_blkno
+ btodb(ep
->b_bcount
) - 1);
panic("Disk buffer overlap");
(*(vp
->v_op
->vn_strategy
))(bp
);
* Print out the contents of an inode.
register struct inode
*ip
= VTOI(vp
);
printf("tag VT_UFS, ino %d, on dev %d, %d", ip
->i_number
,
major(ip
->i_dev
), minor(ip
->i_dev
));
printf("%s\n", (ip
->i_flag
& ILOCKED
) ? " (LOCKED)" : "");
printf("\towner pid %d", ip
->i_spare0
);
printf(" waiting pid %d", ip
->i_spare1
);
* Read wrapper for special devices.
ufsspec_read(vp
, uio
, ioflag
, cred
)
VTOI(vp
)->i_flag
|= IACC
;
return (spec_read(vp
, uio
, ioflag
, cred
));
* Write wrapper for special devices.
ufsspec_write(vp
, uio
, ioflag
, cred
)
* Set update and change flags.
VTOI(vp
)->i_flag
|= IUPD
|ICHG
;
return (spec_write(vp
, uio
, ioflag
, cred
));
* Close wrapper for special devices.
* Update the times on the inode then do device close.
ufsspec_close(vp
, fflag
, cred
)
register struct inode
*ip
= VTOI(vp
);
if (vp
->v_usecount
> 1 && !(ip
->i_flag
& ILOCKED
))
ITIMES(ip
, &time
, &time
);
return (spec_close(vp
, fflag
, cred
));
* Read wrapper for fifo's
ufsfifo_read(vp
, uio
, ioflag
, cred
)
VTOI(vp
)->i_flag
|= IACC
;
return (fifo_read(vp
, uio
, ioflag
, cred
));
* Write wrapper for fifo's.
ufsfifo_write(vp
, uio
, ioflag
, cred
)
* Set update and change flags.
VTOI(vp
)->i_flag
|= IUPD
|ICHG
;
return (fifo_write(vp
, uio
, ioflag
, cred
));
* Close wrapper for fifo's.
* Update the times on the inode then do device close.
ufsfifo_close(vp
, fflag
, cred
)
register struct inode
*ip
= VTOI(vp
);
if (vp
->v_usecount
> 1 && !(ip
->i_flag
& ILOCKED
))
ITIMES(ip
, &time
, &time
);
return (fifo_close(vp
, fflag
, cred
));
register struct nameidata
*ndp
;
register struct inode
*ip
;
register struct inode
*pdir
= VTOI(ndp
->ni_dvp
);
if ((mode
& IFMT
) == IFDIR
)
ipref
= dirpref(pdir
->i_fs
);
if (error
= ialloc(pdir
, ipref
, mode
, ndp
->ni_cred
, &tip
)) {
ip
->i_uid
= ndp
->ni_cred
->cr_uid
;
if ((error
= getinoquota(ip
)) ||
(error
= chkiq(ip
, 1, ndp
->ni_cred
, 0))) {
ifree(ip
, ip
->i_number
, mode
);
ip
->i_flag
|= IACC
|IUPD
|ICHG
;
ITOV(ip
)->v_type
= IFTOVT(mode
); /* Rest init'd in iget() */
if ((ip
->i_mode
& ISGID
) && !groupmember(ip
->i_gid
, ndp
->ni_cred
) &&
suser(ndp
->ni_cred
, NULL
))
* Make sure inode goes to disk before directory entry.
if (error
= iupdat(ip
, &time
, &time
, 1))
if (error
= direnter(ip
, ndp
)) {
* Write error occurred trying to update the inode
* or the directory so must deallocate the inode.