+
+/*
+ * A virgin directory (no blushing please).
+ */
+struct dirtemplate mastertemplate = {
+ 0, 12, 1, ".",
+ 0, DIRBLKSIZ - 12, 2, ".."
+};
+
+/*
+ * Mkdir system call
+ */
+mkdir()
+{
+ struct a {
+ char *name;
+ int dmode;
+ } *uap;
+ register struct inode *ip, *dp;
+ struct dirtemplate dirtemplate;
+
+ uap = (struct a *)u.u_ap;
+ ip = namei(uchar, CREATE, 0);
+ if (u.u_error)
+ return;
+ if (ip != NULL) {
+ iput(ip);
+ u.u_error = EEXIST;
+ return;
+ }
+ dp = u.u_pdir;
+ uap->dmode &= 0777;
+ uap->dmode |= IFDIR;
+ /*
+ * Must simulate part of maknode here
+ * in order to acquire the inode, but
+ * not have it entered in the parent
+ * directory. The entry is made later
+ * after writing "." and ".." entries out.
+ */
+ ip = ialloc(dp, dirpref(dp->i_fs), uap->dmode);
+ if (ip == NULL) {
+ iput(dp);
+ return;
+ }
+#ifdef QUOTA
+ if (ip->i_dquot != NODQUOT)
+ panic("mkdir: dquot");
+#endif
+ ip->i_flag |= IACC|IUPD|ICHG;
+ ip->i_mode = uap->dmode & ~u.u_cmask;
+ ip->i_nlink = 2;
+ ip->i_uid = u.u_uid;
+ ip->i_gid = dp->i_gid;
+#ifdef QUOTA
+ ip->i_dquot = inoquota(ip);
+#endif
+ iupdat(ip, &time, &time, 1);
+
+ /*
+ * Bump link count in parent directory
+ * to reflect work done below. Should
+ * be done before reference is created
+ * so reparation is possible if we crash.
+ */
+ dp->i_nlink++;
+ dp->i_flag |= ICHG;
+ iupdat(dp, &time, &time, 1);
+
+ /*
+ * Initialize directory with "."
+ * and ".." from static template.
+ */
+ dirtemplate = mastertemplate;
+ dirtemplate.dot_ino = ip->i_number;
+ dirtemplate.dotdot_ino = dp->i_number;
+ u.u_error = rdwri(UIO_WRITE, ip, (caddr_t)&dirtemplate,
+ sizeof (dirtemplate), (off_t)0, 1, (int *)0);
+ if (u.u_error) {
+ dp->i_nlink--;
+ dp->i_flag |= ICHG;
+ goto bad;
+ }
+ /*
+ * Directory all set up, now
+ * install the entry for it in
+ * the parent directory.
+ */
+ u.u_error = direnter(ip);
+ dp = NULL;
+ if (u.u_error) {
+ u.u_dirp = uap->name;
+ dp = namei(uchar, LOOKUP | NOCACHE, 0);
+ if (dp) {
+ dp->i_nlink--;
+ dp->i_flag |= ICHG;
+ }
+ }
+bad:
+ /*
+ * No need to do an explicit itrunc here,
+ * irele will do this for us because we set
+ * the link count to 0.
+ */
+ if (u.u_error) {
+ ip->i_nlink = 0;
+ ip->i_flag |= ICHG;
+ }
+ if (dp)
+ iput(dp);
+ iput(ip);
+}
+
+/*
+ * Rmdir system call.
+ */
+rmdir()
+{
+ struct a {
+ char *name;
+ };
+ register struct inode *ip, *dp;
+
+ ip = namei(uchar, DELETE | LOCKPARENT, 0);
+ if (ip == NULL)
+ return;
+ dp = u.u_pdir;
+ /*
+ * No rmdir "." please.
+ */
+ if (dp == ip) {
+ irele(dp);
+ iput(ip);
+ u.u_error = EINVAL;
+ return;
+ }
+ if ((ip->i_mode&IFMT) != IFDIR) {
+ u.u_error = ENOTDIR;
+ goto out;
+ }
+ /*
+ * Don't remove a mounted on directory.
+ */
+ if (ip->i_dev != dp->i_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.)
+ */
+ if (ip->i_nlink != 2 || !dirempty(ip)) {
+ u.u_error = ENOTEMPTY;
+ goto out;
+ }
+ /*
+ * Delete reference to directory before purging
+ * inode. If we crash in between, the directory
+ * will be reattached to lost+found,
+ */
+ if (dirremove() == 0)
+ goto out;
+ dp->i_nlink--;
+ dp->i_flag |= ICHG;
+ iput(dp);
+ dp = NULL;
+ /*
+ * Truncate inode. The only stuff left
+ * in the directory is "." and "..". The
+ * "." reference is inconsequential since
+ * we're quashing it. The ".." reference
+ * has already been adjusted above. We've
+ * removed the "." reference and the reference
+ * in the parent directory, but there may be
+ * other hard links so decrement by 2 and
+ * worry about them later.
+ */
+ ip->i_nlink -= 2;
+ itrunc(ip, (u_long)0);
+out:
+ if (dp)
+ iput(dp);
+ iput(ip);
+}
+
+struct file *
+getinode(fdes)
+ int fdes;
+{
+ struct file *fp;
+
+ if ((unsigned)fdes >= NOFILE || (fp = u.u_ofile[fdes]) == NULL) {
+ u.u_error = EBADF;
+ return ((struct file *)0);
+ }
+ if (fp->f_type != DTYPE_INODE) {
+ u.u_error = EINVAL;
+ return ((struct file *)0);
+ }
+ return (fp);
+}
+
+/*
+ * mode mask for creation of files
+ */
+umask()
+{
+ register struct a {
+ int mask;
+ } *uap;
+
+ uap = (struct a *)u.u_ap;
+ u.u_r.r_val1 = u.u_cmask;
+ u.u_cmask = uap->mask & 07777;
+}