123405Smckusick /* 2*51155Sbostic * Copyright (c) 1982, 1986, 1989, 1991 Regents of the University of California. 337737Smckusick * All rights reserved. 423405Smckusick * 544539Sbostic * %sccs.include.redist.c% 637737Smckusick * 7*51155Sbostic * @(#)lfs_vnops.c 7.66 (Berkeley) 09/20/91 823405Smckusick */ 937Sbill 1017101Sbloom #include "param.h" 1117101Sbloom #include "systm.h" 1247571Skarels #include "namei.h" 1347571Skarels #include "resourcevar.h" 1417101Sbloom #include "kernel.h" 1517101Sbloom #include "file.h" 1617101Sbloom #include "stat.h" 1717101Sbloom #include "buf.h" 1817101Sbloom #include "proc.h" 1937737Smckusick #include "conf.h" 2017101Sbloom #include "mount.h" 2137737Smckusick #include "vnode.h" 2240653Smckusick #include "specdev.h" 2348039Smckusick #include "fifo.h" 2446207Smckusick #include "malloc.h" 2537Sbill 26*51155Sbostic #include "../ufs/lockf.h" 27*51155Sbostic #include "../ufs/quota.h" 28*51155Sbostic #include "../ufs/inode.h" 29*51155Sbostic #include "../ufs/dir.h" 3051134Sbostic #include "lfs.h" 31*51155Sbostic #include "lfs_extern.h" 3247571Skarels 3351134Sbostic static int chmod1 __P((struct vnode *, int, struct proc *)); 3451134Sbostic static int chown1 __P((struct vnode *, uid_t, gid_t, struct proc *)); 3551134Sbostic static int maknode __P((int, struct nameidata *, struct inode **)); 3651134Sbostic 379167Ssam /* 3837737Smckusick * Create a regular file 399167Ssam */ 4051134Sbostic lfs_create(ndp, vap, p) 4137737Smckusick struct nameidata *ndp; 4237737Smckusick struct vattr *vap; 4348039Smckusick struct proc *p; 446254Sroot { 4537737Smckusick struct inode *ip; 4637737Smckusick int error; 476254Sroot 48*51155Sbostic printf("lfs_create\n"); 4937737Smckusick if (error = maknode(MAKEIMODE(vap->va_type, vap->va_mode), ndp, &ip)) 5037737Smckusick return (error); 5137737Smckusick ndp->ni_vp = ITOV(ip); 5237737Smckusick return (0); 536254Sroot } 546254Sroot 5537Sbill /* 5637737Smckusick * Mknod vnode call 576254Sroot */ 5837737Smckusick /* ARGSUSED */ 5951134Sbostic lfs_mknod(ndp, vap, cred, p) 6037737Smckusick struct nameidata *ndp; 6137737Smckusick struct ucred *cred; 6237737Smckusick struct vattr *vap; 6348039Smckusick struct proc *p; 646254Sroot { 6539435Smckusick register struct vnode *vp; 6637737Smckusick struct inode *ip; 6737737Smckusick int error; 686254Sroot 69*51155Sbostic printf("lfs_mknod\n"); 7037737Smckusick if (error = maknode(MAKEIMODE(vap->va_type, vap->va_mode), ndp, &ip)) 7137737Smckusick return (error); 7240290Smckusick ip->i_flag |= IACC|IUPD|ICHG; 7340290Smckusick if (vap->va_rdev != VNOVAL) { 7437737Smckusick /* 7537737Smckusick * Want to be able to use this to make badblock 7637737Smckusick * inodes, so don't truncate the dev number. 7737737Smckusick */ 7839608Smckusick ip->i_rdev = vap->va_rdev; 7912756Ssam } 8037737Smckusick /* 8137737Smckusick * Remove inode so that it will be reloaded by iget and 8237737Smckusick * checked to see if it is an alias of an existing entry 8337737Smckusick * in the inode cache. 8437737Smckusick */ 8540290Smckusick vp = ITOV(ip); 8640290Smckusick vput(vp); 8739435Smckusick vp->v_type = VNON; 8839435Smckusick vgone(vp); 8937737Smckusick return (0); 906254Sroot } 916254Sroot 9237737Smckusick /* ARGSUSED */ 9351134Sbostic lfs_getattr(vp, vap, cred, p) 9437737Smckusick struct vnode *vp; 9537737Smckusick register struct vattr *vap; 9637737Smckusick struct ucred *cred; 9748039Smckusick struct proc *p; 986254Sroot { 9937737Smckusick register struct inode *ip = VTOI(vp); 1006254Sroot 101*51155Sbostic printf("lfs_getattr\n"); 10237737Smckusick ITIMES(ip, &time, &time); 1036254Sroot /* 10437737Smckusick * Copy from inode table 1056254Sroot */ 10637737Smckusick vap->va_fsid = ip->i_dev; 10737737Smckusick vap->va_fileid = ip->i_number; 10837737Smckusick vap->va_mode = ip->i_mode & ~IFMT; 10937737Smckusick vap->va_nlink = ip->i_nlink; 11037737Smckusick vap->va_uid = ip->i_uid; 11137737Smckusick vap->va_gid = ip->i_gid; 11237737Smckusick vap->va_rdev = (dev_t)ip->i_rdev; 11341312Smckusick #ifdef tahoe 11441312Smckusick vap->va_size = ip->i_size; 11541312Smckusick vap->va_size_rsv = 0; 11641312Smckusick #else 11740641Smckusick vap->va_qsize = ip->i_din.di_qsize; 11841312Smckusick #endif 11937737Smckusick vap->va_atime.tv_sec = ip->i_atime; 12038578Smckusick vap->va_atime.tv_usec = 0; 12137737Smckusick vap->va_mtime.tv_sec = ip->i_mtime; 12238578Smckusick vap->va_mtime.tv_usec = 0; 12337737Smckusick vap->va_ctime.tv_sec = ip->i_ctime; 12438578Smckusick vap->va_ctime.tv_usec = 0; 12538254Smckusick vap->va_flags = ip->i_flags; 12638254Smckusick vap->va_gen = ip->i_gen; 12737737Smckusick /* this doesn't belong here */ 12837737Smckusick if (vp->v_type == VBLK) 12937737Smckusick vap->va_blocksize = BLKDEV_IOSIZE; 13037737Smckusick else if (vp->v_type == VCHR) 13137737Smckusick vap->va_blocksize = MAXBSIZE; 1327142Smckusick else 133*51155Sbostic vap->va_blocksize = ip->i_lfs->lfs_bsize; /* LFS */ 13438657Smckusick vap->va_bytes = dbtob(ip->i_blocks); 13540641Smckusick vap->va_bytes_rsv = 0; 13637737Smckusick vap->va_type = vp->v_type; 13737737Smckusick return (0); 1386254Sroot } 1396254Sroot 1406254Sroot /* 14137737Smckusick * Set attribute vnode op. called from several syscalls 1426254Sroot */ 14351134Sbostic lfs_setattr(vp, vap, cred, p) 14437737Smckusick register struct vnode *vp; 14537737Smckusick register struct vattr *vap; 14637737Smckusick register struct ucred *cred; 14748039Smckusick struct proc *p; 1486254Sroot { 14937737Smckusick register struct inode *ip = VTOI(vp); 15037737Smckusick int error = 0; 1516254Sroot 152*51155Sbostic printf("lfs_setattr\n"); 15337737Smckusick /* 154*51155Sbostic * Check for unsettable attributes. 15537737Smckusick */ 15637737Smckusick if ((vap->va_type != VNON) || (vap->va_nlink != VNOVAL) || 15737737Smckusick (vap->va_fsid != VNOVAL) || (vap->va_fileid != VNOVAL) || 15837737Smckusick (vap->va_blocksize != VNOVAL) || (vap->va_rdev != VNOVAL) || 15938254Smckusick ((int)vap->va_bytes != VNOVAL) || (vap->va_gen != VNOVAL)) { 16037737Smckusick return (EINVAL); 16116540Ssam } 16237737Smckusick /* 16337737Smckusick * Go through the fields and update iff not VNOVAL. 16437737Smckusick */ 16537737Smckusick if (vap->va_uid != (u_short)VNOVAL || vap->va_gid != (u_short)VNOVAL) 16647571Skarels if (error = chown1(vp, vap->va_uid, vap->va_gid, p)) 16737737Smckusick return (error); 16837737Smckusick if (vap->va_size != VNOVAL) { 16937737Smckusick if (vp->v_type == VDIR) 170*51155Sbostic return (EISDIR); /* LFS */ 171*51155Sbostic if (error = lfs_itrunc(ip, vap->va_size, 0)) /* XXX IO_SYNC? */ 17237737Smckusick return (error); 17313878Ssam } 17437737Smckusick if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL) { 17537773Smckusick if (cred->cr_uid != ip->i_uid && 17647571Skarels (error = suser(cred, &p->p_acflag))) 17737773Smckusick return (error); 17837737Smckusick if (vap->va_atime.tv_sec != VNOVAL) 17937737Smckusick ip->i_flag |= IACC; 18037737Smckusick if (vap->va_mtime.tv_sec != VNOVAL) 18137737Smckusick ip->i_flag |= IUPD; 182*51155Sbostic ip->i_flag |= ICHG; /* LFS */ 183*51155Sbostic if (error = lfs_iupdat(ip, &vap->va_atime, &vap->va_mtime, 1)) 18437737Smckusick return (error); 1856254Sroot } 18637737Smckusick if (vap->va_mode != (u_short)VNOVAL) 18747571Skarels error = chmod1(vp, (int)vap->va_mode, p); 18838254Smckusick if (vap->va_flags != VNOVAL) { 18938254Smckusick if (cred->cr_uid != ip->i_uid && 19047571Skarels (error = suser(cred, &p->p_acflag))) 19138254Smckusick return (error); 19238254Smckusick if (cred->cr_uid == 0) { 19338254Smckusick ip->i_flags = vap->va_flags; 19438254Smckusick } else { 19538254Smckusick ip->i_flags &= 0xffff0000; 19638254Smckusick ip->i_flags |= (vap->va_flags & 0xffff); 19738254Smckusick } 19838254Smckusick ip->i_flag |= ICHG; 19938254Smckusick } 20037737Smckusick return (error); 2016254Sroot } 2026254Sroot 2036254Sroot /* 20439608Smckusick * Vnode op for reading. 20539608Smckusick */ 20637737Smckusick /* ARGSUSED */ 20751134Sbostic lfs_read(vp, uio, ioflag, cred) 20839608Smckusick struct vnode *vp; 20939608Smckusick register struct uio *uio; 21039608Smckusick int ioflag; 21139608Smckusick struct ucred *cred; 21239608Smckusick { 21339608Smckusick register struct inode *ip = VTOI(vp); 214*51155Sbostic register LFS *fs; /* LFS */ 21539608Smckusick struct buf *bp; 21639608Smckusick daddr_t lbn, bn, rablock; 21739896Smckusick int size, diff, error = 0; 21839608Smckusick long n, on, type; 21939608Smckusick 220*51155Sbostic printf("lfs_read: ino %d\n", ip->i_number); 22148039Smckusick #ifdef DIAGNOSTIC 22239608Smckusick if (uio->uio_rw != UIO_READ) 22339608Smckusick panic("ufs_read mode"); 22439608Smckusick type = ip->i_mode & IFMT; 22539608Smckusick if (type != IFDIR && type != IFREG && type != IFLNK) 22639608Smckusick panic("ufs_read type"); 22748039Smckusick #endif 22839608Smckusick if (uio->uio_resid == 0) 22939608Smckusick return (0); 23039608Smckusick if (uio->uio_offset < 0) 23139608Smckusick return (EINVAL); 23239608Smckusick ip->i_flag |= IACC; 233*51155Sbostic 234*51155Sbostic fs = ip->i_lfs; /* LFS */ 23539608Smckusick do { 23639608Smckusick lbn = lblkno(fs, uio->uio_offset); 23739608Smckusick on = blkoff(fs, uio->uio_offset); 238*51155Sbostic n = MIN((unsigned)(fs->lfs_bsize - on), uio->uio_resid); 23939608Smckusick diff = ip->i_size - uio->uio_offset; 24039608Smckusick if (diff <= 0) 24139608Smckusick return (0); 24239608Smckusick if (diff < n) 24339608Smckusick n = diff; 244*51155Sbostic size = blksize(fs); /* LFS */ 24539674Smckusick rablock = lbn + 1; 24639896Smckusick if (vp->v_lastr + 1 == lbn && 24739896Smckusick lblktosize(fs, rablock) < ip->i_size) 24839896Smckusick error = breada(ITOV(ip), lbn, size, rablock, 249*51155Sbostic blksize(fs), NOCRED, &bp); 25039608Smckusick else 25139674Smckusick error = bread(ITOV(ip), lbn, size, NOCRED, &bp); 25239815Smckusick vp->v_lastr = lbn; 25339608Smckusick n = MIN(n, size - bp->b_resid); 25439608Smckusick if (error) { 25539608Smckusick brelse(bp); 25639608Smckusick return (error); 25739608Smckusick } 25839608Smckusick error = uiomove(bp->b_un.b_addr + on, (int)n, uio); 259*51155Sbostic if (n + on == fs->lfs_bsize || uio->uio_offset == ip->i_size) 26039608Smckusick bp->b_flags |= B_AGE; 26139608Smckusick brelse(bp); 26239608Smckusick } while (error == 0 && uio->uio_resid > 0 && n != 0); 26339608Smckusick return (error); 26439608Smckusick } 26539608Smckusick 26639608Smckusick /* 26739608Smckusick * Vnode op for writing. 26839608Smckusick */ 26951134Sbostic lfs_write(vp, uio, ioflag, cred) 27039608Smckusick register struct vnode *vp; 27139608Smckusick struct uio *uio; 27239608Smckusick int ioflag; 27339608Smckusick struct ucred *cred; 27439608Smckusick { 27548039Smckusick struct proc *p = uio->uio_procp; 27639608Smckusick register struct inode *ip = VTOI(vp); 27739608Smckusick register struct fs *fs; 27839608Smckusick struct buf *bp; 27939608Smckusick daddr_t lbn, bn; 28039608Smckusick u_long osize; 28145722Smckusick int n, on, flags; 28245722Smckusick int size, resid, error = 0; 28339608Smckusick 284*51155Sbostic printf("lfs_write ino %d\n", ip->i_number); 28548039Smckusick #ifdef DIAGNOSTIC 28639608Smckusick if (uio->uio_rw != UIO_WRITE) 28739608Smckusick panic("ufs_write mode"); 28848039Smckusick #endif 28939608Smckusick switch (vp->v_type) { 29039608Smckusick case VREG: 29139608Smckusick if (ioflag & IO_APPEND) 29239608Smckusick uio->uio_offset = ip->i_size; 29339608Smckusick /* fall through */ 29439608Smckusick case VLNK: 29539608Smckusick break; 29639608Smckusick 29739608Smckusick case VDIR: 29839608Smckusick if ((ioflag & IO_SYNC) == 0) 29939608Smckusick panic("ufs_write nonsync dir write"); 30039608Smckusick break; 30139608Smckusick 30239608Smckusick default: 30339608Smckusick panic("ufs_write type"); 30439608Smckusick } 30539608Smckusick if (uio->uio_offset < 0) 30639608Smckusick return (EINVAL); 30739608Smckusick if (uio->uio_resid == 0) 30839608Smckusick return (0); 30939608Smckusick /* 31039608Smckusick * Maybe this should be above the vnode op call, but so long as 31139608Smckusick * file servers have no limits, i don't think it matters 31239608Smckusick */ 31349679Smckusick if (vp->v_type == VREG && p && 31439608Smckusick uio->uio_offset + uio->uio_resid > 31547571Skarels p->p_rlimit[RLIMIT_FSIZE].rlim_cur) { 31647571Skarels psignal(p, SIGXFSZ); 31739608Smckusick return (EFBIG); 31839608Smckusick } 31939608Smckusick resid = uio->uio_resid; 32039608Smckusick osize = ip->i_size; 321*51155Sbostic #ifdef NOTLFS /* LFS */ 32239608Smckusick fs = ip->i_fs; 32339674Smckusick flags = 0; 32439674Smckusick if (ioflag & IO_SYNC) 32539674Smckusick flags = B_SYNC; 32639608Smckusick do { 32739608Smckusick lbn = lblkno(fs, uio->uio_offset); 32839608Smckusick on = blkoff(fs, uio->uio_offset); 32939608Smckusick n = MIN((unsigned)(fs->fs_bsize - on), uio->uio_resid); 33039608Smckusick if (n < fs->fs_bsize) 33139674Smckusick flags |= B_CLRBUF; 33239608Smckusick else 33339674Smckusick flags &= ~B_CLRBUF; 33439674Smckusick if (error = balloc(ip, lbn, (int)(on + n), &bp, flags)) 33539608Smckusick break; 33639674Smckusick bn = bp->b_blkno; 33745722Smckusick if (uio->uio_offset + n > ip->i_size) { 33839608Smckusick ip->i_size = uio->uio_offset + n; 33945722Smckusick vnode_pager_setsize(vp, ip->i_size); 34045722Smckusick } 34139608Smckusick size = blksize(fs, ip, lbn); 34245722Smckusick (void) vnode_pager_uncache(vp); 34339608Smckusick n = MIN(n, size - bp->b_resid); 34439608Smckusick error = uiomove(bp->b_un.b_addr + on, n, uio); 34539608Smckusick if (ioflag & IO_SYNC) 34639608Smckusick (void) bwrite(bp); 34739608Smckusick else if (n + on == fs->fs_bsize) { 34839608Smckusick bp->b_flags |= B_AGE; 34939608Smckusick bawrite(bp); 35039608Smckusick } else 35139608Smckusick bdwrite(bp); 35239608Smckusick ip->i_flag |= IUPD|ICHG; 35339608Smckusick if (cred->cr_uid != 0) 35439608Smckusick ip->i_mode &= ~(ISUID|ISGID); 35539608Smckusick } while (error == 0 && uio->uio_resid > 0 && n != 0); 356*51155Sbostic #else 357*51155Sbostic /* LFS IMPLEMENT -- write call */ 358*51155Sbostic panic("lfs_write not implemented"); 359*51155Sbostic #endif 36039608Smckusick if (error && (ioflag & IO_UNIT)) { 361*51155Sbostic (void) lfs_itrunc(ip, osize, ioflag & IO_SYNC); 36239608Smckusick uio->uio_offset -= resid - uio->uio_resid; 36339608Smckusick uio->uio_resid = resid; 36439608Smckusick } 36542493Smckusick if (!error && (ioflag & IO_SYNC)) 366*51155Sbostic error = lfs_iupdat(ip, &time, &time, 1); 36739608Smckusick return (error); 36839608Smckusick } 36939608Smckusick 3709167Ssam /* 37137737Smckusick * Synch an open file. 3729167Ssam */ 37337737Smckusick /* ARGSUSED */ 37451134Sbostic lfs_fsync(vp, fflags, cred, waitfor, p) 37537737Smckusick struct vnode *vp; 37637737Smckusick int fflags; 37737737Smckusick struct ucred *cred; 37839597Smckusick int waitfor; 37948039Smckusick struct proc *p; 3807701Ssam { 38139597Smckusick struct inode *ip = VTOI(vp); 3827701Ssam 383*51155Sbostic printf("lfs_sync: ino %d\n", ip->i_number); 38448039Smckusick if (fflags & FWRITE) 38537737Smckusick ip->i_flag |= ICHG; 386*51155Sbostic vflushbuf(vp, waitfor == MNT_WAIT ? B_SYNC : 0); /* LFS */ 387*51155Sbostic return (lfs_iupdat(ip, &time, &time, waitfor == MNT_WAIT)); 3887701Ssam } 3897701Ssam 3909167Ssam /* 39137737Smckusick * ufs remove 39237737Smckusick * Hard to avoid races here, especially 39337737Smckusick * in unlinking directories. 39437737Smckusick */ 39551134Sbostic lfs_remove(ndp, p) 39637737Smckusick struct nameidata *ndp; 39748039Smckusick struct proc *p; 39837737Smckusick { 39937737Smckusick register struct inode *ip, *dp; 40037737Smckusick int error; 40137737Smckusick 402*51155Sbostic printf("lfs_remove\n"); 40337737Smckusick ip = VTOI(ndp->ni_vp); 40437737Smckusick dp = VTOI(ndp->ni_dvp); 405*51155Sbostic error = lfs_dirremove(ndp); /* LFS */ 40637737Smckusick if (!error) { 40737737Smckusick ip->i_nlink--; 40837737Smckusick ip->i_flag |= ICHG; 4097701Ssam } 41037737Smckusick if (dp == ip) 41137737Smckusick vrele(ITOV(ip)); 41237737Smckusick else 41337737Smckusick iput(ip); 41437737Smckusick iput(dp); 41537737Smckusick return (error); 4167701Ssam } 4179167Ssam /* 41837737Smckusick * link vnode call 4199167Ssam */ 42051134Sbostic lfs_link(vp, ndp, p) 42137737Smckusick register struct vnode *vp; 42237737Smckusick register struct nameidata *ndp; 42348039Smckusick struct proc *p; 4249167Ssam { 42537737Smckusick register struct inode *ip = VTOI(vp); 42637737Smckusick int error; 4279167Ssam 428*51155Sbostic printf("lfs_link\n"); 42949737Smckusick #ifdef DIANOSTIC 43049737Smckusick if ((ndp->ni_nameiop & HASBUF) == 0) 43149737Smckusick panic("ufs_link: no name"); 43249737Smckusick #endif 43349737Smckusick if ((unsigned short)ip->i_nlink >= LINK_MAX) { 43449737Smckusick free(ndp->ni_pnbuf, M_NAMEI); 43546251Smckusick return (EMLINK); 43649737Smckusick } 43737737Smckusick if (ndp->ni_dvp != vp) 43837737Smckusick ILOCK(ip); 43937737Smckusick ip->i_nlink++; 44037737Smckusick ip->i_flag |= ICHG; 441*51155Sbostic error = lfs_iupdat(ip, &time, &time, 1); /* LFS */ 44237737Smckusick if (!error) 443*51155Sbostic error = lfs_direnter(ip, ndp); /* LFS */ 44437737Smckusick if (ndp->ni_dvp != vp) 44537737Smckusick IUNLOCK(ip); 44649737Smckusick FREE(ndp->ni_pnbuf, M_NAMEI); 44747219Smckusick vput(ndp->ni_dvp); 44837737Smckusick if (error) { 44937737Smckusick ip->i_nlink--; 45030598Smckusick ip->i_flag |= ICHG; 45137737Smckusick } 45237737Smckusick return (error); 4539167Ssam } 4549167Ssam 4559167Ssam /* 4569167Ssam * Rename system call. 4579167Ssam * rename("foo", "bar"); 4589167Ssam * is essentially 4599167Ssam * unlink("bar"); 4609167Ssam * link("foo", "bar"); 4619167Ssam * unlink("foo"); 4629167Ssam * but ``atomically''. Can't do full commit without saving state in the 4639167Ssam * inode on disk which isn't feasible at this time. Best we can do is 4649167Ssam * always guarantee the target exists. 4659167Ssam * 4669167Ssam * Basic algorithm is: 4679167Ssam * 4689167Ssam * 1) Bump link count on source while we're linking it to the 46937737Smckusick * target. This also ensure the inode won't be deleted out 47016776Smckusick * from underneath us while we work (it may be truncated by 47116776Smckusick * a concurrent `trunc' or `open' for creation). 4729167Ssam * 2) Link source to destination. If destination already exists, 4739167Ssam * delete it first. 47416776Smckusick * 3) Unlink source reference to inode if still around. If a 47516776Smckusick * directory was moved and the parent of the destination 4769167Ssam * is different from the source, patch the ".." entry in the 4779167Ssam * directory. 4789167Ssam */ 47951134Sbostic lfs_rename(fndp, tndp, p) 48037737Smckusick register struct nameidata *fndp, *tndp; 48148039Smckusick struct proc *p; 4827701Ssam { 4839167Ssam register struct inode *ip, *xp, *dp; 48416776Smckusick struct dirtemplate dirbuf; 48516776Smckusick int doingdirectory = 0, oldparent = 0, newparent = 0; 48610051Ssam int error = 0; 4877701Ssam 488*51155Sbostic printf("lfs_rename\n"); 48949737Smckusick #ifdef DIANOSTIC 49049737Smckusick if ((tndp->ni_nameiop & HASBUF) == 0 || 49149737Smckusick (fndp->ni_nameiop & HASBUF) == 0) 49249737Smckusick panic("ufs_rename: no name"); 49349737Smckusick #endif 49437737Smckusick dp = VTOI(fndp->ni_dvp); 49537737Smckusick ip = VTOI(fndp->ni_vp); 49649737Smckusick /* 49749737Smckusick * Check if just deleting a link name. 49849737Smckusick */ 49949737Smckusick if (fndp->ni_vp == tndp->ni_vp) { 50049737Smckusick VOP_ABORTOP(tndp); 50149737Smckusick vput(tndp->ni_dvp); 50249737Smckusick vput(tndp->ni_vp); 50349737Smckusick vrele(fndp->ni_dvp); 50449737Smckusick if ((ip->i_mode&IFMT) == IFDIR) { 50549737Smckusick VOP_ABORTOP(fndp); 50649737Smckusick vrele(fndp->ni_vp); 50749737Smckusick return (EINVAL); 50849737Smckusick } 50949737Smckusick doingdirectory = 0; 51049737Smckusick goto unlinkit; 51149737Smckusick } 51237737Smckusick ILOCK(ip); 5139167Ssam if ((ip->i_mode&IFMT) == IFDIR) { 5149167Ssam /* 51511641Ssam * Avoid ".", "..", and aliases of "." for obvious reasons. 5169167Ssam */ 51749737Smckusick if ((fndp->ni_namelen == 1 && fndp->ni_ptr[0] == '.') || 51849737Smckusick dp == ip || fndp->ni_isdotdot || (ip->i_flag & IRENAME)) { 51942466Smckusick VOP_ABORTOP(tndp); 52042466Smckusick vput(tndp->ni_dvp); 52142466Smckusick if (tndp->ni_vp) 52242466Smckusick vput(tndp->ni_vp); 52342466Smckusick VOP_ABORTOP(fndp); 52442466Smckusick vrele(fndp->ni_dvp); 52542466Smckusick vput(fndp->ni_vp); 52637737Smckusick return (EINVAL); 5279167Ssam } 52816776Smckusick ip->i_flag |= IRENAME; 5299167Ssam oldparent = dp->i_number; 5309167Ssam doingdirectory++; 5319167Ssam } 53237737Smckusick vrele(fndp->ni_dvp); 5339167Ssam 5349167Ssam /* 5359167Ssam * 1) Bump link count while we're moving stuff 5369167Ssam * around. If we crash somewhere before 5379167Ssam * completing our work, the link count 5389167Ssam * may be wrong, but correctable. 5399167Ssam */ 5409167Ssam ip->i_nlink++; 5419167Ssam ip->i_flag |= ICHG; 542*51155Sbostic error = lfs_iupdat(ip, &time, &time, 1); /* LFS */ 54316664Smckusick IUNLOCK(ip); 5449167Ssam 5459167Ssam /* 5469167Ssam * When the target exists, both the directory 54737737Smckusick * and target vnodes are returned locked. 5489167Ssam */ 54937737Smckusick dp = VTOI(tndp->ni_dvp); 55037737Smckusick xp = NULL; 55137737Smckusick if (tndp->ni_vp) 55237737Smckusick xp = VTOI(tndp->ni_vp); 5539167Ssam /* 55411641Ssam * If ".." must be changed (ie the directory gets a new 55512816Smckusick * parent) then the source directory must not be in the 55612816Smckusick * directory heirarchy above the target, as this would 55712816Smckusick * orphan everything below the source directory. Also 55812816Smckusick * the user must have write permission in the source so 55912816Smckusick * as to be able to change "..". We must repeat the call 56012816Smckusick * to namei, as the parent directory is unlocked by the 56112816Smckusick * call to checkpath(). 56211641Ssam */ 56316776Smckusick if (oldparent != dp->i_number) 56416776Smckusick newparent = dp->i_number; 56516776Smckusick if (doingdirectory && newparent) { 56641466Smckusick VOP_LOCK(fndp->ni_vp); 56748039Smckusick error = ufs_access(fndp->ni_vp, VWRITE, tndp->ni_cred, p); 56841466Smckusick VOP_UNLOCK(fndp->ni_vp); 56941466Smckusick if (error) 57012816Smckusick goto bad; 57149737Smckusick if (xp != NULL) 572*51155Sbostic iput(xp); /* LFS */ 573*51155Sbostic if (error = lfs_checkpath(ip, dp, tndp->ni_cred)) 57449737Smckusick goto out; 57549737Smckusick if ((tndp->ni_nameiop & SAVESTART) == 0) 57649737Smckusick panic("ufs_rename: lost to startdir"); 57749737Smckusick if (error = lookup(tndp, p)) 57849737Smckusick goto out; 57949737Smckusick dp = VTOI(tndp->ni_dvp); 58049737Smckusick xp = NULL; 58149737Smckusick if (tndp->ni_vp) 58249737Smckusick xp = VTOI(tndp->ni_vp); 58312816Smckusick } 58411641Ssam /* 5859167Ssam * 2) If target doesn't exist, link the target 5869167Ssam * to the source and unlink the source. 5879167Ssam * Otherwise, rewrite the target directory 5889167Ssam * entry to reference the source inode and 5899167Ssam * expunge the original entry's existence. 5909167Ssam */ 5919167Ssam if (xp == NULL) { 59237737Smckusick if (dp->i_dev != ip->i_dev) 59337737Smckusick panic("rename: EXDEV"); 5949167Ssam /* 59516776Smckusick * Account for ".." in new directory. 59616776Smckusick * When source and destination have the same 59716776Smckusick * parent we don't fool with the link count. 5989167Ssam */ 59916776Smckusick if (doingdirectory && newparent) { 60046251Smckusick if ((unsigned short)dp->i_nlink >= LINK_MAX) { 60146251Smckusick error = EMLINK; 60246251Smckusick goto bad; 60346251Smckusick } 6049167Ssam dp->i_nlink++; 605*51155Sbostic dp->i_flag |= ICHG; /* LFS */ 606*51155Sbostic if (error = lfs_iupdat(dp, &time, &time, 1)) 60746251Smckusick goto bad; 6089167Ssam } 609*51155Sbostic if (error = lfs_direnter(ip, tndp)) { 61047219Smckusick if (doingdirectory && newparent) { 61147219Smckusick dp->i_nlink--; 612*51155Sbostic dp->i_flag |= ICHG; /* LFS */ 613*51155Sbostic (void) lfs_iupdat(dp, &time, &time, 1); 61447219Smckusick } 61547219Smckusick goto bad; 61647219Smckusick } 61747234Smckusick iput(dp); 6189167Ssam } else { 61937737Smckusick if (xp->i_dev != dp->i_dev || xp->i_dev != ip->i_dev) 62037737Smckusick panic("rename: EXDEV"); 6219167Ssam /* 62210590Ssam * Short circuit rename(foo, foo). 62310590Ssam */ 62410590Ssam if (xp->i_number == ip->i_number) 62537737Smckusick panic("rename: same file"); 62610590Ssam /* 62724433Sbloom * If the parent directory is "sticky", then the user must 62824433Sbloom * own the parent directory, or the destination of the rename, 62924433Sbloom * otherwise the destination may not be changed (except by 63024433Sbloom * root). This implements append-only directories. 63124433Sbloom */ 63237737Smckusick if ((dp->i_mode & ISVTX) && tndp->ni_cred->cr_uid != 0 && 63337737Smckusick tndp->ni_cred->cr_uid != dp->i_uid && 63437737Smckusick xp->i_uid != tndp->ni_cred->cr_uid) { 63524433Sbloom error = EPERM; 63624433Sbloom goto bad; 63724433Sbloom } 63824433Sbloom /* 63949737Smckusick * Target must be empty if a directory and have no links 64049737Smckusick * to it. Also, ensure source and target are compatible 64149737Smckusick * (both directories, or both not directories). 6429167Ssam */ 6439167Ssam if ((xp->i_mode&IFMT) == IFDIR) { 64437737Smckusick if (!dirempty(xp, dp->i_number, tndp->ni_cred) || 64537737Smckusick xp->i_nlink > 2) { 64610051Ssam error = ENOTEMPTY; 6479167Ssam goto bad; 6489167Ssam } 6499167Ssam if (!doingdirectory) { 65010051Ssam error = ENOTDIR; 6519167Ssam goto bad; 6529167Ssam } 65337737Smckusick cache_purge(ITOV(dp)); 6549167Ssam } else if (doingdirectory) { 65510051Ssam error = EISDIR; 6569167Ssam goto bad; 6579167Ssam } 65837737Smckusick if (error = dirrewrite(dp, ip, tndp)) 65937737Smckusick goto bad; 66045354Smckusick /* 66145354Smckusick * If the target directory is in the same 66245354Smckusick * directory as the source directory, 66345354Smckusick * decrement the link count on the parent 66445354Smckusick * of the target directory. 66545354Smckusick */ 66645354Smckusick if (doingdirectory && !newparent) { 66745354Smckusick dp->i_nlink--; 66845354Smckusick dp->i_flag |= ICHG; 66945354Smckusick } 67037737Smckusick vput(ITOV(dp)); 6719167Ssam /* 67210051Ssam * Adjust the link count of the target to 67310051Ssam * reflect the dirrewrite above. If this is 67410051Ssam * a directory it is empty and there are 67510051Ssam * no links to it, so we can squash the inode and 67610051Ssam * any space associated with it. We disallowed 67710051Ssam * renaming over top of a directory with links to 67816776Smckusick * it above, as the remaining link would point to 67916776Smckusick * a directory without "." or ".." entries. 6809167Ssam */ 68110051Ssam xp->i_nlink--; 6829167Ssam if (doingdirectory) { 683*51155Sbostic if (--xp->i_nlink != 0) /* LFS */ 68410051Ssam panic("rename: linked directory"); 685*51155Sbostic error = lfs_itrunc(xp, (u_long)0, IO_SYNC); 68610051Ssam } 6879167Ssam xp->i_flag |= ICHG; 68838398Smckusick iput(xp); 68910246Ssam xp = NULL; 6909167Ssam } 6919167Ssam 6929167Ssam /* 6939167Ssam * 3) Unlink the source. 6949167Ssam */ 69549737Smckusick unlinkit: 69649737Smckusick fndp->ni_nameiop &= ~MODMASK; 69749737Smckusick fndp->ni_nameiop |= LOCKPARENT | LOCKLEAF; 69849737Smckusick if ((fndp->ni_nameiop & SAVESTART) == 0) 69949737Smckusick panic("ufs_rename: lost from startdir"); 70049737Smckusick (void) lookup(fndp, p); 70137737Smckusick if (fndp->ni_vp != NULL) { 70237737Smckusick xp = VTOI(fndp->ni_vp); 70337737Smckusick dp = VTOI(fndp->ni_dvp); 70437737Smckusick } else { 70546250Smckusick /* 70646250Smckusick * From name has disappeared. 70746250Smckusick */ 70846250Smckusick if (doingdirectory) 70946250Smckusick panic("rename: lost dir entry"); 71046250Smckusick vrele(ITOV(ip)); 71146250Smckusick return (0); 71237737Smckusick } 7139167Ssam /* 71437737Smckusick * Ensure that the directory entry still exists and has not 71516776Smckusick * changed while the new name has been entered. If the source is 71616776Smckusick * a file then the entry may have been unlinked or renamed. In 71716776Smckusick * either case there is no further work to be done. If the source 71816776Smckusick * is a directory then it cannot have been rmdir'ed; its link 71916776Smckusick * count of three would cause a rmdir to fail with ENOTEMPTY. 72037737Smckusick * The IRENAME flag ensures that it cannot be moved by another 72116776Smckusick * rename. 7229167Ssam */ 72317758Smckusick if (xp != ip) { 72416776Smckusick if (doingdirectory) 72517758Smckusick panic("rename: lost dir entry"); 72616776Smckusick } else { 7279167Ssam /* 72816776Smckusick * If the source is a directory with a 72916776Smckusick * new parent, the link count of the old 73016776Smckusick * parent directory must be decremented 73116776Smckusick * and ".." set to point to the new parent. 7329167Ssam */ 73316776Smckusick if (doingdirectory && newparent) { 7349167Ssam dp->i_nlink--; 7359167Ssam dp->i_flag |= ICHG; 73639597Smckusick error = vn_rdwr(UIO_READ, ITOV(xp), (caddr_t)&dirbuf, 73737737Smckusick sizeof (struct dirtemplate), (off_t)0, 73839597Smckusick UIO_SYSSPACE, IO_NODELOCKED, 73948039Smckusick tndp->ni_cred, (int *)0, (struct proc *)0); 74016776Smckusick if (error == 0) { 74116776Smckusick if (dirbuf.dotdot_namlen != 2 || 74216776Smckusick dirbuf.dotdot_name[0] != '.' || 74316776Smckusick dirbuf.dotdot_name[1] != '.') { 744*51155Sbostic lfs_dirbad(xp, 12, 745*51155Sbostic "rename: mangled dir"); 74616776Smckusick } else { 74716776Smckusick dirbuf.dotdot_ino = newparent; 74839597Smckusick (void) vn_rdwr(UIO_WRITE, ITOV(xp), 74916776Smckusick (caddr_t)&dirbuf, 75016776Smckusick sizeof (struct dirtemplate), 75137740Smckusick (off_t)0, UIO_SYSSPACE, 75239597Smckusick IO_NODELOCKED|IO_SYNC, 75348039Smckusick tndp->ni_cred, (int *)0, 75448039Smckusick (struct proc *)0); 75537737Smckusick cache_purge(ITOV(dp)); 75616776Smckusick } 75716776Smckusick } 7589167Ssam } 759*51155Sbostic error = lfs_dirremove(fndp); /* LFS */ 76037737Smckusick if (!error) { 76116776Smckusick xp->i_nlink--; 76216776Smckusick xp->i_flag |= ICHG; 7639167Ssam } 76416776Smckusick xp->i_flag &= ~IRENAME; 7659167Ssam } 7669167Ssam if (dp) 76737737Smckusick vput(ITOV(dp)); 76816776Smckusick if (xp) 76937737Smckusick vput(ITOV(xp)); 77037737Smckusick vrele(ITOV(ip)); 77137737Smckusick return (error); 7729167Ssam 7739167Ssam bad: 7749167Ssam if (xp) 77537737Smckusick vput(ITOV(xp)); 77637737Smckusick vput(ITOV(dp)); 7779167Ssam out: 7789167Ssam ip->i_nlink--; 7799167Ssam ip->i_flag |= ICHG; 78037737Smckusick vrele(ITOV(ip)); 78137737Smckusick return (error); 7827701Ssam } 7837701Ssam 7847535Sroot /* 78512756Ssam * A virgin directory (no blushing please). 78612756Ssam */ 787*51155Sbostic static struct dirtemplate mastertemplate = { 78812756Ssam 0, 12, 1, ".", 78912756Ssam 0, DIRBLKSIZ - 12, 2, ".." 79012756Ssam }; 79112756Ssam 79212756Ssam /* 79312756Ssam * Mkdir system call 79412756Ssam */ 79551134Sbostic lfs_mkdir(ndp, vap, p) 79637737Smckusick struct nameidata *ndp; 79737737Smckusick struct vattr *vap; 79848039Smckusick struct proc *p; 79912756Ssam { 80012756Ssam register struct inode *ip, *dp; 80137737Smckusick struct inode *tip; 80237737Smckusick struct vnode *dvp; 80312756Ssam struct dirtemplate dirtemplate; 80437737Smckusick int error; 80537737Smckusick int dmode; 80612756Ssam 807*51155Sbostic printf("lfs_mkdir\n"); 80849737Smckusick #ifdef DIANOSTIC 80949737Smckusick if ((ndp->ni_nameiop & HASBUF) == 0) 81049737Smckusick panic("ufs_mkdir: no name"); 81149737Smckusick #endif 81237737Smckusick dvp = ndp->ni_dvp; 81337737Smckusick dp = VTOI(dvp); 81446251Smckusick if ((unsigned short)dp->i_nlink >= LINK_MAX) { 81549737Smckusick free(ndp->ni_pnbuf, M_NAMEI); 81646251Smckusick iput(dp); 81746251Smckusick return (EMLINK); 81846251Smckusick } 81937737Smckusick dmode = vap->va_mode&0777; 82037737Smckusick dmode |= IFDIR; 82112756Ssam /* 82249737Smckusick * Must simulate part of maknode here to acquire the inode, but 82349737Smckusick * not have it entered in the parent directory. The entry is made 82449737Smckusick * later after writing "." and ".." entries. 82512756Ssam */ 826*51155Sbostic #ifdef NOTLFS /* LFS */ 82741312Smckusick if (error = ialloc(dp, dirpref(dp->i_fs), dmode, ndp->ni_cred, &tip)) { 828*51155Sbostic #else 829*51155Sbostic if (error = lfs_ialloc(dp->i_lfs, dp, &tip, ndp->ni_cred)) { 830*51155Sbostic #endif 83149737Smckusick free(ndp->ni_pnbuf, M_NAMEI); 83212756Ssam iput(dp); 83337737Smckusick return (error); 83412756Ssam } 83537737Smckusick ip = tip; 83641312Smckusick ip->i_uid = ndp->ni_cred->cr_uid; 83741312Smckusick ip->i_gid = dp->i_gid; 83812756Ssam #ifdef QUOTA 83941312Smckusick if ((error = getinoquota(ip)) || 84041312Smckusick (error = chkiq(ip, 1, ndp->ni_cred, 0))) { 84149737Smckusick free(ndp->ni_pnbuf, M_NAMEI); 842*51155Sbostic #ifdef NOTLFS /* LFS */ 84341312Smckusick ifree(ip, ip->i_number, dmode); 844*51155Sbostic #else 845*51155Sbostic lfs_ifree(ip); 846*51155Sbostic #endif 84741312Smckusick iput(ip); 84841312Smckusick iput(dp); 84941312Smckusick return (error); 85041312Smckusick } 85112756Ssam #endif 85212756Ssam ip->i_flag |= IACC|IUPD|ICHG; 85337737Smckusick ip->i_mode = dmode; 85437737Smckusick ITOV(ip)->v_type = VDIR; /* Rest init'd in iget() */ 85512756Ssam ip->i_nlink = 2; 856*51155Sbostic error = lfs_iupdat(ip, &time, &time, 1); /* LFS */ 85712756Ssam 85812756Ssam /* 85912756Ssam * Bump link count in parent directory 86012756Ssam * to reflect work done below. Should 86112756Ssam * be done before reference is created 86212756Ssam * so reparation is possible if we crash. 86312756Ssam */ 86412756Ssam dp->i_nlink++; 86512756Ssam dp->i_flag |= ICHG; 866*51155Sbostic if (error = lfs_iupdat(dp, &time, &time, 1)) /* LFS */ 86747219Smckusick goto bad; 86812756Ssam 86912756Ssam /* 87012756Ssam * Initialize directory with "." 87112756Ssam * and ".." from static template. 87212756Ssam */ 87312756Ssam dirtemplate = mastertemplate; 87412756Ssam dirtemplate.dot_ino = ip->i_number; 87512756Ssam dirtemplate.dotdot_ino = dp->i_number; 87639597Smckusick error = vn_rdwr(UIO_WRITE, ITOV(ip), (caddr_t)&dirtemplate, 87748039Smckusick sizeof (dirtemplate), (off_t)0, UIO_SYSSPACE, 87848039Smckusick IO_NODELOCKED|IO_SYNC, ndp->ni_cred, (int *)0, (struct proc *)0); 87937737Smckusick if (error) { 88012756Ssam dp->i_nlink--; 88112756Ssam dp->i_flag |= ICHG; 88212756Ssam goto bad; 88312756Ssam } 884*51155Sbostic if (DIRBLKSIZ > dp->i_lfs->lfs_fsize) { 88537737Smckusick panic("mkdir: blksize"); /* XXX - should grow w/balloc() */ 88643288Smckusick } else { 88718103Smckusick ip->i_size = DIRBLKSIZ; 88843288Smckusick ip->i_flag |= ICHG; 88943288Smckusick } 89012756Ssam /* 89112756Ssam * Directory all set up, now 89212756Ssam * install the entry for it in 89312756Ssam * the parent directory. 89412756Ssam */ 895*51155Sbostic if (error = lfs_direnter(ip, ndp)) { /* LFS */ 89647657Smckusick dp->i_nlink--; 89747657Smckusick dp->i_flag |= ICHG; 89812756Ssam } 89912756Ssam bad: 90012756Ssam /* 901*51155Sbostic * No need to do an explicit lfs_itrunc here, 90237737Smckusick * vrele will do this for us because we set 90312756Ssam * the link count to 0. 90412756Ssam */ 90537737Smckusick if (error) { 90612756Ssam ip->i_nlink = 0; 90712756Ssam ip->i_flag |= ICHG; 90838144Smckusick iput(ip); 90938144Smckusick } else 91038144Smckusick ndp->ni_vp = ITOV(ip); 91149737Smckusick FREE(ndp->ni_pnbuf, M_NAMEI); 91247219Smckusick iput(dp); 91337737Smckusick return (error); 91412756Ssam } 91512756Ssam 91612756Ssam /* 91712756Ssam * Rmdir system call. 91812756Ssam */ 91951134Sbostic lfs_rmdir(ndp, p) 92037737Smckusick register struct nameidata *ndp; 92148039Smckusick struct proc *p; 92212756Ssam { 92312756Ssam register struct inode *ip, *dp; 92437737Smckusick int error = 0; 92512756Ssam 926*51155Sbostic printf("lfs_rmdir\n"); 92737737Smckusick ip = VTOI(ndp->ni_vp); 92837737Smckusick dp = VTOI(ndp->ni_dvp); 92912756Ssam /* 93012756Ssam * No rmdir "." please. 93112756Ssam */ 93212756Ssam if (dp == ip) { 93337737Smckusick vrele(ITOV(dp)); 93412756Ssam iput(ip); 93537737Smckusick return (EINVAL); 93612756Ssam } 93712756Ssam /* 93812756Ssam * Verify the directory is empty (and valid). 93912756Ssam * (Rmdir ".." won't be valid since 94012756Ssam * ".." will contain a reference to 94112756Ssam * the current directory and thus be 94212756Ssam * non-empty.) 94312756Ssam */ 94437737Smckusick if (ip->i_nlink != 2 || !dirempty(ip, dp->i_number, ndp->ni_cred)) { 94537737Smckusick error = ENOTEMPTY; 94612756Ssam goto out; 94712756Ssam } 94812756Ssam /* 94912756Ssam * Delete reference to directory before purging 95012756Ssam * inode. If we crash in between, the directory 95112756Ssam * will be reattached to lost+found, 95212756Ssam */ 953*51155Sbostic if (error = lfs_dirremove(ndp)) /* LFS */ 95412756Ssam goto out; 95512756Ssam dp->i_nlink--; 95612756Ssam dp->i_flag |= ICHG; 95737737Smckusick cache_purge(ITOV(dp)); 95812756Ssam iput(dp); 95937737Smckusick ndp->ni_dvp = NULL; 96012756Ssam /* 96112756Ssam * Truncate inode. The only stuff left 96212756Ssam * in the directory is "." and "..". The 96312756Ssam * "." reference is inconsequential since 96412756Ssam * we're quashing it. The ".." reference 96512756Ssam * has already been adjusted above. We've 96612756Ssam * removed the "." reference and the reference 96712756Ssam * in the parent directory, but there may be 96812756Ssam * other hard links so decrement by 2 and 96912756Ssam * worry about them later. 97012756Ssam */ 97112756Ssam ip->i_nlink -= 2; 972*51155Sbostic error = lfs_itrunc(ip, (u_long)0, IO_SYNC); /* LFS */ 97337737Smckusick cache_purge(ITOV(ip)); 97412756Ssam out: 97537737Smckusick if (ndp->ni_dvp) 97612756Ssam iput(dp); 97712756Ssam iput(ip); 97837737Smckusick return (error); 97912756Ssam } 98012756Ssam 98137737Smckusick /* 98237737Smckusick * symlink -- make a symbolic link 98337737Smckusick */ 98451134Sbostic lfs_symlink(ndp, vap, target, p) 98537737Smckusick struct nameidata *ndp; 98637737Smckusick struct vattr *vap; 98737737Smckusick char *target; 98848039Smckusick struct proc *p; 98912756Ssam { 99037737Smckusick struct inode *ip; 99137737Smckusick int error; 99212756Ssam 993*51155Sbostic printf("lfs_symlink\n"); 99437737Smckusick error = maknode(IFLNK | vap->va_mode, ndp, &ip); 99537737Smckusick if (error) 99637737Smckusick return (error); 99739597Smckusick error = vn_rdwr(UIO_WRITE, ITOV(ip), target, strlen(target), (off_t)0, 99848039Smckusick UIO_SYSSPACE, IO_NODELOCKED, ndp->ni_cred, (int *)0, 99948039Smckusick (struct proc *)0); 100037737Smckusick iput(ip); 100137737Smckusick return (error); 100237737Smckusick } 100337737Smckusick 100437737Smckusick /* 100537737Smckusick * Vnode op for read and write 100637737Smckusick */ 100751134Sbostic lfs_readdir(vp, uio, cred, eofflagp) 100837737Smckusick struct vnode *vp; 100937737Smckusick register struct uio *uio; 101037737Smckusick struct ucred *cred; 101140345Smckusick int *eofflagp; 101237737Smckusick { 101339597Smckusick int count, lost, error; 101437737Smckusick 1015*51155Sbostic printf("lfs_readdir\n"); 101637737Smckusick count = uio->uio_resid; 101737737Smckusick count &= ~(DIRBLKSIZ - 1); 101839597Smckusick lost = uio->uio_resid - count; 101939597Smckusick if (count < DIRBLKSIZ || (uio->uio_offset & (DIRBLKSIZ -1))) 102037737Smckusick return (EINVAL); 102137737Smckusick uio->uio_resid = count; 102237737Smckusick uio->uio_iov->iov_len = count; 1023*51155Sbostic error = lfs_read(vp, uio, 0, cred); /* LFS */ 102439597Smckusick uio->uio_resid += lost; 102540345Smckusick if ((VTOI(vp)->i_size - uio->uio_offset) <= 0) 102640345Smckusick *eofflagp = 1; 102740345Smckusick else 102840345Smckusick *eofflagp = 0; 102937737Smckusick return (error); 103037737Smckusick } 103137737Smckusick 103237737Smckusick /* 103337737Smckusick * Return target name of a symbolic link 103437737Smckusick */ 103551134Sbostic lfs_readlink(vp, uiop, cred) 103637737Smckusick struct vnode *vp; 103737737Smckusick struct uio *uiop; 103837737Smckusick struct ucred *cred; 103937737Smckusick { 104037737Smckusick 1041*51155Sbostic printf("lfs_readlink\n"); 1042*51155Sbostic return (lfs_read(vp, uiop, 0, cred)); /* LFS */ 104337737Smckusick } 104437737Smckusick 104537737Smckusick /* 104637737Smckusick * Get access to bmap 104712756Ssam */ 1048*51155Sbostic lfs_vbmap(vp, bn, vpp, bnp) 104937737Smckusick struct vnode *vp; 105037737Smckusick daddr_t bn; 105137737Smckusick struct vnode **vpp; 105237737Smckusick daddr_t *bnp; 105312756Ssam { 105437737Smckusick struct inode *ip = VTOI(vp); 105512756Ssam 1056*51155Sbostic printf("lfs_vbmap\n"); 105737737Smckusick if (vpp != NULL) 105837737Smckusick *vpp = ip->i_devvp; 105937737Smckusick if (bnp == NULL) 106037737Smckusick return (0); 1061*51155Sbostic return (lfs_bmap(ip, bn, bnp)); /* LFS */ 106212756Ssam } 106337737Smckusick 106437737Smckusick /* 106541538Smckusick * Calculate the logical to physical mapping if not done already, 106641538Smckusick * then call the device strategy routine. 106737737Smckusick */ 106851134Sbostic lfs_strategy(bp) 106937737Smckusick register struct buf *bp; 107037737Smckusick { 107139674Smckusick register struct inode *ip = VTOI(bp->b_vp); 107239674Smckusick struct vnode *vp; 107339674Smckusick int error; 107439674Smckusick 1075*51155Sbostic printf("lfs_strategy: type: %d lblk %d pblk %d\n", bp->b_vp->v_type, 1076*51155Sbostic bp->b_lblkno, bp->b_blkno); 107739674Smckusick if (bp->b_vp->v_type == VBLK || bp->b_vp->v_type == VCHR) 107839674Smckusick panic("ufs_strategy: spec"); 1079*51155Sbostic if (bp->b_blkno == bp->b_lblkno) { /* LFS */ 1080*51155Sbostic if (error = lfs_bmap(ip, bp->b_lblkno, &bp->b_blkno)) 108139674Smckusick return (error); 108239896Smckusick if ((long)bp->b_blkno == -1) 108339674Smckusick clrbuf(bp); 108439674Smckusick } 108539896Smckusick if ((long)bp->b_blkno == -1) { 108639896Smckusick biodone(bp); 108739674Smckusick return (0); 108839896Smckusick } 108939674Smckusick vp = ip->i_devvp; 109039674Smckusick bp->b_dev = vp->v_rdev; 109149762Smckusick (*(vp->v_op->vop_strategy))(bp); 109237737Smckusick return (0); 109337737Smckusick } 109437737Smckusick 109537737Smckusick /* 109649452Smckusick * Allocate a new inode. 109737737Smckusick */ 109851134Sbostic static int 109937737Smckusick maknode(mode, ndp, ipp) 110037737Smckusick int mode; 110137737Smckusick register struct nameidata *ndp; 110237737Smckusick struct inode **ipp; 110337737Smckusick { 110437737Smckusick register struct inode *ip; 110537737Smckusick struct inode *tip; 110637737Smckusick register struct inode *pdir = VTOI(ndp->ni_dvp); 110737737Smckusick ino_t ipref; 110837737Smckusick int error; 110937737Smckusick 1110*51155Sbostic printf("maknode\n"); 111149737Smckusick #ifdef DIANOSTIC 111249737Smckusick if ((ndp->ni_nameiop & HASBUF) == 0) 111349737Smckusick panic("maknode: no name"); 111449737Smckusick #endif 111537737Smckusick *ipp = 0; 111641312Smckusick if ((mode & IFMT) == 0) 111741312Smckusick mode |= IFREG; 1118*51155Sbostic #ifdef NOTLFS /* LFS */ 111937737Smckusick if ((mode & IFMT) == IFDIR) 112037737Smckusick ipref = dirpref(pdir->i_fs); 112137737Smckusick else 112237737Smckusick ipref = pdir->i_number; 112341312Smckusick if (error = ialloc(pdir, ipref, mode, ndp->ni_cred, &tip)) { 1124*51155Sbostic #else 1125*51155Sbostic if (error = lfs_ialloc(pdir->i_lfs, pdir, &tip, ndp->ni_cred)) { 1126*51155Sbostic #endif 112749737Smckusick free(ndp->ni_pnbuf, M_NAMEI); 112837737Smckusick iput(pdir); 112937737Smckusick return (error); 113037737Smckusick } 113137737Smckusick ip = tip; 113241312Smckusick ip->i_uid = ndp->ni_cred->cr_uid; 113341312Smckusick ip->i_gid = pdir->i_gid; 113437737Smckusick #ifdef QUOTA 113541312Smckusick if ((error = getinoquota(ip)) || 113641312Smckusick (error = chkiq(ip, 1, ndp->ni_cred, 0))) { 113749737Smckusick free(ndp->ni_pnbuf, M_NAMEI); 1138*51155Sbostic #ifdef NOTLFS /* LFS */ 113941312Smckusick ifree(ip, ip->i_number, mode); 1140*51155Sbostic #else 1141*51155Sbostic lfs_ifree(ip); 1142*51155Sbostic #endif 114341312Smckusick iput(ip); 114441312Smckusick iput(pdir); 114541312Smckusick return (error); 114641312Smckusick } 114737737Smckusick #endif 114837737Smckusick ip->i_flag |= IACC|IUPD|ICHG; 114937737Smckusick ip->i_mode = mode; 115037737Smckusick ITOV(ip)->v_type = IFTOVT(mode); /* Rest init'd in iget() */ 115137737Smckusick ip->i_nlink = 1; 115237737Smckusick if ((ip->i_mode & ISGID) && !groupmember(ip->i_gid, ndp->ni_cred) && 115337737Smckusick suser(ndp->ni_cred, NULL)) 115437737Smckusick ip->i_mode &= ~ISGID; 115537737Smckusick 115637737Smckusick /* 115737737Smckusick * Make sure inode goes to disk before directory entry. 1158*51155Sbostic * 1159*51155Sbostic * XXX Wrong... 116037737Smckusick */ 1161*51155Sbostic if (error = lfs_iupdat(ip, &time, &time, 1)) /* LFS */ 116241312Smckusick goto bad; 1163*51155Sbostic if (error = lfs_direnter(ip, ndp)) /* LFS */ 116441312Smckusick goto bad; 116549737Smckusick if ((ndp->ni_nameiop & SAVESTART) == 0) 116649737Smckusick FREE(ndp->ni_pnbuf, M_NAMEI); 116747219Smckusick iput(pdir); 116837737Smckusick *ipp = ip; 116937737Smckusick return (0); 117041312Smckusick 117141312Smckusick bad: 117241312Smckusick /* 117341312Smckusick * Write error occurred trying to update the inode 117441312Smckusick * or the directory so must deallocate the inode. 117541312Smckusick */ 117649737Smckusick free(ndp->ni_pnbuf, M_NAMEI); 117747219Smckusick iput(pdir); 117841312Smckusick ip->i_nlink = 0; 117941312Smckusick ip->i_flag |= ICHG; 118041312Smckusick iput(ip); 118141312Smckusick return (error); 118237737Smckusick } 118346207Smckusick 118446207Smckusick /* 118551134Sbostic * Global vfs data structures for lfs 118648039Smckusick */ 118751134Sbostic struct vnodeops lfs_vnodeops = { 1188*51155Sbostic lfs_lookup, /* lookup */ 1189*51155Sbostic lfs_create, /* create */ 1190*51155Sbostic lfs_mknod, /* mknod */ 119148039Smckusick ufs_open, /* open */ 119248039Smckusick ufs_close, /* close */ 119348039Smckusick ufs_access, /* access */ 1194*51155Sbostic lfs_getattr, /* getattr */ 1195*51155Sbostic lfs_setattr, /* setattr */ 1196*51155Sbostic lfs_read, /* read */ 1197*51155Sbostic lfs_write, /* write */ 119848039Smckusick ufs_ioctl, /* ioctl */ 119948039Smckusick ufs_select, /* select */ 120048039Smckusick ufs_mmap, /* mmap */ 1201*51155Sbostic lfs_fsync, /* fsync */ 120248039Smckusick ufs_seek, /* seek */ 1203*51155Sbostic lfs_remove, /* remove */ 1204*51155Sbostic lfs_link, /* link */ 1205*51155Sbostic lfs_rename, /* rename */ 1206*51155Sbostic lfs_mkdir, /* mkdir */ 1207*51155Sbostic lfs_rmdir, /* rmdir */ 1208*51155Sbostic lfs_symlink, /* symlink */ 1209*51155Sbostic lfs_readdir, /* readdir */ 1210*51155Sbostic lfs_readlink, /* readlink */ 121148039Smckusick ufs_abortop, /* abortop */ 1212*51155Sbostic lfs_inactive, /* inactive */ 121348039Smckusick ufs_reclaim, /* reclaim */ 121448039Smckusick ufs_lock, /* lock */ 121548039Smckusick ufs_unlock, /* unlock */ 1216*51155Sbostic lfs_vbmap, /* bmap */ 1217*51155Sbostic lfs_strategy, /* strategy */ 121848039Smckusick ufs_print, /* print */ 121948039Smckusick ufs_islocked, /* islocked */ 122048039Smckusick ufs_advlock, /* advlock */ 122148039Smckusick }; 1222