1*9167Ssam /* lfs_vnops.c 4.42 82/11/13 */ 237Sbill 337Sbill #include "../h/param.h" 437Sbill #include "../h/systm.h" 537Sbill #include "../h/dir.h" 637Sbill #include "../h/user.h" 78040Sroot #include "../h/kernel.h" 86254Sroot #include "../h/file.h" 96574Smckusic #include "../h/stat.h" 1037Sbill #include "../h/inode.h" 116574Smckusic #include "../h/fs.h" 126254Sroot #include "../h/buf.h" 136254Sroot #include "../h/proc.h" 147482Skre #include "../h/quota.h" 157505Sroot #include "../h/descrip.h" 167826Sroot #include "../h/uio.h" 177826Sroot #include "../h/socket.h" 188632Sroot #include "../h/socketvar.h" 19*9167Ssam #include "../h/nami.h" 2037Sbill 21*9167Ssam /* 22*9167Ssam * Change current working directory (``.''). 23*9167Ssam */ 246254Sroot chdir() 256254Sroot { 266254Sroot 276254Sroot chdirec(&u.u_cdir); 286254Sroot } 296254Sroot 30*9167Ssam /* 31*9167Ssam * Change notion of root (``/'') directory. 32*9167Ssam */ 336254Sroot chroot() 346254Sroot { 356254Sroot 366254Sroot if (suser()) 376254Sroot chdirec(&u.u_rdir); 386254Sroot } 396254Sroot 40*9167Ssam /* 41*9167Ssam * Common routine for chroot and chdir. 42*9167Ssam */ 436254Sroot chdirec(ipp) 447701Ssam register struct inode **ipp; 456254Sroot { 466254Sroot register struct inode *ip; 476254Sroot struct a { 486254Sroot char *fname; 496254Sroot }; 506254Sroot 51*9167Ssam ip = namei(uchar, LOOKUP, 1); 52*9167Ssam if (ip == NULL) 536254Sroot return; 54*9167Ssam if ((ip->i_mode&IFMT) != IFDIR) { 556254Sroot u.u_error = ENOTDIR; 566254Sroot goto bad; 576254Sroot } 58*9167Ssam if (access(ip, IEXEC)) 596254Sroot goto bad; 607122Smckusick iunlock(ip); 617142Smckusick if (*ipp) 627142Smckusick irele(*ipp); 636254Sroot *ipp = ip; 646254Sroot return; 656254Sroot 666254Sroot bad: 676254Sroot iput(ip); 686254Sroot } 696254Sroot 7037Sbill /* 716254Sroot * Open system call. 726254Sroot */ 736254Sroot open() 746254Sroot { 756254Sroot register struct inode *ip; 766254Sroot register struct a { 776254Sroot char *fname; 787701Ssam int flags; 797701Ssam int mode; 806254Sroot } *uap; 81*9167Ssam int checkpermissions = 1, flags; 826254Sroot 836254Sroot uap = (struct a *)u.u_ap; 84*9167Ssam flags = uap->flags + 1; 85*9167Ssam if ((flags&FTRUNCATE) && (flags&FWRITE) == 0) { 86*9167Ssam u.u_error = EINVAL; 87*9167Ssam return; 88*9167Ssam } 89*9167Ssam if (flags&FCREATE) { 90*9167Ssam ip = namei(uchar, CREATE, 1); 917701Ssam if (ip == NULL) { 927701Ssam if (u.u_error) 937701Ssam return; 947701Ssam ip = maknode(uap->mode&07777&(~ISVTX)); 957701Ssam checkpermissions = 0; 96*9167Ssam flags &= ~FTRUNCATE; 977701Ssam } 987701Ssam } else 99*9167Ssam ip = namei(uchar, LOOKUP, 1); 1006254Sroot if (ip == NULL) 1016254Sroot return; 102*9167Ssam open1(ip, flags, checkpermissions); 1036254Sroot } 1046254Sroot 1057701Ssam #ifndef NOCOMPAT 1066254Sroot /* 1076254Sroot * Creat system call. 1086254Sroot */ 1097505Sroot ocreat() 1106254Sroot { 1116254Sroot register struct inode *ip; 1126254Sroot register struct a { 1136254Sroot char *fname; 1146254Sroot int fmode; 1156254Sroot } *uap; 1166254Sroot 1176254Sroot uap = (struct a *)u.u_ap; 118*9167Ssam ip = namei(uchar, CREATE, 1); 1196254Sroot if (ip == NULL) { 1206254Sroot if (u.u_error) 1216254Sroot return; 1226254Sroot ip = maknode(uap->fmode&07777&(~ISVTX)); 1237701Ssam if (ip == NULL) 1246254Sroot return; 1257701Ssam open1(ip, FWRITE, 0); 1266254Sroot } else 127*9167Ssam open1(ip, FWRITE|FTRUNCATE, 1); 1286254Sroot } 1297701Ssam #endif 1306254Sroot 1316254Sroot /* 1326254Sroot * Common code for open and creat. 1337701Ssam * Check permissions (if we haven't done so already), 1347701Ssam * allocate an open file structure, and call 1357701Ssam * the device open routine, if any. 1366254Sroot */ 1377701Ssam open1(ip, mode, checkpermissions) 1386254Sroot register struct inode *ip; 1396254Sroot register mode; 1406254Sroot { 1416254Sroot register struct file *fp; 1427701Ssam int i, flags; 1436254Sroot 1447701Ssam if (checkpermissions) { 1456254Sroot if (mode&FREAD) 1467701Ssam if (access(ip, IREAD)) 1477701Ssam goto bad; 1486254Sroot if (mode&FWRITE) { 1497701Ssam if (access(ip, IWRITE)) 1507701Ssam goto bad; 1517701Ssam if ((ip->i_mode&IFMT) == IFDIR) { 1526254Sroot u.u_error = EISDIR; 1537701Ssam goto bad; 1547701Ssam } 1556254Sroot } 1566254Sroot } 1577701Ssam 1587701Ssam /* 1597701Ssam * Check locking on inode. Release "inode lock" 1607701Ssam * while doing so in case we block inside flocki. 1617701Ssam */ 1627701Ssam flags = 0; 163*9167Ssam if (mode&(FSHLOCK|FEXLOCK)) { 1647701Ssam iunlock(ip); 1657701Ssam flags = flocki(ip, 0, mode); 1667701Ssam ilock(ip); 1677701Ssam if (u.u_error) 1687701Ssam goto bad; 1697142Smckusick } 1707701Ssam if (mode&FTRUNCATE) 171*9167Ssam itrunc(ip, (u_long)0); 1727122Smckusick iunlock(ip); 1736254Sroot if ((fp = falloc()) == NULL) 1746254Sroot goto out; 1757701Ssam fp->f_flag = mode & FMODES; 1767505Sroot fp->f_type = DTYPE_FILE; 1776254Sroot i = u.u_r.r_val1; 1786254Sroot fp->f_inode = ip; 1798559Sroot u.u_error = openi(ip, mode); 1807701Ssam if (u.u_error == 0) { 1817701Ssam u.u_pofile[i] = flags; 1826254Sroot return; 1837701Ssam } 1846254Sroot u.u_ofile[i] = NULL; 1856254Sroot fp->f_count--; 1866254Sroot out: 1877142Smckusick irele(ip); 1887701Ssam return; 1897701Ssam bad: 1907701Ssam iput(ip); 1916254Sroot } 1926254Sroot 1936254Sroot /* 1946254Sroot * Mknod system call 1956254Sroot */ 1966254Sroot mknod() 1976254Sroot { 1986254Sroot register struct inode *ip; 1996254Sroot register struct a { 2006254Sroot char *fname; 2016254Sroot int fmode; 2026254Sroot int dev; 2036254Sroot } *uap; 2046254Sroot 2056254Sroot uap = (struct a *)u.u_ap; 2066254Sroot if (suser()) { 207*9167Ssam ip = namei(uchar, CREATE, 0); 2086254Sroot if (ip != NULL) { 2096254Sroot u.u_error = EEXIST; 2106254Sroot goto out; 2116254Sroot } 2126254Sroot } 2136254Sroot if (u.u_error) 2146254Sroot return; 2156254Sroot ip = maknode(uap->fmode); 2166254Sroot if (ip == NULL) 2176254Sroot return; 2186254Sroot if (uap->dev) { 2196254Sroot /* 2206254Sroot * Want to be able to use this to make badblock 2216254Sroot * inodes, so don't truncate the dev number. 2226254Sroot */ 2236574Smckusic ip->i_rdev = uap->dev; 2246254Sroot ip->i_flag |= IACC|IUPD|ICHG; 2256254Sroot } 2266254Sroot 2276254Sroot out: 2286254Sroot iput(ip); 2296254Sroot } 2306254Sroot 2316254Sroot /* 2326254Sroot * link system call 2336254Sroot */ 2346254Sroot link() 2356254Sroot { 2366254Sroot register struct inode *ip, *xp; 2376254Sroot register struct a { 2386254Sroot char *target; 2396254Sroot char *linkname; 2406254Sroot } *uap; 2416254Sroot 2426254Sroot uap = (struct a *)u.u_ap; 243*9167Ssam ip = namei(uchar, LOOKUP, 1); /* well, this routine is doomed anyhow */ 2446254Sroot if (ip == NULL) 2456254Sroot return; 246*9167Ssam if ((ip->i_mode&IFMT) == IFDIR && !suser()) { 2477439Sroot iput(ip); 2487439Sroot return; 2497439Sroot } 2506254Sroot ip->i_nlink++; 2516254Sroot ip->i_flag |= ICHG; 2528673Sroot iupdat(ip, &time, &time, 1); 2537122Smckusick iunlock(ip); 2546254Sroot u.u_dirp = (caddr_t)uap->linkname; 255*9167Ssam xp = namei(uchar, CREATE, 0); 2566254Sroot if (xp != NULL) { 2576254Sroot u.u_error = EEXIST; 2586254Sroot iput(xp); 2596254Sroot goto out; 2606254Sroot } 2616254Sroot if (u.u_error) 2626254Sroot goto out; 2636254Sroot if (u.u_pdir->i_dev != ip->i_dev) { 2646254Sroot iput(u.u_pdir); 2656254Sroot u.u_error = EXDEV; 2666254Sroot goto out; 2676254Sroot } 2687535Sroot direnter(ip); 2696254Sroot out: 2706254Sroot if (u.u_error) { 2716254Sroot ip->i_nlink--; 2726254Sroot ip->i_flag |= ICHG; 2736254Sroot } 2747142Smckusick irele(ip); 2756254Sroot } 2766254Sroot 2776254Sroot /* 2786254Sroot * symlink -- make a symbolic link 2796254Sroot */ 2806254Sroot symlink() 2816254Sroot { 2826254Sroot register struct a { 2836254Sroot char *target; 2846254Sroot char *linkname; 2856254Sroot } *uap; 2866254Sroot register struct inode *ip; 2876254Sroot register char *tp; 2886254Sroot register c, nc; 2896254Sroot 2906254Sroot uap = (struct a *)u.u_ap; 2916254Sroot tp = uap->target; 2926254Sroot nc = 0; 2936254Sroot while (c = fubyte(tp)) { 2946254Sroot if (c < 0) { 2956254Sroot u.u_error = EFAULT; 2966254Sroot return; 2976254Sroot } 2986254Sroot tp++; 2996254Sroot nc++; 3006254Sroot } 3016254Sroot u.u_dirp = uap->linkname; 302*9167Ssam ip = namei(uchar, CREATE, 0); 3036254Sroot if (ip) { 3046254Sroot iput(ip); 3056254Sroot u.u_error = EEXIST; 3066254Sroot return; 3076254Sroot } 3086254Sroot if (u.u_error) 3096254Sroot return; 3106254Sroot ip = maknode(IFLNK | 0777); 3116254Sroot if (ip == NULL) 3126254Sroot return; 3137826Sroot u.u_error = rdwri(UIO_WRITE, ip, uap->target, nc, 0, 0, (int *)0); 314*9167Ssam /* handle u.u_error != 0 */ 3156254Sroot iput(ip); 3166254Sroot } 3176254Sroot 3186254Sroot /* 3196254Sroot * Unlink system call. 3206254Sroot * Hard to avoid races here, especially 3216254Sroot * in unlinking directories. 3226254Sroot */ 3236254Sroot unlink() 3246254Sroot { 3256254Sroot struct a { 3266254Sroot char *fname; 3276254Sroot }; 328*9167Ssam register struct inode *ip, *dp; 3296254Sroot 330*9167Ssam ip = namei(uchar, DELETE | LOCKPARENT, 0); 331*9167Ssam if (ip == NULL) 3326254Sroot return; 333*9167Ssam dp = u.u_pdir; 334*9167Ssam if ((ip->i_mode&IFMT) == IFDIR && !suser()) 3356254Sroot goto out; 3366254Sroot /* 3376254Sroot * Don't unlink a mounted file. 3386254Sroot */ 339*9167Ssam if (ip->i_dev != dp->i_dev) { 3406254Sroot u.u_error = EBUSY; 3416254Sroot goto out; 3426254Sroot } 3436254Sroot if (ip->i_flag&ITEXT) 3446254Sroot xrele(ip); /* try once to free text */ 3457535Sroot if (dirremove()) { 3467535Sroot ip->i_nlink--; 3477535Sroot ip->i_flag |= ICHG; 3486254Sroot } 3496254Sroot out: 350*9167Ssam if (dp == ip) 3517142Smckusick irele(ip); 3527142Smckusick else 3537142Smckusick iput(ip); 354*9167Ssam iput(dp); 3556254Sroot } 3566254Sroot 3576254Sroot /* 3586254Sroot * Seek system call 3596254Sroot */ 3608040Sroot lseek() 3616254Sroot { 3626254Sroot register struct file *fp; 3636254Sroot register struct a { 3647701Ssam int fd; 3656254Sroot off_t off; 3666254Sroot int sbase; 3676254Sroot } *uap; 3686254Sroot 3696254Sroot uap = (struct a *)u.u_ap; 3707701Ssam fp = getf(uap->fd); 3716254Sroot if (fp == NULL) 3726254Sroot return; 3737505Sroot if (fp->f_type == DTYPE_SOCKET) { 3746254Sroot u.u_error = ESPIPE; 3756254Sroot return; 3766254Sroot } 3777701Ssam if (uap->sbase == FSEEK_RELATIVE) 3786254Sroot uap->off += fp->f_offset; 3797701Ssam else if (uap->sbase == FSEEK_EOF) 3806254Sroot uap->off += fp->f_inode->i_size; 3816254Sroot fp->f_offset = uap->off; 3826254Sroot u.u_r.r_off = uap->off; 3836254Sroot } 3846254Sroot 3856254Sroot /* 3866254Sroot * Access system call 3876254Sroot */ 3886254Sroot saccess() 3896254Sroot { 3906254Sroot register svuid, svgid; 3916254Sroot register struct inode *ip; 3926254Sroot register struct a { 3936254Sroot char *fname; 3946254Sroot int fmode; 3956254Sroot } *uap; 3966254Sroot 3976254Sroot uap = (struct a *)u.u_ap; 3986254Sroot svuid = u.u_uid; 3996254Sroot svgid = u.u_gid; 4006254Sroot u.u_uid = u.u_ruid; 4016254Sroot u.u_gid = u.u_rgid; 402*9167Ssam ip = namei(uchar, LOOKUP, 1); 4036254Sroot if (ip != NULL) { 404*9167Ssam if ((uap->fmode&FACCESS_READ) && access(ip, IREAD)) 4057701Ssam goto done; 406*9167Ssam if ((uap->fmode&FACCESS_WRITE) && access(ip, IWRITE)) 4077701Ssam goto done; 408*9167Ssam if ((uap->fmode&FACCESS_EXECUTE) && access(ip, IEXEC)) 4097701Ssam goto done; 4107701Ssam done: 4116254Sroot iput(ip); 4126254Sroot } 4136254Sroot u.u_uid = svuid; 4146254Sroot u.u_gid = svgid; 4156254Sroot } 4166254Sroot 4176254Sroot /* 41837Sbill * the fstat system call. 41937Sbill */ 42037Sbill fstat() 42137Sbill { 42237Sbill register struct file *fp; 42337Sbill register struct a { 4247701Ssam int fd; 42537Sbill struct stat *sb; 42637Sbill } *uap; 42737Sbill 42837Sbill uap = (struct a *)u.u_ap; 4297701Ssam fp = getf(uap->fd); 4304828Swnj if (fp == NULL) 43137Sbill return; 4327505Sroot if (fp->f_type == DTYPE_SOCKET) 4334891Swnj u.u_error = sostat(fp->f_socket, uap->sb); 4344828Swnj else 4354828Swnj stat1(fp->f_inode, uap->sb); 43637Sbill } 43737Sbill 43837Sbill /* 4396574Smckusic * Stat system call. This version follows links. 44037Sbill */ 44137Sbill stat() 44237Sbill { 44337Sbill register struct inode *ip; 44437Sbill register struct a { 44537Sbill char *fname; 44637Sbill struct stat *sb; 44737Sbill } *uap; 44837Sbill 44937Sbill uap = (struct a *)u.u_ap; 450*9167Ssam ip = namei(uchar, LOOKUP, 1); 4514828Swnj if (ip == NULL) 45237Sbill return; 4533624Sroot stat1(ip, uap->sb); 45437Sbill iput(ip); 45537Sbill } 45637Sbill 45737Sbill /* 4586574Smckusic * Lstat system call. This version does not follow links. 4595992Swnj */ 4605992Swnj lstat() 4615992Swnj { 4625992Swnj register struct inode *ip; 4635992Swnj register struct a { 4645992Swnj char *fname; 4655992Swnj struct stat *sb; 4665992Swnj } *uap; 4675992Swnj 4685992Swnj uap = (struct a *)u.u_ap; 469*9167Ssam ip = namei(uchar, LOOKUP, 0); 4705992Swnj if (ip == NULL) 4715992Swnj return; 4726153Ssam stat1(ip, uap->sb); 4735992Swnj iput(ip); 4745992Swnj } 4755992Swnj 4765992Swnj /* 47737Sbill * The basic routine for fstat and stat: 47837Sbill * get the inode and pass appropriate parts back. 47937Sbill */ 4803624Sroot stat1(ip, ub) 4814828Swnj register struct inode *ip; 4824828Swnj struct stat *ub; 48337Sbill { 48437Sbill struct stat ds; 48537Sbill 4868673Sroot IUPDAT(ip, &time, &time, 0); 48737Sbill /* 4887023Smckusick * Copy from inode table 48937Sbill */ 49037Sbill ds.st_dev = ip->i_dev; 49137Sbill ds.st_ino = ip->i_number; 49237Sbill ds.st_mode = ip->i_mode; 49337Sbill ds.st_nlink = ip->i_nlink; 49437Sbill ds.st_uid = ip->i_uid; 49537Sbill ds.st_gid = ip->i_gid; 4966574Smckusic ds.st_rdev = (dev_t)ip->i_rdev; 4973624Sroot ds.st_size = ip->i_size; 4986574Smckusic ds.st_atime = ip->i_atime; 4996574Smckusic ds.st_mtime = ip->i_mtime; 5006574Smckusic ds.st_ctime = ip->i_ctime; 5017701Ssam /* this doesn't belong here */ 5027701Ssam if ((ip->i_mode&IFMT) == IFBLK) 5037701Ssam ds.st_blksize = BLKDEV_IOSIZE; 5047701Ssam else if ((ip->i_mode&IFMT) == IFCHR) 5057701Ssam ds.st_blksize = MAXBSIZE; 5067701Ssam else 5077701Ssam ds.st_blksize = ip->i_fs->fs_bsize; 50837Sbill if (copyout((caddr_t)&ds, (caddr_t)ub, sizeof(ds)) < 0) 50937Sbill u.u_error = EFAULT; 51037Sbill } 51137Sbill 51237Sbill /* 5135992Swnj * Return target name of a symbolic link 51437Sbill */ 5155992Swnj readlink() 5165992Swnj { 5175992Swnj register struct inode *ip; 5185992Swnj register struct a { 5195992Swnj char *name; 5205992Swnj char *buf; 5215992Swnj int count; 5227826Sroot } *uap = (struct a *)u.u_ap; 5237826Sroot int resid; 5245992Swnj 525*9167Ssam ip = namei(uchar, LOOKUP, 0); 5265992Swnj if (ip == NULL) 5275992Swnj return; 5285992Swnj if ((ip->i_mode&IFMT) != IFLNK) { 5295992Swnj u.u_error = ENXIO; 5305992Swnj goto out; 5315992Swnj } 5327826Sroot u.u_error = rdwri(UIO_READ, ip, uap->buf, uap->count, 0, 0, &resid); 5335992Swnj out: 5345992Swnj iput(ip); 5357826Sroot u.u_r.r_val1 = uap->count - resid; 5365992Swnj } 5375992Swnj 538*9167Ssam /* 539*9167Ssam * Change mode of a file given path name. 540*9167Ssam */ 5416254Sroot chmod() 5425992Swnj { 5437701Ssam struct inode *ip; 5447701Ssam struct a { 5456254Sroot char *fname; 5466254Sroot int fmode; 5475992Swnj } *uap; 5485992Swnj 5495992Swnj uap = (struct a *)u.u_ap; 5506254Sroot if ((ip = owner(1)) == NULL) 5515992Swnj return; 5527701Ssam chmod1(ip, uap->fmode); 553*9167Ssam iput(ip); 5547701Ssam } 5557439Sroot 556*9167Ssam /* 557*9167Ssam * Change mode of a file given a file descriptor. 558*9167Ssam */ 5597701Ssam fchmod() 5607701Ssam { 5617701Ssam struct a { 5627701Ssam int fd; 5637701Ssam int fmode; 5647701Ssam } *uap; 5657701Ssam register struct inode *ip; 5667701Ssam register struct file *fp; 5677701Ssam 5687701Ssam uap = (struct a *)u.u_ap; 5697701Ssam fp = getf(uap->fd); 5707701Ssam if (fp == NULL) 5717701Ssam return; 5727701Ssam if (fp->f_type == DTYPE_SOCKET) { 5737701Ssam u.u_error = EINVAL; 5747701Ssam return; 5757439Sroot } 5767701Ssam ip = fp->f_inode; 577*9167Ssam if (u.u_uid != ip->i_uid && !suser()) 578*9167Ssam return; 5797701Ssam ilock(ip); 5807701Ssam chmod1(ip, uap->fmode); 581*9167Ssam iunlock(ip); 5827701Ssam } 5837701Ssam 584*9167Ssam /* 585*9167Ssam * Change the mode on a file. 586*9167Ssam * Inode must be locked before calling. 587*9167Ssam */ 5887701Ssam chmod1(ip, mode) 5897701Ssam register struct inode *ip; 5907701Ssam register int mode; 5917701Ssam { 5927868Sroot register int *gp; 5937868Sroot 5946254Sroot ip->i_mode &= ~07777; 5957439Sroot if (u.u_uid) { 5967701Ssam mode &= ~ISVTX; 5977868Sroot for (gp = u.u_groups; gp < &u.u_groups[NGROUPS]; gp++) 5987868Sroot if (*gp == ip->i_gid) 5997868Sroot goto ok; 6007868Sroot mode &= ~ISGID; 6017868Sroot ok: 6027868Sroot ; 6037701Ssam #ifdef MUSH 6047482Skre if (u.u_quota->q_syflags & QF_UMASK && u.u_uid != 0 && 6057482Skre (ip->i_mode & IFMT) != IFCHR) 6067701Ssam mode &= ~u.u_cmask; 6077482Skre #endif 6087439Sroot } 6097701Ssam ip->i_mode |= mode&07777; 6106254Sroot ip->i_flag |= ICHG; 6116254Sroot if (ip->i_flag&ITEXT && (ip->i_mode&ISVTX)==0) 6126254Sroot xrele(ip); 6135992Swnj } 6145992Swnj 615*9167Ssam /* 616*9167Ssam * Set ownership given a path name. 617*9167Ssam */ 6186254Sroot chown() 61937Sbill { 6207701Ssam struct inode *ip; 6217701Ssam struct a { 6226254Sroot char *fname; 6236254Sroot int uid; 6246254Sroot int gid; 62537Sbill } *uap; 62637Sbill 62737Sbill uap = (struct a *)u.u_ap; 6286254Sroot if (!suser() || (ip = owner(0)) == NULL) 62937Sbill return; 6307701Ssam chown1(ip, uap->uid, uap->gid); 631*9167Ssam iput(ip); 6327701Ssam } 6337439Sroot 634*9167Ssam /* 635*9167Ssam * Set ownership given a file descriptor. 636*9167Ssam */ 6377701Ssam fchown() 6387701Ssam { 6397701Ssam struct a { 6407701Ssam int fd; 6417701Ssam int uid; 6427701Ssam int gid; 6437701Ssam } *uap; 6447701Ssam register struct inode *ip; 6457701Ssam register struct file *fp; 6467701Ssam 6477701Ssam uap = (struct a *)u.u_ap; 6487701Ssam fp = getf(uap->fd); 6497701Ssam if (fp == NULL) 6507701Ssam return; 6517701Ssam if (fp->f_type == DTYPE_SOCKET) { 6527701Ssam u.u_error = EINVAL; 6537701Ssam return; 6547439Sroot } 6557701Ssam ip = fp->f_inode; 656*9167Ssam if (!suser()) 657*9167Ssam return; 6587701Ssam ilock(ip); 6597701Ssam chown1(ip, uap->uid, uap->gid); 660*9167Ssam iunlock(ip); 6617701Ssam } 6627701Ssam 6637701Ssam /* 6647701Ssam * Perform chown operation on inode ip; 6657701Ssam * inode must be locked prior to call. 6667701Ssam */ 6677701Ssam chown1(ip, uid, gid) 6687701Ssam register struct inode *ip; 6697701Ssam int uid, gid; 6707701Ssam { 6717701Ssam #ifdef QUOTA 6727701Ssam register long change; 6737701Ssam 6747439Sroot /* 6757482Skre * This doesn't allow for holes in files (which hopefully don't 6767482Skre * happen often in files that we chown), and is not accurate anyway 6777482Skre * (eg: it totally ignores 3 level indir blk files - but hopefully 6787482Skre * noone who can make a file that big will have a quota) 6797482Skre */ 6807701Ssam if (ip->i_uid == uid) 6817482Skre change = 0; 6827482Skre else { 6837482Skre register struct fs *fs = ip->i_fs; 6847482Skre 6857482Skre if (ip->i_size > (change = NDADDR * fs->fs_bsize)) { 6867482Skre register off_t size; 6877482Skre 6887482Skre size = blkroundup(fs, ip->i_size) - change; 6897482Skre change += size; 6907482Skre change += fs->fs_bsize; 6917701Ssam /* this assumes NIADDR <= 2 */ 6927482Skre if (size > NINDIR(fs) * fs->fs_bsize) 6937482Skre change += fs->fs_bsize; 6947482Skre } else 6957482Skre change = fragroundup(fs, ip->i_size); 6967482Skre change /= DEV_BSIZE; 6977482Skre } 698*9167Ssam (void)chkdq(ip, -change, 1); 699*9167Ssam (void)chkiq(ip->i_dev, ip, ip->i_uid, 1); 7007482Skre dqrele(ip->i_dquot); 7017482Skre #endif 7027482Skre /* 7037701Ssam * keep uid/gid's in sane range -- no err, 7047701Ssam * so chown(file, uid, -1) will do something useful 7057439Sroot */ 7067701Ssam if (uid >= 0 && uid <= 32767) /* should have a constant */ 7077701Ssam ip->i_uid = uid; 7087701Ssam if (gid >= 0 && gid <= 32767) /* same here */ 7097701Ssam ip->i_gid = gid; 7106254Sroot ip->i_flag |= ICHG; 7116254Sroot if (u.u_ruid != 0) 7126254Sroot ip->i_mode &= ~(ISUID|ISGID); 7137701Ssam #ifdef QUOTA 7147482Skre ip->i_dquot = inoquota(ip); 715*9167Ssam (void)chkdq(ip, change, 1); 716*9167Ssam (void)chkiq(ip->i_dev, (struct inode *)NULL, uid, 1); 7177482Skre #endif 71837Sbill } 71937Sbill 72037Sbill /* 7216254Sroot * Set IUPD and IACC times on file. 7226254Sroot * Can't set ICHG. 72337Sbill */ 7248107Sroot outime() 7254828Swnj { 72637Sbill register struct a { 7276254Sroot char *fname; 7286254Sroot time_t *tptr; 72937Sbill } *uap; 7306254Sroot register struct inode *ip; 7316254Sroot time_t tv[2]; 7328632Sroot struct timeval tv0, tv1; 73337Sbill 73437Sbill uap = (struct a *)u.u_ap; 7356254Sroot if ((ip = owner(1)) == NULL) 73637Sbill return; 7376254Sroot if (copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof(tv))) { 7386254Sroot u.u_error = EFAULT; 7396254Sroot } else { 7406254Sroot ip->i_flag |= IACC|IUPD|ICHG; 7418632Sroot tv0.tv_sec = tv[0]; tv0.tv_usec = 0; 7428632Sroot tv1.tv_sec = tv[1]; tv1.tv_usec = 0; 7438632Sroot iupdat(ip, &tv0, &tv1, 0); 74437Sbill } 74537Sbill iput(ip); 74637Sbill } 74737Sbill 748*9167Ssam /* 749*9167Ssam * Flush any pending I/O. 750*9167Ssam */ 7516254Sroot sync() 75237Sbill { 75337Sbill 7548673Sroot update(); 75537Sbill } 7567535Sroot 757*9167Ssam /* 758*9167Ssam * Apply an advisory lock on a file descriptor. 759*9167Ssam */ 7607701Ssam flock() 7617701Ssam { 7627701Ssam struct a { 7637701Ssam int fd; 7647701Ssam int how; 7657701Ssam } *uap; 7667701Ssam register struct file *fp; 7677701Ssam register int cmd, flags; 7687701Ssam 7697701Ssam uap = (struct a *)u.u_ap; 7707701Ssam fp = getf(uap->fd); 7717701Ssam if (fp == NULL) 7727701Ssam return; 7737701Ssam if (fp->f_type == DTYPE_SOCKET) { /* XXX */ 7747701Ssam u.u_error = EINVAL; 7757701Ssam return; 7767701Ssam } 7777701Ssam cmd = uap->how; 778*9167Ssam flags = u.u_pofile[uap->fd] & (SHLOCK|EXLOCK); 7797701Ssam if (cmd&FUNLOCK) { 7807701Ssam if (flags == 0) { 7817701Ssam u.u_error = EINVAL; 7827701Ssam return; 7837701Ssam } 7847701Ssam funlocki(fp->f_inode, flags); 785*9167Ssam u.u_pofile[uap->fd] &= ~(SHLOCK|EXLOCK); 7867701Ssam return; 7877701Ssam } 7887701Ssam /* 7897701Ssam * No reason to write lock a file we've already 7907701Ssam * write locked, similarly with a read lock. 7917701Ssam */ 792*9167Ssam if ((flags&EXLOCK) && (cmd&FEXLOCK) || 793*9167Ssam (flags&SHLOCK) && (cmd&FSHLOCK)) 7947701Ssam return; 7957701Ssam u.u_pofile[uap->fd] = flocki(fp->f_inode, u.u_pofile[uap->fd], cmd); 7967701Ssam } 7977701Ssam 798*9167Ssam /* 799*9167Ssam * Truncate a file given its path name. 800*9167Ssam */ 8017701Ssam truncate() 8027701Ssam { 8037701Ssam struct a { 8047701Ssam char *fname; 805*9167Ssam u_long length; 8067826Sroot } *uap = (struct a *)u.u_ap; 8077701Ssam struct inode *ip; 8087701Ssam 809*9167Ssam ip = namei(uchar, LOOKUP, 1); 8107701Ssam if (ip == NULL) 8117701Ssam return; 8127701Ssam if (access(ip, IWRITE)) 8137701Ssam goto bad; 8147701Ssam if ((ip->i_mode&IFMT) == IFDIR) { 8157701Ssam u.u_error = EISDIR; 8167701Ssam goto bad; 8177701Ssam } 8187701Ssam itrunc(ip, uap->length); 8197701Ssam bad: 8207701Ssam iput(ip); 8217701Ssam } 8227701Ssam 823*9167Ssam /* 824*9167Ssam * Truncate a file given a file descriptor. 825*9167Ssam */ 8267701Ssam ftruncate() 8277701Ssam { 8287701Ssam struct a { 8297701Ssam int fd; 830*9167Ssam u_long length; 8317826Sroot } *uap = (struct a *)u.u_ap; 8327701Ssam struct inode *ip; 8337701Ssam struct file *fp; 8347701Ssam 8357701Ssam fp = getf(uap->fd); 8367701Ssam if (fp == NULL) 8377701Ssam return; 8387701Ssam if (fp->f_type == DTYPE_SOCKET) { 8397701Ssam u.u_error = EINVAL; 8407701Ssam return; 8417701Ssam } 8427701Ssam if ((fp->f_flag&FWRITE) == 0) { 8437701Ssam u.u_error = EINVAL; 8447701Ssam return; 8457701Ssam } 8467701Ssam ip = fp->f_inode; 8477701Ssam ilock(ip); 8487701Ssam itrunc(ip, uap->length); 849*9167Ssam iunlock(ip); 8507701Ssam } 8517701Ssam 852*9167Ssam /* 853*9167Ssam * Synch an open file. 854*9167Ssam */ 855*9167Ssam fsync() 856*9167Ssam { 857*9167Ssam struct a { 858*9167Ssam int fd; 859*9167Ssam } *uap = (struct a *)u.u_ap; 860*9167Ssam struct inode *ip; 861*9167Ssam struct file *fp; 862*9167Ssam 863*9167Ssam fp = getf(uap->fd); 864*9167Ssam if (fp == NULL) 865*9167Ssam return; 866*9167Ssam if (fp->f_type == DTYPE_SOCKET) { 867*9167Ssam u.u_error = EINVAL; 868*9167Ssam return; 869*9167Ssam } 870*9167Ssam ip = fp->f_inode; 871*9167Ssam ilock(ip); 872*9167Ssam syncip(ip); 873*9167Ssam iunlock(ip); 874*9167Ssam } 875*9167Ssam 876*9167Ssam /* 877*9167Ssam * Rename system call. 878*9167Ssam * rename("foo", "bar"); 879*9167Ssam * is essentially 880*9167Ssam * unlink("bar"); 881*9167Ssam * link("foo", "bar"); 882*9167Ssam * unlink("foo"); 883*9167Ssam * but ``atomically''. Can't do full commit without saving state in the 884*9167Ssam * inode on disk which isn't feasible at this time. Best we can do is 885*9167Ssam * always guarantee the target exists. 886*9167Ssam * 887*9167Ssam * Basic algorithm is: 888*9167Ssam * 889*9167Ssam * 1) Bump link count on source while we're linking it to the 890*9167Ssam * target. This also insure the inode won't be deleted out 891*9167Ssam * from underneath us while we work. 892*9167Ssam * 2) Link source to destination. If destination already exists, 893*9167Ssam * delete it first. 894*9167Ssam * 3) Unlink source reference to inode if still around. 895*9167Ssam * 4) If a directory was moved and the parent of the destination 896*9167Ssam * is different from the source, patch the ".." entry in the 897*9167Ssam * directory. 898*9167Ssam * 899*9167Ssam * Source and destination must either both be directories, or both 900*9167Ssam * not be directories. If target is a directory, it must be empty. 901*9167Ssam */ 9027701Ssam rename() 9037701Ssam { 9047701Ssam struct a { 9057701Ssam char *from; 9067701Ssam char *to; 9077701Ssam } *uap; 908*9167Ssam register struct inode *ip, *xp, *dp; 909*9167Ssam int oldparent, parentdifferent, doingdirectory; 9107701Ssam 911*9167Ssam uap = (struct a *)u.u_ap; 912*9167Ssam ip = namei(uchar, LOOKUP | LOCKPARENT, 0); 913*9167Ssam if (ip == NULL) 914*9167Ssam return; 915*9167Ssam dp = u.u_pdir; 916*9167Ssam oldparent = 0, doingdirectory = 0; 917*9167Ssam if ((ip->i_mode&IFMT) == IFDIR) { 918*9167Ssam register struct direct *d; 919*9167Ssam 920*9167Ssam d = &u.u_dent; 921*9167Ssam /* 922*9167Ssam * Avoid "." and ".." for obvious reasons. 923*9167Ssam */ 924*9167Ssam if (d->d_name[0] == '.') { 925*9167Ssam if (d->d_namlen == 1 || 926*9167Ssam (d->d_namlen == 2 && d->d_name[1] == '.')) { 927*9167Ssam u.u_error = EINVAL; 928*9167Ssam iput(ip); 929*9167Ssam return; 930*9167Ssam } 931*9167Ssam } 932*9167Ssam oldparent = dp->i_number; 933*9167Ssam doingdirectory++; 934*9167Ssam } 935*9167Ssam irele(dp); 936*9167Ssam 937*9167Ssam /* 938*9167Ssam * 1) Bump link count while we're moving stuff 939*9167Ssam * around. If we crash somewhere before 940*9167Ssam * completing our work, the link count 941*9167Ssam * may be wrong, but correctable. 942*9167Ssam */ 943*9167Ssam ip->i_nlink++; 944*9167Ssam ip->i_flag |= ICHG; 945*9167Ssam iupdat(ip, &time, &time, 1); 946*9167Ssam iunlock(ip); 947*9167Ssam 948*9167Ssam /* 949*9167Ssam * When the target exists, both the directory 950*9167Ssam * and target inodes are returned locked. 951*9167Ssam */ 952*9167Ssam u.u_dirp = (caddr_t)uap->to; 953*9167Ssam xp = namei(uchar, CREATE | LOCKPARENT, 0); 954*9167Ssam if (u.u_error) 955*9167Ssam goto out; 956*9167Ssam dp = u.u_pdir; 957*9167Ssam /* 958*9167Ssam * 2) If target doesn't exist, link the target 959*9167Ssam * to the source and unlink the source. 960*9167Ssam * Otherwise, rewrite the target directory 961*9167Ssam * entry to reference the source inode and 962*9167Ssam * expunge the original entry's existence. 963*9167Ssam */ 964*9167Ssam parentdifferent = oldparent != dp->i_number; 965*9167Ssam if (xp == NULL) { 966*9167Ssam if (dp->i_dev != ip->i_dev) { 967*9167Ssam u.u_error = EXDEV; 968*9167Ssam goto bad; 969*9167Ssam } 970*9167Ssam /* 971*9167Ssam * Account for ".." in directory. 972*9167Ssam * When source and destination have the 973*9167Ssam * same parent we don't fool with the 974*9167Ssam * link count -- this isn't required 975*9167Ssam * because we do a similar check below. 976*9167Ssam */ 977*9167Ssam if (doingdirectory && parentdifferent) { 978*9167Ssam dp->i_nlink++; 979*9167Ssam dp->i_flag |= ICHG; 980*9167Ssam iupdat(dp, &time, &time, 1); 981*9167Ssam } 982*9167Ssam direnter(ip); 983*9167Ssam if (u.u_error) 984*9167Ssam goto out; 985*9167Ssam } else { 986*9167Ssam if (xp->i_dev != dp->i_dev || xp->i_dev != ip->i_dev) { 987*9167Ssam u.u_error = EXDEV; 988*9167Ssam goto bad; 989*9167Ssam } 990*9167Ssam /* 991*9167Ssam * Target must be empty if a directory. 992*9167Ssam * Also, insure source and target are 993*9167Ssam * compatible (both directories, or both 994*9167Ssam * not directories). 995*9167Ssam */ 996*9167Ssam if ((xp->i_mode&IFMT) == IFDIR) { 997*9167Ssam if (!dirempty(xp)) { 998*9167Ssam u.u_error = EEXIST; /* XXX */ 999*9167Ssam goto bad; 1000*9167Ssam } 1001*9167Ssam if (!doingdirectory) { 1002*9167Ssam u.u_error = ENOTDIR; 1003*9167Ssam goto bad; 1004*9167Ssam } 1005*9167Ssam } else if (doingdirectory) { 1006*9167Ssam u.u_error = EISDIR; 1007*9167Ssam goto bad; 1008*9167Ssam } 1009*9167Ssam dirrewrite(dp, ip); 1010*9167Ssam if (u.u_error) 1011*9167Ssam goto bad1; 1012*9167Ssam /* 1013*9167Ssam * If this is a directory we know it is 1014*9167Ssam * empty and we can squash the inode and 1015*9167Ssam * any space associated with it. Otherwise, 1016*9167Ssam * we've got a plain file and the link count 1017*9167Ssam * simply needs to be adjusted. 1018*9167Ssam */ 1019*9167Ssam if (doingdirectory) { 1020*9167Ssam xp->i_nlink = 0; 1021*9167Ssam itrunc(xp, (u_long)0); 1022*9167Ssam } else 1023*9167Ssam xp->i_nlink--; 1024*9167Ssam xp->i_flag |= ICHG; 1025*9167Ssam iput(xp); 1026*9167Ssam } 1027*9167Ssam 1028*9167Ssam /* 1029*9167Ssam * 3) Unlink the source. 1030*9167Ssam */ 1031*9167Ssam u.u_dirp = uap->from; 1032*9167Ssam dp = namei(uchar, DELETE, 0); 1033*9167Ssam /* 1034*9167Ssam * Insure directory entry still exists and 1035*9167Ssam * has not changed since the start of all 1036*9167Ssam * this. If either has occured, forget about 1037*9167Ssam * about deleting the original entry and just 1038*9167Ssam * adjust the link count in the inode. 1039*9167Ssam */ 1040*9167Ssam if (dp == NULL || u.u_dent.d_ino != ip->i_number) { 1041*9167Ssam ip->i_nlink--; 1042*9167Ssam ip->i_flag |= ICHG; 1043*9167Ssam } else { 1044*9167Ssam /* 1045*9167Ssam * If source is a directory, must adjust 1046*9167Ssam * link count of parent directory also. 1047*9167Ssam * If target didn't exist and source and 1048*9167Ssam * target have the same parent, then we 1049*9167Ssam * needn't touch the link count, it all 1050*9167Ssam * balances out in the end. Otherwise, we 1051*9167Ssam * must do so to reflect deletion of ".." 1052*9167Ssam * done above. 1053*9167Ssam */ 1054*9167Ssam if (doingdirectory && (xp != NULL || parentdifferent)) { 1055*9167Ssam dp->i_nlink--; 1056*9167Ssam dp->i_flag |= ICHG; 1057*9167Ssam } 1058*9167Ssam if (dirremove()) { 1059*9167Ssam ip->i_nlink--; 1060*9167Ssam ip->i_flag |= ICHG; 1061*9167Ssam } 1062*9167Ssam } 1063*9167Ssam irele(ip); 1064*9167Ssam if (dp) 1065*9167Ssam iput(dp); 1066*9167Ssam 1067*9167Ssam /* 1068*9167Ssam * 4) Renaming a directory with the parent 1069*9167Ssam * different requires ".." to be rewritten. 1070*9167Ssam * The window is still there for ".." to 1071*9167Ssam * be inconsistent, but this is unavoidable, 1072*9167Ssam * and a lot shorter than when it was done 1073*9167Ssam * in a user process. 1074*9167Ssam */ 1075*9167Ssam if (doingdirectory && parentdifferent && u.u_error == 0) { 1076*9167Ssam struct dirtemplate dirbuf; 1077*9167Ssam 1078*9167Ssam u.u_dirp = uap->to; 1079*9167Ssam ip = namei(uchar, LOOKUP | LOCKPARENT, 0); 1080*9167Ssam if (ip == NULL) { 1081*9167Ssam printf("rename: .. went away\n"); 1082*9167Ssam return; 1083*9167Ssam } 1084*9167Ssam dp = u.u_pdir; 1085*9167Ssam if ((ip->i_mode&IFMT) != IFDIR) { 1086*9167Ssam printf("rename: .. not a directory\n"); 1087*9167Ssam goto stuck; 1088*9167Ssam } 1089*9167Ssam u.u_error = rdwri(UIO_READ, ip, (caddr_t)&dirbuf, 1090*9167Ssam sizeof (struct dirtemplate), (off_t)0, 1, (int *)0); 1091*9167Ssam if (u.u_error == 0) { 1092*9167Ssam dirbuf.dotdot_ino = dp->i_number; 1093*9167Ssam (void) rdwri(UIO_WRITE, ip, (caddr_t)&dirbuf, 1094*9167Ssam sizeof (struct dirtemplate), (off_t)0, 1, (int *)0); 1095*9167Ssam } 1096*9167Ssam stuck: 1097*9167Ssam irele(dp); 1098*9167Ssam iput(ip); 1099*9167Ssam } 1100*9167Ssam return; 1101*9167Ssam bad: 1102*9167Ssam iput(u.u_pdir); 1103*9167Ssam bad1: 1104*9167Ssam if (xp) 1105*9167Ssam irele(xp); 1106*9167Ssam out: 1107*9167Ssam ip->i_nlink--; 1108*9167Ssam ip->i_flag |= ICHG; 1109*9167Ssam irele(ip); 11107701Ssam } 11117701Ssam 11127535Sroot /* 11137535Sroot * Make a new file. 11147535Sroot */ 11157535Sroot struct inode * 11167535Sroot maknode(mode) 11177535Sroot int mode; 11187535Sroot { 11197535Sroot register struct inode *ip; 11207535Sroot ino_t ipref; 11217535Sroot 11227535Sroot if ((mode & IFMT) == IFDIR) 11237535Sroot ipref = dirpref(u.u_pdir->i_fs); 11247535Sroot else 11257535Sroot ipref = u.u_pdir->i_number; 11267535Sroot ip = ialloc(u.u_pdir, ipref, mode); 11277535Sroot if (ip == NULL) { 11287535Sroot iput(u.u_pdir); 11297701Ssam return (NULL); 11307535Sroot } 11317701Ssam #ifdef QUOTA 11327535Sroot if (ip->i_dquot != NODQUOT) 11337535Sroot panic("maknode: dquot"); 11347535Sroot #endif 11357535Sroot ip->i_flag |= IACC|IUPD|ICHG; 11367535Sroot if ((mode & IFMT) == 0) 11377535Sroot mode |= IFREG; 11387535Sroot ip->i_mode = mode & ~u.u_cmask; 11397535Sroot ip->i_nlink = 1; 11407535Sroot ip->i_uid = u.u_uid; 11417535Sroot ip->i_gid = u.u_pdir->i_gid; 11427701Ssam #ifdef QUOTA 11437535Sroot ip->i_dquot = inoquota(ip); 11447535Sroot #endif 11457535Sroot 11467535Sroot /* 11477535Sroot * Make sure inode goes to disk before directory entry. 11487535Sroot */ 11498673Sroot iupdat(ip, &time, &time, 1); 11507535Sroot direnter(ip); 11517535Sroot if (u.u_error) { 11527535Sroot /* 11537535Sroot * write error occurred trying to update directory 11547535Sroot * so must deallocate the inode 11557535Sroot */ 11567535Sroot ip->i_nlink = 0; 11577535Sroot ip->i_flag |= ICHG; 11587535Sroot iput(ip); 11597701Ssam return (NULL); 11607535Sroot } 11617701Ssam return (ip); 11627535Sroot } 1163