📄 ufs_syscalls.c
字号:
(target_gp->g_flag>EXT)) { xrele(target_gp); if (target_gp->g_flag>EXT) { error = ETXTBSY; goto bad; } } /* * Target must be empty if a directory * and have no links to it. * Also, insure source and target are * compatible (both directories, or both * not directories). */ if ((target_gp->g_mode&GFMT) == GFDIR) { if (!dirempty(target_gp, dp->g_number) || target_gp->g_nlink > 2) { error = ENOTEMPTY; goto bad; } if (!doingdirectory) { error = EISDIR; goto bad; } cacheinval(dp); } else if (doingdirectory) { error = ENOTDIR; goto bad; } /* * If we are renaming directories and we will be * rewriting the source starting directory, fail * the operation because we will need the source * starting directory in tact to remove the source_gp. */ if (doingdirectory && target_gp == ssd) { u.u_error = EINVAL; goto bad; } dirrewrite(dp, gp, target_ndp); if (u.u_error) { error = u.u_error; goto bad1; } /* * Adjust the link count of the target to * reflect the dirrewrite above. If this is * a directory it is empty and there are * no links to it, so we can squash the gnode and * any space associated with it. We disallowed * renaming over top of a directory with links to * it above, as the remaining link would point to * a directory without "." or ".." entries. */ target_gp->g_nlink--; if (doingdirectory) { if (--target_gp->g_nlink != 0) panic("rename: linked directory"); ufs_gtrunc(target_gp, (u_long)0, (struct ucred *) 0); /* * We must decrement the link count of the * parent directory here, if we are unlinking * the target within the same directory as the * source. */ if (!newparent) { dp->g_nlink--; dp->g_flag |= GCHG; } } target_gp->g_flag |= GCHG; gput(target_gp); target_gp = NULL; } /* * 3) Unlink the source. */ source_ndp->ni_nameiop = DELETE | LOCKPARENT; u.u_cdir = ssd; target_gp = GNAMEI(source_ndp); if (target_gp != NULL) { dp = source_ndp->ni_pdir; } else { dp = NULL; } /* * Insure that the directory entry still exists and has not * changed while the new name has been entered. If the source is * a file then the entry may have been unlinked or renamed. In * either case there is no further work to be done. If the source * is a directory then it cannot have been rmdir'ed; its link * count of three would cause a rmdir to fail with ENOTEMPTY. * The GRENAME flag insures that it cannot be moved by another * rename. */ if (target_gp != gp) { if (doingdirectory) panic("rename: lost dir entry"); } else { /* * If the source is a directory with a * new parent, the link count of the old * parent directory must be decremented * and ".." set to point to the new parent. */ if (doingdirectory && newparent) { dp->g_nlink--; dp->g_flag |= GCHG; error = rdwri(UIO_READ, target_gp, (caddr_t)&dirbuf, sizeof (struct dirtemplate), (off_t)0, 1, (int *)0); if (error == 0) { if (dirbuf.dotdot_namlen != 2 || dirbuf.dotdot_name[0] != '.' || dirbuf.dotdot_name[1] != '.') { printf("rename: mangled dir\n"); } else { dirbuf.dotdot_ino = newparent; (void) rdwri(UIO_WRITE, target_gp, (caddr_t)&dirbuf, sizeof (struct dirtemplate), (off_t)0, 1, (int *)0); cacheinval(dp); } } } if (dirremove(source_ndp)) { target_gp->g_nlink--; target_gp->g_flag |= GCHG; } target_gp->g_flag &= ~GRENAME; if (error == 0) /* conservative */ error = u.u_error; } if (dp) gput(dp); if (target_gp) gput(target_gp); grele(gp); if (error) u.u_error = error; return;bad: gput(dp);bad1: if (target_gp) gput(target_gp);out: gfs_lock(gp); gp->g_nlink--; gp->g_flag |= GCHG; gput(gp); if (error) u.u_error = error;}/* * Make a new file. */extern struct gnode_ops *ufs_gnode_ops;struct gnode *ufs_maknode(mode, dev, ndp) register int mode; register dev_t dev; register struct nameidata *ndp;{ register struct gnode *gp; register struct gnode *pdir = ndp->ni_pdir; register gno_t gpref; int type;#ifdef GFSDEBUG if(GFS[17]) cprintf("ufs_maknod: ndp 0x%x, ni_pdir 0x%x\n", ndp, ndp->ni_pdir);#endif if ((mode & GFMT) == GFDIR) gpref = dirpref(FS(pdir)); else gpref = pdir->g_number; gp = ufs_galloc(pdir, gpref, mode); if (gp == NULL) { gput(pdir); return (NULL); }#ifdef QUOTA if (gp->g_dquot != NODQUOT) panic("maknode: dquot");#endif gp->g_flag |= GACC|GUPD|GCHG; gp->g_mode = mode & ~u.u_cmask; gp->g_nlink = 1; gp->g_uid = u.u_uid; gp->g_gid = pdir->g_gid; gp->g_rdev = dev; gp->g_ops = ufs_gnode_ops; type = gp->g_mode & GFMT; if ((type == GFCHR) || (type == GFBLK) || (type == GFPORT)) { specvp(gp); } if (gp->g_mode & GSGID && !groupmember(gp->g_gid)) gp->g_mode &= ~GSGID;#ifdef QUOTA gp->g_dquot = inoquota(gp);#endif /* * Make sure gnode goes to disk before directory entry. */ ufs_gupdat(gp, timepick, timepick, 1, (struct ucred *) 0); u.u_error = direnter(gp, ndp); if (u.u_error) { /* * Write error occurred trying to update directory * so must deallocate the gnode. */ gp->g_nlink = 0; gp->g_flag |= GCHG; gput(gp); return (NULL); } if ((gp->g_mode & GFMT) == GFPORT) gp->g_fifo = 0; return (gp);}/* * A virgin directory (no blushing please). */struct dirtemplate mastertemplate = { 0, 12, 1, ".", 0, DIRBLKSIZ - 12, 2, ".."};struct gnode *ufs_mkdir(dp, name, mode) register struct gnode *dp; register int mode; register char *name;{ register struct nameidata *ndp = &u.u_nd; register struct gnode *gp; struct dirtemplate dirtemplate; if (dp->g_nlink >= LINK_MAX) { gput(dp); u.u_error = EMLINK; return(NULL); } mode &= 0777; mode |= GFDIR; /* * Must simulate part of maknode here * in order to acquire the gnode, but * not have it entered in the parent * directory. The entry is made later * after writing "." and ".." entries out. */ gp = ufs_galloc(dp, dirpref(FS(dp)), mode); if (gp == NULL) { gput(dp); return(NULL); }#ifdef QUOTA if (gp->g_dquot != NODQUOT) panic("mkdir: dquot");#endif gp->g_flag |= GACC|GUPD|GCHG; gp->g_mode = mode & ~u.u_cmask; gp->g_nlink = 2; gp->g_uid = u.u_uid; gp->g_gid = dp->g_gid; gp->g_ops = ufs_gnode_ops;#ifdef QUOTA gp->g_dquot = inoquota(gp);#endif ufs_gupdat(gp, timepick, timepick, 1, (struct ucred *) 0); /* * Bump link count in parent directory * to reflect work done below. Should * be done before reference is created * so reparation is possible if we crash. */ gassert(dp); dp->g_nlink++; dp->g_flag |= GCHG; ufs_gupdat(dp, timepick, timepick, 1, (struct ucred *) 0); /* * Initialize directory with "." * and ".." from static template. */ dirtemplate = mastertemplate; dirtemplate.dot_ino = gp->g_number; dirtemplate.dotdot_ino = dp->g_number; u.u_error = rdwri(UIO_WRITE, gp, (caddr_t)&dirtemplate, sizeof (dirtemplate), (off_t)0, 1, (int *)0); if (u.u_error) { dp->g_nlink--; dp->g_flag |= GCHG; gp->g_nlink = 0; gp->g_flag |= GCHG; gput(dp); gput(gp); /* * No need to do an explicit itrunc here, * grele will do this for us because we set * the link count to 0. */ return(NULL); } if (DIRBLKSIZ > FS(gp)->fs_fsize) panic("mkdir: blksize"); /* XXX - should grow with bmap() */ else gp->g_size = DIRBLKSIZ; /* * Ref the parent directory , in case * we have to decrement link count * because direnter failure. */ gref(dp); /* * Directory all set up, now * install the entry for it in * the parent directory. */ u.u_error = direnter(gp, ndp); if (u.u_error) { /* * Remove link from parent dir. * We refed the directory, to * ensure it would not go away. */ gfs_lock(dp); dp->g_nlink--; dp->g_flag |= GCHG; gput(dp);#ifdef notdef /* * A comedy of errors...... * The following uncompiled code is completely * bogus. Since we were not rewriting, the * entry cannot exist in the cache. * Why bother doing a namei ? Besides, this code * does nothing about the parent dir, it decrements * the targer dir link count. - prs */ ndp->ni_nameiop = LOOKUP | NOCACHE; ndp->ni_dirp = name; /* * XXX - GNAMEI insists u.u_error be zero. * If not, it returnes root dp. Ouch ! */ dp = GNAMEI(ndp); if (dp) { dp->g_nlink--; dp->g_flag |= GCHG; gput(dp); }#endif /* * Destroy target directory (that * was not entered in parent) */ gp->g_nlink = 0; gp->g_flag |= GCHG; gput(gp); return(NULL); } grele(dp); ufs_gunlock(gp); return(gp);}ufs_rmdir(gp, ndp) register struct gnode *gp; register struct nameidata *ndp;{ register struct gnode *dp; dp = ndp->ni_pdir; gassert(dp); /* * No rmdir "." please. */ if (dp == gp) { grele(dp); gput(gp); u.u_error = EINVAL; return; } /* * Don't remove a mounted on directory. */ if (gp->g_dev != dp->g_dev) { u.u_error = EBUSY; goto out; } /* * Verify the directory is empty (and valid). * (Rmdir ".." won't be valid since * ".." will contain a reference to * the current directory and thus be * non-empty.) */#ifdef GFSDEBUG if(GFS[13]) cprintf("ufs_rmdir: gp 0x%x (%d) links %d size %d\n", gp, gp->g_number, gp->g_nlink, gp->g_size);#endif if (gp->g_nlink != 2 || !dirempty(gp, dp->g_number)) { u.u_error = ENOTEMPTY; goto out; } /* * Delete reference to directory before purging * gnode. If we crash in between, the directory * will be reattached to lost+found, */ if (dirremove(ndp) == 0) goto out; dp->g_nlink--; dp->g_flag |= GCHG; cacheinval(dp); gput(dp); dp = NULL; /* * Truncate gnode. The only stuff left * in the directory is "." and "..". The * "." reference is inconsequential since * we're quashing it. The ".." reference * has already been adjusted above. We've * removed the "." reference and the reference * in the parent directory, but there may be * other hard links so decrement by 2 and * worry about them later. */ gp->g_nlink -= 2; ufs_gtrunc(gp, (u_long)0, (struct ucred *) 0); cacheinval(gp);out: if (dp) gput(dp); gput(gp);}ufs_seek(gp, where) struct gnode *gp; int where;{ /* * this is a dummy routine because gfs semantics tell us that * if an operation is not supported, there is no function * in the mount ops. */ return(0);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -