123405Smckusick /* 251155Sbostic * Copyright (c) 1982, 1986, 1989, 1991 Regents of the University of California. 337737Smckusick * All rights reserved. 423405Smckusick * 544539Sbostic * %sccs.include.redist.c% 637737Smckusick * 7*51183Sbostic * @(#)lfs_vnops.c 7.67 (Berkeley) 09/25/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 2651155Sbostic #include "../ufs/lockf.h" 2751155Sbostic #include "../ufs/quota.h" 2851155Sbostic #include "../ufs/inode.h" 2951155Sbostic #include "../ufs/dir.h" 3051134Sbostic #include "lfs.h" 3151155Sbostic #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 4851155Sbostic 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 6951155Sbostic 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 10151155Sbostic printf("lfs_getattr\n"); 102*51183Sbostic ITIMES(ip, &time, &time); /* LFS */ 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 13351155Sbostic 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 15251155Sbostic printf("lfs_setattr\n"); 15337737Smckusick /* 15451155Sbostic * 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) 17051155Sbostic return (EISDIR); /* LFS */ 17151155Sbostic 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; 18251155Sbostic ip->i_flag |= ICHG; /* LFS */ 183*51183Sbostic ITIMES(ip, &vap->va_atime, &vap->va_mtime); /* LFS */ 1846254Sroot } 18537737Smckusick if (vap->va_mode != (u_short)VNOVAL) 18647571Skarels error = chmod1(vp, (int)vap->va_mode, p); 18738254Smckusick if (vap->va_flags != VNOVAL) { 18838254Smckusick if (cred->cr_uid != ip->i_uid && 18947571Skarels (error = suser(cred, &p->p_acflag))) 19038254Smckusick return (error); 19138254Smckusick if (cred->cr_uid == 0) { 19238254Smckusick ip->i_flags = vap->va_flags; 19338254Smckusick } else { 19438254Smckusick ip->i_flags &= 0xffff0000; 19538254Smckusick ip->i_flags |= (vap->va_flags & 0xffff); 19638254Smckusick } 19738254Smckusick ip->i_flag |= ICHG; 19838254Smckusick } 19937737Smckusick return (error); 2006254Sroot } 2016254Sroot 2026254Sroot /* 20339608Smckusick * Vnode op for reading. 20439608Smckusick */ 20537737Smckusick /* ARGSUSED */ 20651134Sbostic lfs_read(vp, uio, ioflag, cred) 20739608Smckusick struct vnode *vp; 20839608Smckusick register struct uio *uio; 20939608Smckusick int ioflag; 21039608Smckusick struct ucred *cred; 21139608Smckusick { 21239608Smckusick register struct inode *ip = VTOI(vp); 21351155Sbostic register LFS *fs; /* LFS */ 21439608Smckusick struct buf *bp; 21539608Smckusick daddr_t lbn, bn, rablock; 21639896Smckusick int size, diff, error = 0; 21739608Smckusick long n, on, type; 21839608Smckusick 21951155Sbostic printf("lfs_read: ino %d\n", ip->i_number); 22048039Smckusick #ifdef DIAGNOSTIC 22139608Smckusick if (uio->uio_rw != UIO_READ) 22239608Smckusick panic("ufs_read mode"); 22339608Smckusick type = ip->i_mode & IFMT; 22439608Smckusick if (type != IFDIR && type != IFREG && type != IFLNK) 22539608Smckusick panic("ufs_read type"); 22648039Smckusick #endif 22739608Smckusick if (uio->uio_resid == 0) 22839608Smckusick return (0); 22939608Smckusick if (uio->uio_offset < 0) 23039608Smckusick return (EINVAL); 23139608Smckusick ip->i_flag |= IACC; 23251155Sbostic 23351155Sbostic fs = ip->i_lfs; /* LFS */ 23439608Smckusick do { 23539608Smckusick lbn = lblkno(fs, uio->uio_offset); 23639608Smckusick on = blkoff(fs, uio->uio_offset); 23751155Sbostic n = MIN((unsigned)(fs->lfs_bsize - on), uio->uio_resid); 23839608Smckusick diff = ip->i_size - uio->uio_offset; 23939608Smckusick if (diff <= 0) 24039608Smckusick return (0); 24139608Smckusick if (diff < n) 24239608Smckusick n = diff; 24351155Sbostic size = blksize(fs); /* LFS */ 24439674Smckusick rablock = lbn + 1; 24539896Smckusick if (vp->v_lastr + 1 == lbn && 24639896Smckusick lblktosize(fs, rablock) < ip->i_size) 24739896Smckusick error = breada(ITOV(ip), lbn, size, rablock, 24851155Sbostic blksize(fs), NOCRED, &bp); 24939608Smckusick else 25039674Smckusick error = bread(ITOV(ip), lbn, size, NOCRED, &bp); 25139815Smckusick vp->v_lastr = lbn; 25239608Smckusick n = MIN(n, size - bp->b_resid); 25339608Smckusick if (error) { 25439608Smckusick brelse(bp); 25539608Smckusick return (error); 25639608Smckusick } 25739608Smckusick error = uiomove(bp->b_un.b_addr + on, (int)n, uio); 25851155Sbostic if (n + on == fs->lfs_bsize || uio->uio_offset == ip->i_size) 25939608Smckusick bp->b_flags |= B_AGE; 26039608Smckusick brelse(bp); 26139608Smckusick } while (error == 0 && uio->uio_resid > 0 && n != 0); 26239608Smckusick return (error); 26339608Smckusick } 26439608Smckusick 26539608Smckusick /* 26639608Smckusick * Vnode op for writing. 26739608Smckusick */ 26851134Sbostic lfs_write(vp, uio, ioflag, cred) 26939608Smckusick register struct vnode *vp; 27039608Smckusick struct uio *uio; 27139608Smckusick int ioflag; 27239608Smckusick struct ucred *cred; 27339608Smckusick { 27448039Smckusick struct proc *p = uio->uio_procp; 27539608Smckusick register struct inode *ip = VTOI(vp); 276*51183Sbostic register LFS *fs; /* LFS */ 27739608Smckusick struct buf *bp; 27839608Smckusick daddr_t lbn, bn; 27939608Smckusick u_long osize; 28045722Smckusick int n, on, flags; 28145722Smckusick int size, resid, error = 0; 28239608Smckusick 28351155Sbostic printf("lfs_write ino %d\n", ip->i_number); 28448039Smckusick #ifdef DIAGNOSTIC 28539608Smckusick if (uio->uio_rw != UIO_WRITE) 28639608Smckusick panic("ufs_write mode"); 28748039Smckusick #endif 28839608Smckusick switch (vp->v_type) { 28939608Smckusick case VREG: 29039608Smckusick if (ioflag & IO_APPEND) 29139608Smckusick uio->uio_offset = ip->i_size; 29239608Smckusick /* fall through */ 29339608Smckusick case VLNK: 29439608Smckusick break; 29539608Smckusick 29639608Smckusick case VDIR: 29739608Smckusick if ((ioflag & IO_SYNC) == 0) 29839608Smckusick panic("ufs_write nonsync dir write"); 29939608Smckusick break; 30039608Smckusick 30139608Smckusick default: 30239608Smckusick panic("ufs_write type"); 30339608Smckusick } 30439608Smckusick if (uio->uio_offset < 0) 30539608Smckusick return (EINVAL); 30639608Smckusick if (uio->uio_resid == 0) 30739608Smckusick return (0); 30839608Smckusick /* 30939608Smckusick * Maybe this should be above the vnode op call, but so long as 31039608Smckusick * file servers have no limits, i don't think it matters 31139608Smckusick */ 31249679Smckusick if (vp->v_type == VREG && p && 31339608Smckusick uio->uio_offset + uio->uio_resid > 31447571Skarels p->p_rlimit[RLIMIT_FSIZE].rlim_cur) { 31547571Skarels psignal(p, SIGXFSZ); 31639608Smckusick return (EFBIG); 31739608Smckusick } 31839608Smckusick resid = uio->uio_resid; 31939608Smckusick osize = ip->i_size; 320*51183Sbostic fs = ip->i_lfs; /* LFS */ 32139674Smckusick flags = 0; 322*51183Sbostic #ifdef NOTLFS 32339674Smckusick if (ioflag & IO_SYNC) 32439674Smckusick flags = B_SYNC; 325*51183Sbostic #endif 32639608Smckusick do { 32739608Smckusick lbn = lblkno(fs, uio->uio_offset); 328*51183Sbostic on = blkoff(fs, uio->uio_offset); /* LFS */ 329*51183Sbostic n = MIN((unsigned)(fs->lfs_bsize - on), uio->uio_resid); 330*51183Sbostic if (n < fs->lfs_bsize) /* LFS */ 33139674Smckusick flags |= B_CLRBUF; 33239608Smckusick else 333*51183Sbostic flags &= ~B_CLRBUF; /* LFS */ 334*51183Sbostic if (error = bread(vp, lbn, fs->lfs_bsize, NOCRED, &bp)) 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 } 341*51183Sbostic size = blksize(fs); 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); 345*51183Sbostic #ifdef NOTLFS /* LFS */ 34639608Smckusick if (ioflag & IO_SYNC) 34739608Smckusick (void) bwrite(bp); 34839608Smckusick else if (n + on == fs->fs_bsize) { 34939608Smckusick bp->b_flags |= B_AGE; 35039608Smckusick bawrite(bp); 35139608Smckusick } else 35239608Smckusick bdwrite(bp); 353*51183Sbostic #else 354*51183Sbostic /* 355*51183Sbostic * Update segment usage information; call segment 356*51183Sbostic * writer if necessary. 357*51183Sbostic */ 358*51183Sbostic lfs_bwrite(bp); 359*51183Sbostic #endif 36039608Smckusick ip->i_flag |= IUPD|ICHG; 36139608Smckusick if (cred->cr_uid != 0) 36239608Smckusick ip->i_mode &= ~(ISUID|ISGID); 36339608Smckusick } while (error == 0 && uio->uio_resid > 0 && n != 0); 36439608Smckusick if (error && (ioflag & IO_UNIT)) { 365*51183Sbostic #ifdef NOTLFS 366*51183Sbostic /* This just doesn't work... */ 36751155Sbostic (void) lfs_itrunc(ip, osize, ioflag & IO_SYNC); 368*51183Sbostic #endif 36939608Smckusick uio->uio_offset -= resid - uio->uio_resid; 37039608Smckusick uio->uio_resid = resid; 37139608Smckusick } 37242493Smckusick if (!error && (ioflag & IO_SYNC)) 373*51183Sbostic ITIMES(ip, &time, &time); /* LFS */ 37439608Smckusick return (error); 37539608Smckusick } 37639608Smckusick 3779167Ssam /* 37837737Smckusick * Synch an open file. 3799167Ssam */ 38037737Smckusick /* ARGSUSED */ 38151134Sbostic lfs_fsync(vp, fflags, cred, waitfor, p) 38237737Smckusick struct vnode *vp; 38337737Smckusick int fflags; 38437737Smckusick struct ucred *cred; 38539597Smckusick int waitfor; 38648039Smckusick struct proc *p; 3877701Ssam { 38839597Smckusick struct inode *ip = VTOI(vp); 3897701Ssam 39051155Sbostic printf("lfs_sync: ino %d\n", ip->i_number); 39148039Smckusick if (fflags & FWRITE) 39237737Smckusick ip->i_flag |= ICHG; 393*51183Sbostic ITIMES(ip, &time, &time); /* LFS */ 39451155Sbostic vflushbuf(vp, waitfor == MNT_WAIT ? B_SYNC : 0); /* LFS */ 395*51183Sbostic return (0); 3967701Ssam } 3977701Ssam 3989167Ssam /* 39937737Smckusick * ufs remove 40037737Smckusick * Hard to avoid races here, especially 40137737Smckusick * in unlinking directories. 40237737Smckusick */ 40351134Sbostic lfs_remove(ndp, p) 40437737Smckusick struct nameidata *ndp; 40548039Smckusick struct proc *p; 40637737Smckusick { 40737737Smckusick register struct inode *ip, *dp; 40837737Smckusick int error; 40937737Smckusick 41051155Sbostic printf("lfs_remove\n"); 41137737Smckusick ip = VTOI(ndp->ni_vp); 41237737Smckusick dp = VTOI(ndp->ni_dvp); 41351155Sbostic error = lfs_dirremove(ndp); /* LFS */ 41437737Smckusick if (!error) { 41537737Smckusick ip->i_nlink--; 41637737Smckusick ip->i_flag |= ICHG; 4177701Ssam } 41837737Smckusick if (dp == ip) 41937737Smckusick vrele(ITOV(ip)); 42037737Smckusick else 42137737Smckusick iput(ip); 42237737Smckusick iput(dp); 42337737Smckusick return (error); 4247701Ssam } 4259167Ssam /* 42637737Smckusick * link vnode call 4279167Ssam */ 42851134Sbostic lfs_link(vp, ndp, p) 42937737Smckusick register struct vnode *vp; 43037737Smckusick register struct nameidata *ndp; 43148039Smckusick struct proc *p; 4329167Ssam { 43337737Smckusick register struct inode *ip = VTOI(vp); 43437737Smckusick int error; 4359167Ssam 43651155Sbostic printf("lfs_link\n"); 43749737Smckusick #ifdef DIANOSTIC 43849737Smckusick if ((ndp->ni_nameiop & HASBUF) == 0) 43949737Smckusick panic("ufs_link: no name"); 44049737Smckusick #endif 44149737Smckusick if ((unsigned short)ip->i_nlink >= LINK_MAX) { 44249737Smckusick free(ndp->ni_pnbuf, M_NAMEI); 44346251Smckusick return (EMLINK); 44449737Smckusick } 44537737Smckusick if (ndp->ni_dvp != vp) 44637737Smckusick ILOCK(ip); 44737737Smckusick ip->i_nlink++; 44837737Smckusick ip->i_flag |= ICHG; 449*51183Sbostic ITIMES(ip, &time, &time); /* LFS */ 450*51183Sbostic error = lfs_direnter(ip, ndp); /* LFS */ 45137737Smckusick if (ndp->ni_dvp != vp) 45237737Smckusick IUNLOCK(ip); 45349737Smckusick FREE(ndp->ni_pnbuf, M_NAMEI); 45447219Smckusick vput(ndp->ni_dvp); 45537737Smckusick if (error) { 45637737Smckusick ip->i_nlink--; 45730598Smckusick ip->i_flag |= ICHG; 45837737Smckusick } 45937737Smckusick return (error); 4609167Ssam } 4619167Ssam 4629167Ssam /* 4639167Ssam * Rename system call. 4649167Ssam * rename("foo", "bar"); 4659167Ssam * is essentially 4669167Ssam * unlink("bar"); 4679167Ssam * link("foo", "bar"); 4689167Ssam * unlink("foo"); 4699167Ssam * but ``atomically''. Can't do full commit without saving state in the 4709167Ssam * inode on disk which isn't feasible at this time. Best we can do is 4719167Ssam * always guarantee the target exists. 4729167Ssam * 4739167Ssam * Basic algorithm is: 4749167Ssam * 4759167Ssam * 1) Bump link count on source while we're linking it to the 47637737Smckusick * target. This also ensure the inode won't be deleted out 47716776Smckusick * from underneath us while we work (it may be truncated by 47816776Smckusick * a concurrent `trunc' or `open' for creation). 4799167Ssam * 2) Link source to destination. If destination already exists, 4809167Ssam * delete it first. 48116776Smckusick * 3) Unlink source reference to inode if still around. If a 48216776Smckusick * directory was moved and the parent of the destination 4839167Ssam * is different from the source, patch the ".." entry in the 4849167Ssam * directory. 4859167Ssam */ 48651134Sbostic lfs_rename(fndp, tndp, p) 48737737Smckusick register struct nameidata *fndp, *tndp; 48848039Smckusick struct proc *p; 4897701Ssam { 4909167Ssam register struct inode *ip, *xp, *dp; 49116776Smckusick struct dirtemplate dirbuf; 49216776Smckusick int doingdirectory = 0, oldparent = 0, newparent = 0; 49310051Ssam int error = 0; 4947701Ssam 49551155Sbostic printf("lfs_rename\n"); 49649737Smckusick #ifdef DIANOSTIC 49749737Smckusick if ((tndp->ni_nameiop & HASBUF) == 0 || 49849737Smckusick (fndp->ni_nameiop & HASBUF) == 0) 49949737Smckusick panic("ufs_rename: no name"); 50049737Smckusick #endif 50137737Smckusick dp = VTOI(fndp->ni_dvp); 50237737Smckusick ip = VTOI(fndp->ni_vp); 50349737Smckusick /* 50449737Smckusick * Check if just deleting a link name. 50549737Smckusick */ 50649737Smckusick if (fndp->ni_vp == tndp->ni_vp) { 50749737Smckusick VOP_ABORTOP(tndp); 50849737Smckusick vput(tndp->ni_dvp); 50949737Smckusick vput(tndp->ni_vp); 51049737Smckusick vrele(fndp->ni_dvp); 51149737Smckusick if ((ip->i_mode&IFMT) == IFDIR) { 51249737Smckusick VOP_ABORTOP(fndp); 51349737Smckusick vrele(fndp->ni_vp); 51449737Smckusick return (EINVAL); 51549737Smckusick } 51649737Smckusick doingdirectory = 0; 51749737Smckusick goto unlinkit; 51849737Smckusick } 51937737Smckusick ILOCK(ip); 5209167Ssam if ((ip->i_mode&IFMT) == IFDIR) { 5219167Ssam /* 52211641Ssam * Avoid ".", "..", and aliases of "." for obvious reasons. 5239167Ssam */ 52449737Smckusick if ((fndp->ni_namelen == 1 && fndp->ni_ptr[0] == '.') || 52549737Smckusick dp == ip || fndp->ni_isdotdot || (ip->i_flag & IRENAME)) { 52642466Smckusick VOP_ABORTOP(tndp); 52742466Smckusick vput(tndp->ni_dvp); 52842466Smckusick if (tndp->ni_vp) 52942466Smckusick vput(tndp->ni_vp); 53042466Smckusick VOP_ABORTOP(fndp); 53142466Smckusick vrele(fndp->ni_dvp); 53242466Smckusick vput(fndp->ni_vp); 53337737Smckusick return (EINVAL); 5349167Ssam } 53516776Smckusick ip->i_flag |= IRENAME; 5369167Ssam oldparent = dp->i_number; 5379167Ssam doingdirectory++; 5389167Ssam } 53937737Smckusick vrele(fndp->ni_dvp); 5409167Ssam 5419167Ssam /* 5429167Ssam * 1) Bump link count while we're moving stuff 5439167Ssam * around. If we crash somewhere before 5449167Ssam * completing our work, the link count 5459167Ssam * may be wrong, but correctable. 5469167Ssam */ 5479167Ssam ip->i_nlink++; 5489167Ssam ip->i_flag |= ICHG; 549*51183Sbostic ITIMES(ip, &time, &time); /* LFS */ 55016664Smckusick IUNLOCK(ip); 5519167Ssam 5529167Ssam /* 5539167Ssam * When the target exists, both the directory 55437737Smckusick * and target vnodes are returned locked. 5559167Ssam */ 55637737Smckusick dp = VTOI(tndp->ni_dvp); 55737737Smckusick xp = NULL; 55837737Smckusick if (tndp->ni_vp) 55937737Smckusick xp = VTOI(tndp->ni_vp); 5609167Ssam /* 56111641Ssam * If ".." must be changed (ie the directory gets a new 56212816Smckusick * parent) then the source directory must not be in the 56312816Smckusick * directory heirarchy above the target, as this would 56412816Smckusick * orphan everything below the source directory. Also 56512816Smckusick * the user must have write permission in the source so 56612816Smckusick * as to be able to change "..". We must repeat the call 56712816Smckusick * to namei, as the parent directory is unlocked by the 56812816Smckusick * call to checkpath(). 56911641Ssam */ 57016776Smckusick if (oldparent != dp->i_number) 57116776Smckusick newparent = dp->i_number; 57216776Smckusick if (doingdirectory && newparent) { 57341466Smckusick VOP_LOCK(fndp->ni_vp); 57448039Smckusick error = ufs_access(fndp->ni_vp, VWRITE, tndp->ni_cred, p); 57541466Smckusick VOP_UNLOCK(fndp->ni_vp); 57641466Smckusick if (error) 57712816Smckusick goto bad; 57849737Smckusick if (xp != NULL) 57951155Sbostic iput(xp); /* LFS */ 58051155Sbostic if (error = lfs_checkpath(ip, dp, tndp->ni_cred)) 58149737Smckusick goto out; 58249737Smckusick if ((tndp->ni_nameiop & SAVESTART) == 0) 58349737Smckusick panic("ufs_rename: lost to startdir"); 58449737Smckusick if (error = lookup(tndp, p)) 58549737Smckusick goto out; 58649737Smckusick dp = VTOI(tndp->ni_dvp); 58749737Smckusick xp = NULL; 58849737Smckusick if (tndp->ni_vp) 58949737Smckusick xp = VTOI(tndp->ni_vp); 59012816Smckusick } 59111641Ssam /* 5929167Ssam * 2) If target doesn't exist, link the target 5939167Ssam * to the source and unlink the source. 5949167Ssam * Otherwise, rewrite the target directory 5959167Ssam * entry to reference the source inode and 5969167Ssam * expunge the original entry's existence. 5979167Ssam */ 5989167Ssam if (xp == NULL) { 59937737Smckusick if (dp->i_dev != ip->i_dev) 60037737Smckusick panic("rename: EXDEV"); 6019167Ssam /* 60216776Smckusick * Account for ".." in new directory. 60316776Smckusick * When source and destination have the same 60416776Smckusick * parent we don't fool with the link count. 6059167Ssam */ 60616776Smckusick if (doingdirectory && newparent) { 60746251Smckusick if ((unsigned short)dp->i_nlink >= LINK_MAX) { 60846251Smckusick error = EMLINK; 60946251Smckusick goto bad; 61046251Smckusick } 6119167Ssam dp->i_nlink++; 61251155Sbostic dp->i_flag |= ICHG; /* LFS */ 613*51183Sbostic ITIMES(dp, &time, &time); /* LFS */ 6149167Ssam } 61551155Sbostic if (error = lfs_direnter(ip, tndp)) { 61647219Smckusick if (doingdirectory && newparent) { 61747219Smckusick dp->i_nlink--; 61851155Sbostic dp->i_flag |= ICHG; /* LFS */ 619*51183Sbostic ITIMES(dp, &time, &time); /* LFS */ 62047219Smckusick } 62147219Smckusick goto bad; 62247219Smckusick } 62347234Smckusick iput(dp); 6249167Ssam } else { 62537737Smckusick if (xp->i_dev != dp->i_dev || xp->i_dev != ip->i_dev) 62637737Smckusick panic("rename: EXDEV"); 6279167Ssam /* 62810590Ssam * Short circuit rename(foo, foo). 62910590Ssam */ 63010590Ssam if (xp->i_number == ip->i_number) 63137737Smckusick panic("rename: same file"); 63210590Ssam /* 63324433Sbloom * If the parent directory is "sticky", then the user must 63424433Sbloom * own the parent directory, or the destination of the rename, 63524433Sbloom * otherwise the destination may not be changed (except by 63624433Sbloom * root). This implements append-only directories. 63724433Sbloom */ 63837737Smckusick if ((dp->i_mode & ISVTX) && tndp->ni_cred->cr_uid != 0 && 63937737Smckusick tndp->ni_cred->cr_uid != dp->i_uid && 64037737Smckusick xp->i_uid != tndp->ni_cred->cr_uid) { 64124433Sbloom error = EPERM; 64224433Sbloom goto bad; 64324433Sbloom } 64424433Sbloom /* 64549737Smckusick * Target must be empty if a directory and have no links 64649737Smckusick * to it. Also, ensure source and target are compatible 64749737Smckusick * (both directories, or both not directories). 6489167Ssam */ 6499167Ssam if ((xp->i_mode&IFMT) == IFDIR) { 65037737Smckusick if (!dirempty(xp, dp->i_number, tndp->ni_cred) || 65137737Smckusick xp->i_nlink > 2) { 65210051Ssam error = ENOTEMPTY; 6539167Ssam goto bad; 6549167Ssam } 6559167Ssam if (!doingdirectory) { 65610051Ssam error = ENOTDIR; 6579167Ssam goto bad; 6589167Ssam } 65937737Smckusick cache_purge(ITOV(dp)); 6609167Ssam } else if (doingdirectory) { 66110051Ssam error = EISDIR; 6629167Ssam goto bad; 6639167Ssam } 66437737Smckusick if (error = dirrewrite(dp, ip, tndp)) 66537737Smckusick goto bad; 66645354Smckusick /* 66745354Smckusick * If the target directory is in the same 66845354Smckusick * directory as the source directory, 66945354Smckusick * decrement the link count on the parent 67045354Smckusick * of the target directory. 67145354Smckusick */ 67245354Smckusick if (doingdirectory && !newparent) { 67345354Smckusick dp->i_nlink--; 67445354Smckusick dp->i_flag |= ICHG; 67545354Smckusick } 67637737Smckusick vput(ITOV(dp)); 6779167Ssam /* 67810051Ssam * Adjust the link count of the target to 67910051Ssam * reflect the dirrewrite above. If this is 68010051Ssam * a directory it is empty and there are 68110051Ssam * no links to it, so we can squash the inode and 68210051Ssam * any space associated with it. We disallowed 68310051Ssam * renaming over top of a directory with links to 68416776Smckusick * it above, as the remaining link would point to 68516776Smckusick * a directory without "." or ".." entries. 6869167Ssam */ 68710051Ssam xp->i_nlink--; 6889167Ssam if (doingdirectory) { 68951155Sbostic if (--xp->i_nlink != 0) /* LFS */ 69010051Ssam panic("rename: linked directory"); 69151155Sbostic error = lfs_itrunc(xp, (u_long)0, IO_SYNC); 69210051Ssam } 6939167Ssam xp->i_flag |= ICHG; 69438398Smckusick iput(xp); 69510246Ssam xp = NULL; 6969167Ssam } 6979167Ssam 6989167Ssam /* 6999167Ssam * 3) Unlink the source. 7009167Ssam */ 70149737Smckusick unlinkit: 70249737Smckusick fndp->ni_nameiop &= ~MODMASK; 70349737Smckusick fndp->ni_nameiop |= LOCKPARENT | LOCKLEAF; 70449737Smckusick if ((fndp->ni_nameiop & SAVESTART) == 0) 70549737Smckusick panic("ufs_rename: lost from startdir"); 70649737Smckusick (void) lookup(fndp, p); 70737737Smckusick if (fndp->ni_vp != NULL) { 70837737Smckusick xp = VTOI(fndp->ni_vp); 70937737Smckusick dp = VTOI(fndp->ni_dvp); 71037737Smckusick } else { 71146250Smckusick /* 71246250Smckusick * From name has disappeared. 71346250Smckusick */ 71446250Smckusick if (doingdirectory) 71546250Smckusick panic("rename: lost dir entry"); 71646250Smckusick vrele(ITOV(ip)); 71746250Smckusick return (0); 71837737Smckusick } 7199167Ssam /* 72037737Smckusick * Ensure that the directory entry still exists and has not 72116776Smckusick * changed while the new name has been entered. If the source is 72216776Smckusick * a file then the entry may have been unlinked or renamed. In 72316776Smckusick * either case there is no further work to be done. If the source 72416776Smckusick * is a directory then it cannot have been rmdir'ed; its link 72516776Smckusick * count of three would cause a rmdir to fail with ENOTEMPTY. 72637737Smckusick * The IRENAME flag ensures that it cannot be moved by another 72716776Smckusick * rename. 7289167Ssam */ 72917758Smckusick if (xp != ip) { 73016776Smckusick if (doingdirectory) 73117758Smckusick panic("rename: lost dir entry"); 73216776Smckusick } else { 7339167Ssam /* 73416776Smckusick * If the source is a directory with a 73516776Smckusick * new parent, the link count of the old 73616776Smckusick * parent directory must be decremented 73716776Smckusick * and ".." set to point to the new parent. 7389167Ssam */ 73916776Smckusick if (doingdirectory && newparent) { 7409167Ssam dp->i_nlink--; 7419167Ssam dp->i_flag |= ICHG; 74239597Smckusick error = vn_rdwr(UIO_READ, ITOV(xp), (caddr_t)&dirbuf, 74337737Smckusick sizeof (struct dirtemplate), (off_t)0, 74439597Smckusick UIO_SYSSPACE, IO_NODELOCKED, 74548039Smckusick tndp->ni_cred, (int *)0, (struct proc *)0); 74616776Smckusick if (error == 0) { 74716776Smckusick if (dirbuf.dotdot_namlen != 2 || 74816776Smckusick dirbuf.dotdot_name[0] != '.' || 74916776Smckusick dirbuf.dotdot_name[1] != '.') { 75051155Sbostic lfs_dirbad(xp, 12, 75151155Sbostic "rename: mangled dir"); 75216776Smckusick } else { 75316776Smckusick dirbuf.dotdot_ino = newparent; 75439597Smckusick (void) vn_rdwr(UIO_WRITE, ITOV(xp), 75516776Smckusick (caddr_t)&dirbuf, 75616776Smckusick sizeof (struct dirtemplate), 75737740Smckusick (off_t)0, UIO_SYSSPACE, 75839597Smckusick IO_NODELOCKED|IO_SYNC, 75948039Smckusick tndp->ni_cred, (int *)0, 76048039Smckusick (struct proc *)0); 76137737Smckusick cache_purge(ITOV(dp)); 76216776Smckusick } 76316776Smckusick } 7649167Ssam } 76551155Sbostic error = lfs_dirremove(fndp); /* LFS */ 76637737Smckusick if (!error) { 76716776Smckusick xp->i_nlink--; 76816776Smckusick xp->i_flag |= ICHG; 7699167Ssam } 77016776Smckusick xp->i_flag &= ~IRENAME; 7719167Ssam } 7729167Ssam if (dp) 77337737Smckusick vput(ITOV(dp)); 77416776Smckusick if (xp) 77537737Smckusick vput(ITOV(xp)); 77637737Smckusick vrele(ITOV(ip)); 77737737Smckusick return (error); 7789167Ssam 7799167Ssam bad: 7809167Ssam if (xp) 78137737Smckusick vput(ITOV(xp)); 78237737Smckusick vput(ITOV(dp)); 7839167Ssam out: 7849167Ssam ip->i_nlink--; 7859167Ssam ip->i_flag |= ICHG; 78637737Smckusick vrele(ITOV(ip)); 78737737Smckusick return (error); 7887701Ssam } 7897701Ssam 7907535Sroot /* 79112756Ssam * A virgin directory (no blushing please). 79212756Ssam */ 79351155Sbostic static struct dirtemplate mastertemplate = { 79412756Ssam 0, 12, 1, ".", 79512756Ssam 0, DIRBLKSIZ - 12, 2, ".." 79612756Ssam }; 79712756Ssam 79812756Ssam /* 79912756Ssam * Mkdir system call 80012756Ssam */ 80151134Sbostic lfs_mkdir(ndp, vap, p) 80237737Smckusick struct nameidata *ndp; 80337737Smckusick struct vattr *vap; 80448039Smckusick struct proc *p; 80512756Ssam { 80612756Ssam register struct inode *ip, *dp; 80737737Smckusick struct inode *tip; 80837737Smckusick struct vnode *dvp; 80912756Ssam struct dirtemplate dirtemplate; 81037737Smckusick int error; 81137737Smckusick int dmode; 81212756Ssam 81351155Sbostic printf("lfs_mkdir\n"); 81449737Smckusick #ifdef DIANOSTIC 81549737Smckusick if ((ndp->ni_nameiop & HASBUF) == 0) 81649737Smckusick panic("ufs_mkdir: no name"); 81749737Smckusick #endif 81837737Smckusick dvp = ndp->ni_dvp; 81937737Smckusick dp = VTOI(dvp); 82046251Smckusick if ((unsigned short)dp->i_nlink >= LINK_MAX) { 82149737Smckusick free(ndp->ni_pnbuf, M_NAMEI); 82246251Smckusick iput(dp); 82346251Smckusick return (EMLINK); 82446251Smckusick } 82537737Smckusick dmode = vap->va_mode&0777; 82637737Smckusick dmode |= IFDIR; 82712756Ssam /* 82849737Smckusick * Must simulate part of maknode here to acquire the inode, but 82949737Smckusick * not have it entered in the parent directory. The entry is made 83049737Smckusick * later after writing "." and ".." entries. 83112756Ssam */ 83251155Sbostic #ifdef NOTLFS /* LFS */ 83341312Smckusick if (error = ialloc(dp, dirpref(dp->i_fs), dmode, ndp->ni_cred, &tip)) { 83451155Sbostic #else 83551155Sbostic if (error = lfs_ialloc(dp->i_lfs, dp, &tip, ndp->ni_cred)) { 83651155Sbostic #endif 83749737Smckusick free(ndp->ni_pnbuf, M_NAMEI); 83812756Ssam iput(dp); 83937737Smckusick return (error); 84012756Ssam } 84137737Smckusick ip = tip; 84241312Smckusick ip->i_uid = ndp->ni_cred->cr_uid; 84341312Smckusick ip->i_gid = dp->i_gid; 84412756Ssam #ifdef QUOTA 84541312Smckusick if ((error = getinoquota(ip)) || 84641312Smckusick (error = chkiq(ip, 1, ndp->ni_cred, 0))) { 84749737Smckusick free(ndp->ni_pnbuf, M_NAMEI); 84851155Sbostic #ifdef NOTLFS /* LFS */ 84941312Smckusick ifree(ip, ip->i_number, dmode); 85051155Sbostic #else 85151155Sbostic lfs_ifree(ip); 85251155Sbostic #endif 85341312Smckusick iput(ip); 85441312Smckusick iput(dp); 85541312Smckusick return (error); 85641312Smckusick } 85712756Ssam #endif 85812756Ssam ip->i_flag |= IACC|IUPD|ICHG; 85937737Smckusick ip->i_mode = dmode; 86037737Smckusick ITOV(ip)->v_type = VDIR; /* Rest init'd in iget() */ 86112756Ssam ip->i_nlink = 2; 862*51183Sbostic ITIMES(ip, &time, &time); /* LFS */ 86312756Ssam 86412756Ssam /* 86512756Ssam * Bump link count in parent directory 86612756Ssam * to reflect work done below. Should 86712756Ssam * be done before reference is created 86812756Ssam * so reparation is possible if we crash. 86912756Ssam */ 87012756Ssam dp->i_nlink++; 87112756Ssam dp->i_flag |= ICHG; 872*51183Sbostic ITIMES(dp, &time, &time); /* LFS */ 87312756Ssam 87412756Ssam /* 87512756Ssam * Initialize directory with "." 87612756Ssam * and ".." from static template. 87712756Ssam */ 87812756Ssam dirtemplate = mastertemplate; 87912756Ssam dirtemplate.dot_ino = ip->i_number; 88012756Ssam dirtemplate.dotdot_ino = dp->i_number; 88139597Smckusick error = vn_rdwr(UIO_WRITE, ITOV(ip), (caddr_t)&dirtemplate, 88248039Smckusick sizeof (dirtemplate), (off_t)0, UIO_SYSSPACE, 88348039Smckusick IO_NODELOCKED|IO_SYNC, ndp->ni_cred, (int *)0, (struct proc *)0); 88437737Smckusick if (error) { 88512756Ssam dp->i_nlink--; 88612756Ssam dp->i_flag |= ICHG; 88712756Ssam goto bad; 88812756Ssam } 88951155Sbostic if (DIRBLKSIZ > dp->i_lfs->lfs_fsize) { 89037737Smckusick panic("mkdir: blksize"); /* XXX - should grow w/balloc() */ 89143288Smckusick } else { 89218103Smckusick ip->i_size = DIRBLKSIZ; 89343288Smckusick ip->i_flag |= ICHG; 89443288Smckusick } 89512756Ssam /* 89612756Ssam * Directory all set up, now 89712756Ssam * install the entry for it in 89812756Ssam * the parent directory. 89912756Ssam */ 90051155Sbostic if (error = lfs_direnter(ip, ndp)) { /* LFS */ 90147657Smckusick dp->i_nlink--; 90247657Smckusick dp->i_flag |= ICHG; 90312756Ssam } 90412756Ssam bad: 90512756Ssam /* 90651155Sbostic * No need to do an explicit lfs_itrunc here, 90737737Smckusick * vrele will do this for us because we set 90812756Ssam * the link count to 0. 90912756Ssam */ 91037737Smckusick if (error) { 91112756Ssam ip->i_nlink = 0; 91212756Ssam ip->i_flag |= ICHG; 91338144Smckusick iput(ip); 91438144Smckusick } else 91538144Smckusick ndp->ni_vp = ITOV(ip); 91649737Smckusick FREE(ndp->ni_pnbuf, M_NAMEI); 91747219Smckusick iput(dp); 91837737Smckusick return (error); 91912756Ssam } 92012756Ssam 92112756Ssam /* 92212756Ssam * Rmdir system call. 92312756Ssam */ 92451134Sbostic lfs_rmdir(ndp, p) 92537737Smckusick register struct nameidata *ndp; 92648039Smckusick struct proc *p; 92712756Ssam { 92812756Ssam register struct inode *ip, *dp; 92937737Smckusick int error = 0; 93012756Ssam 93151155Sbostic printf("lfs_rmdir\n"); 93237737Smckusick ip = VTOI(ndp->ni_vp); 93337737Smckusick dp = VTOI(ndp->ni_dvp); 93412756Ssam /* 93512756Ssam * No rmdir "." please. 93612756Ssam */ 93712756Ssam if (dp == ip) { 93837737Smckusick vrele(ITOV(dp)); 93912756Ssam iput(ip); 94037737Smckusick return (EINVAL); 94112756Ssam } 94212756Ssam /* 94312756Ssam * Verify the directory is empty (and valid). 94412756Ssam * (Rmdir ".." won't be valid since 94512756Ssam * ".." will contain a reference to 94612756Ssam * the current directory and thus be 94712756Ssam * non-empty.) 94812756Ssam */ 94937737Smckusick if (ip->i_nlink != 2 || !dirempty(ip, dp->i_number, ndp->ni_cred)) { 95037737Smckusick error = ENOTEMPTY; 95112756Ssam goto out; 95212756Ssam } 95312756Ssam /* 95412756Ssam * Delete reference to directory before purging 95512756Ssam * inode. If we crash in between, the directory 95612756Ssam * will be reattached to lost+found, 95712756Ssam */ 95851155Sbostic if (error = lfs_dirremove(ndp)) /* LFS */ 95912756Ssam goto out; 96012756Ssam dp->i_nlink--; 96112756Ssam dp->i_flag |= ICHG; 96237737Smckusick cache_purge(ITOV(dp)); 96312756Ssam iput(dp); 96437737Smckusick ndp->ni_dvp = NULL; 96512756Ssam /* 96612756Ssam * Truncate inode. The only stuff left 96712756Ssam * in the directory is "." and "..". The 96812756Ssam * "." reference is inconsequential since 96912756Ssam * we're quashing it. The ".." reference 97012756Ssam * has already been adjusted above. We've 97112756Ssam * removed the "." reference and the reference 97212756Ssam * in the parent directory, but there may be 97312756Ssam * other hard links so decrement by 2 and 97412756Ssam * worry about them later. 97512756Ssam */ 97612756Ssam ip->i_nlink -= 2; 97751155Sbostic error = lfs_itrunc(ip, (u_long)0, IO_SYNC); /* LFS */ 97837737Smckusick cache_purge(ITOV(ip)); 97912756Ssam out: 98037737Smckusick if (ndp->ni_dvp) 98112756Ssam iput(dp); 98212756Ssam iput(ip); 98337737Smckusick return (error); 98412756Ssam } 98512756Ssam 98637737Smckusick /* 98737737Smckusick * symlink -- make a symbolic link 98837737Smckusick */ 98951134Sbostic lfs_symlink(ndp, vap, target, p) 99037737Smckusick struct nameidata *ndp; 99137737Smckusick struct vattr *vap; 99237737Smckusick char *target; 99348039Smckusick struct proc *p; 99412756Ssam { 99537737Smckusick struct inode *ip; 99637737Smckusick int error; 99712756Ssam 99851155Sbostic printf("lfs_symlink\n"); 99937737Smckusick error = maknode(IFLNK | vap->va_mode, ndp, &ip); 100037737Smckusick if (error) 100137737Smckusick return (error); 100239597Smckusick error = vn_rdwr(UIO_WRITE, ITOV(ip), target, strlen(target), (off_t)0, 100348039Smckusick UIO_SYSSPACE, IO_NODELOCKED, ndp->ni_cred, (int *)0, 100448039Smckusick (struct proc *)0); 100537737Smckusick iput(ip); 100637737Smckusick return (error); 100737737Smckusick } 100837737Smckusick 100937737Smckusick /* 101037737Smckusick * Vnode op for read and write 101137737Smckusick */ 101251134Sbostic lfs_readdir(vp, uio, cred, eofflagp) 101337737Smckusick struct vnode *vp; 101437737Smckusick register struct uio *uio; 101537737Smckusick struct ucred *cred; 101640345Smckusick int *eofflagp; 101737737Smckusick { 101839597Smckusick int count, lost, error; 101937737Smckusick 102051155Sbostic printf("lfs_readdir\n"); 102137737Smckusick count = uio->uio_resid; 102237737Smckusick count &= ~(DIRBLKSIZ - 1); 102339597Smckusick lost = uio->uio_resid - count; 102439597Smckusick if (count < DIRBLKSIZ || (uio->uio_offset & (DIRBLKSIZ -1))) 102537737Smckusick return (EINVAL); 102637737Smckusick uio->uio_resid = count; 102737737Smckusick uio->uio_iov->iov_len = count; 102851155Sbostic error = lfs_read(vp, uio, 0, cred); /* LFS */ 102939597Smckusick uio->uio_resid += lost; 103040345Smckusick if ((VTOI(vp)->i_size - uio->uio_offset) <= 0) 103140345Smckusick *eofflagp = 1; 103240345Smckusick else 103340345Smckusick *eofflagp = 0; 103437737Smckusick return (error); 103537737Smckusick } 103637737Smckusick 103737737Smckusick /* 103837737Smckusick * Return target name of a symbolic link 103937737Smckusick */ 104051134Sbostic lfs_readlink(vp, uiop, cred) 104137737Smckusick struct vnode *vp; 104237737Smckusick struct uio *uiop; 104337737Smckusick struct ucred *cred; 104437737Smckusick { 104537737Smckusick 104651155Sbostic printf("lfs_readlink\n"); 104751155Sbostic return (lfs_read(vp, uiop, 0, cred)); /* LFS */ 104837737Smckusick } 104937737Smckusick 105037737Smckusick /* 105137737Smckusick * Get access to bmap 105212756Ssam */ 105351155Sbostic lfs_vbmap(vp, bn, vpp, bnp) 105437737Smckusick struct vnode *vp; 105537737Smckusick daddr_t bn; 105637737Smckusick struct vnode **vpp; 105737737Smckusick daddr_t *bnp; 105812756Ssam { 105937737Smckusick struct inode *ip = VTOI(vp); 106012756Ssam 106151155Sbostic printf("lfs_vbmap\n"); 106237737Smckusick if (vpp != NULL) 106337737Smckusick *vpp = ip->i_devvp; 106437737Smckusick if (bnp == NULL) 106537737Smckusick return (0); 106651155Sbostic return (lfs_bmap(ip, bn, bnp)); /* LFS */ 106712756Ssam } 106837737Smckusick 106937737Smckusick /* 107041538Smckusick * Calculate the logical to physical mapping if not done already, 107141538Smckusick * then call the device strategy routine. 107237737Smckusick */ 107351134Sbostic lfs_strategy(bp) 107437737Smckusick register struct buf *bp; 107537737Smckusick { 107639674Smckusick register struct inode *ip = VTOI(bp->b_vp); 107739674Smckusick struct vnode *vp; 107839674Smckusick int error; 107939674Smckusick 108051155Sbostic printf("lfs_strategy: type: %d lblk %d pblk %d\n", bp->b_vp->v_type, 108151155Sbostic bp->b_lblkno, bp->b_blkno); 108239674Smckusick if (bp->b_vp->v_type == VBLK || bp->b_vp->v_type == VCHR) 108339674Smckusick panic("ufs_strategy: spec"); 108451155Sbostic if (bp->b_blkno == bp->b_lblkno) { /* LFS */ 108551155Sbostic if (error = lfs_bmap(ip, bp->b_lblkno, &bp->b_blkno)) 108639674Smckusick return (error); 108739896Smckusick if ((long)bp->b_blkno == -1) 108839674Smckusick clrbuf(bp); 108939674Smckusick } 109039896Smckusick if ((long)bp->b_blkno == -1) { 109139896Smckusick biodone(bp); 109239674Smckusick return (0); 109339896Smckusick } 109439674Smckusick vp = ip->i_devvp; 109539674Smckusick bp->b_dev = vp->v_rdev; 109649762Smckusick (*(vp->v_op->vop_strategy))(bp); 109737737Smckusick return (0); 109837737Smckusick } 109937737Smckusick 110037737Smckusick /* 110149452Smckusick * Allocate a new inode. 110237737Smckusick */ 110351134Sbostic static int 110437737Smckusick maknode(mode, ndp, ipp) 110537737Smckusick int mode; 110637737Smckusick register struct nameidata *ndp; 110737737Smckusick struct inode **ipp; 110837737Smckusick { 110937737Smckusick register struct inode *ip; 111037737Smckusick struct inode *tip; 111137737Smckusick register struct inode *pdir = VTOI(ndp->ni_dvp); 111237737Smckusick ino_t ipref; 111337737Smckusick int error; 111437737Smckusick 111551155Sbostic printf("maknode\n"); 111649737Smckusick #ifdef DIANOSTIC 111749737Smckusick if ((ndp->ni_nameiop & HASBUF) == 0) 111849737Smckusick panic("maknode: no name"); 111949737Smckusick #endif 112037737Smckusick *ipp = 0; 112141312Smckusick if ((mode & IFMT) == 0) 112241312Smckusick mode |= IFREG; 112351155Sbostic #ifdef NOTLFS /* LFS */ 112437737Smckusick if ((mode & IFMT) == IFDIR) 112537737Smckusick ipref = dirpref(pdir->i_fs); 112637737Smckusick else 112737737Smckusick ipref = pdir->i_number; 112841312Smckusick if (error = ialloc(pdir, ipref, mode, ndp->ni_cred, &tip)) { 112951155Sbostic #else 113051155Sbostic if (error = lfs_ialloc(pdir->i_lfs, pdir, &tip, ndp->ni_cred)) { 113151155Sbostic #endif 113249737Smckusick free(ndp->ni_pnbuf, M_NAMEI); 113337737Smckusick iput(pdir); 113437737Smckusick return (error); 113537737Smckusick } 113637737Smckusick ip = tip; 113741312Smckusick ip->i_uid = ndp->ni_cred->cr_uid; 113841312Smckusick ip->i_gid = pdir->i_gid; 113937737Smckusick #ifdef QUOTA 114041312Smckusick if ((error = getinoquota(ip)) || 114141312Smckusick (error = chkiq(ip, 1, ndp->ni_cred, 0))) { 114249737Smckusick free(ndp->ni_pnbuf, M_NAMEI); 114351155Sbostic #ifdef NOTLFS /* LFS */ 114441312Smckusick ifree(ip, ip->i_number, mode); 114551155Sbostic #else 114651155Sbostic lfs_ifree(ip); 114751155Sbostic #endif 114841312Smckusick iput(ip); 114941312Smckusick iput(pdir); 115041312Smckusick return (error); 115141312Smckusick } 115237737Smckusick #endif 115337737Smckusick ip->i_flag |= IACC|IUPD|ICHG; 115437737Smckusick ip->i_mode = mode; 115537737Smckusick ITOV(ip)->v_type = IFTOVT(mode); /* Rest init'd in iget() */ 115637737Smckusick ip->i_nlink = 1; 115737737Smckusick if ((ip->i_mode & ISGID) && !groupmember(ip->i_gid, ndp->ni_cred) && 115837737Smckusick suser(ndp->ni_cred, NULL)) 115937737Smckusick ip->i_mode &= ~ISGID; 116037737Smckusick 1161*51183Sbostic ITIMES(ip, &time, &time); /* LFS */ 116251155Sbostic if (error = lfs_direnter(ip, ndp)) /* LFS */ 116341312Smckusick goto bad; 116449737Smckusick if ((ndp->ni_nameiop & SAVESTART) == 0) 116549737Smckusick FREE(ndp->ni_pnbuf, M_NAMEI); 116647219Smckusick iput(pdir); 116737737Smckusick *ipp = ip; 116837737Smckusick return (0); 116941312Smckusick 117041312Smckusick bad: 117141312Smckusick /* 117241312Smckusick * Write error occurred trying to update the inode 117341312Smckusick * or the directory so must deallocate the inode. 117441312Smckusick */ 117549737Smckusick free(ndp->ni_pnbuf, M_NAMEI); 117647219Smckusick iput(pdir); 117741312Smckusick ip->i_nlink = 0; 117841312Smckusick ip->i_flag |= ICHG; 117941312Smckusick iput(ip); 118041312Smckusick return (error); 118137737Smckusick } 118246207Smckusick 118346207Smckusick /* 118451134Sbostic * Global vfs data structures for lfs 118548039Smckusick */ 118651134Sbostic struct vnodeops lfs_vnodeops = { 118751155Sbostic lfs_lookup, /* lookup */ 118851155Sbostic lfs_create, /* create */ 118951155Sbostic lfs_mknod, /* mknod */ 119048039Smckusick ufs_open, /* open */ 119148039Smckusick ufs_close, /* close */ 119248039Smckusick ufs_access, /* access */ 119351155Sbostic lfs_getattr, /* getattr */ 119451155Sbostic lfs_setattr, /* setattr */ 119551155Sbostic lfs_read, /* read */ 119651155Sbostic lfs_write, /* write */ 119748039Smckusick ufs_ioctl, /* ioctl */ 119848039Smckusick ufs_select, /* select */ 119948039Smckusick ufs_mmap, /* mmap */ 120051155Sbostic lfs_fsync, /* fsync */ 120148039Smckusick ufs_seek, /* seek */ 120251155Sbostic lfs_remove, /* remove */ 120351155Sbostic lfs_link, /* link */ 120451155Sbostic lfs_rename, /* rename */ 120551155Sbostic lfs_mkdir, /* mkdir */ 120651155Sbostic lfs_rmdir, /* rmdir */ 120751155Sbostic lfs_symlink, /* symlink */ 120851155Sbostic lfs_readdir, /* readdir */ 120951155Sbostic lfs_readlink, /* readlink */ 121048039Smckusick ufs_abortop, /* abortop */ 121151155Sbostic lfs_inactive, /* inactive */ 121248039Smckusick ufs_reclaim, /* reclaim */ 121348039Smckusick ufs_lock, /* lock */ 121448039Smckusick ufs_unlock, /* unlock */ 121551155Sbostic lfs_vbmap, /* bmap */ 121651155Sbostic lfs_strategy, /* strategy */ 121748039Smckusick ufs_print, /* print */ 121848039Smckusick ufs_islocked, /* islocked */ 121948039Smckusick ufs_advlock, /* advlock */ 122048039Smckusick }; 1221