+/*
+ * make an entry in a directory
+ */
+makeentry(parent, ino, name)
+ ino_t parent, ino;
+ char *name;
+{
+ DINODE *dp;
+ struct inodesc idesc;
+
+ if (parent < ROOTINO || parent >= imax || ino < ROOTINO || ino >= imax)
+ return (0);
+ bzero(&idesc, sizeof(struct inodesc));
+ idesc.id_type = DATA;
+ idesc.id_func = mkentry;
+ idesc.id_number = parent;
+ idesc.id_parent = ino; /* this is the inode to enter */
+ idesc.id_fix = DONTKNOW;
+ idesc.id_name = name;
+ dp = ginode(parent);
+ if (dp->di_size % DIRBLKSIZ) {
+ dp->di_size = roundup(dp->di_size, DIRBLKSIZ);
+ inodirty();
+ }
+ if ((ckinode(dp, &idesc) & ALTERED) != 0)
+ return (1);
+ if (expanddir(dp) == 0)
+ return (0);
+ return (ckinode(dp, &idesc) & ALTERED);
+}
+
+/*
+ * Attempt to expand the size of a directory
+ */
+expanddir(dp)
+ register DINODE *dp;
+{
+ daddr_t lastbn, newblk;
+ char *cp, firstblk[DIRBLKSIZ];
+
+ lastbn = lblkno(&sblock, dp->di_size);
+ if (lastbn >= NDADDR - 1)
+ return (0);
+ if ((newblk = allocblk(sblock.fs_frag)) == 0)
+ return (0);
+ dp->di_db[lastbn + 1] = dp->di_db[lastbn];
+ dp->di_db[lastbn] = newblk;
+ dp->di_size += sblock.fs_bsize;
+ dp->di_blocks += btodb(sblock.fs_bsize);
+ getblk(&fileblk, dp->di_db[lastbn + 1],
+ dblksize(&sblock, dp, lastbn + 1));
+ if (fileblk.b_errs != NULL)
+ goto bad;
+ bcopy(dirblk.b_buf, firstblk, DIRBLKSIZ);
+ getblk(&fileblk, newblk, sblock.fs_bsize);
+ if (fileblk.b_errs != NULL)
+ goto bad;
+ bcopy(firstblk, dirblk.b_buf, DIRBLKSIZ);
+ for (cp = &dirblk.b_buf[DIRBLKSIZ];
+ cp < &dirblk.b_buf[sblock.fs_bsize];
+ cp += DIRBLKSIZ)
+ bcopy((char *)&emptydir, cp, sizeof emptydir);
+ dirty(&fileblk);
+ getblk(&fileblk, dp->di_db[lastbn + 1],
+ dblksize(&sblock, dp, lastbn + 1));
+ if (fileblk.b_errs != NULL)
+ goto bad;
+ bcopy((char *)&emptydir, dirblk.b_buf, sizeof emptydir);
+ pwarn("NO SPACE LEFT IN %s", pathname);
+ if (preen)
+ printf(" (EXPANDED)\n");
+ else if (reply("EXPAND") == 0)
+ goto bad;
+ dirty(&fileblk);
+ inodirty();
+ return (1);
+bad:
+ dp->di_db[lastbn] = dp->di_db[lastbn + 1];
+ dp->di_db[lastbn + 1] = 0;
+ dp->di_size -= sblock.fs_bsize;
+ dp->di_blocks -= btodb(sblock.fs_bsize);
+ freeblk(newblk, sblock.fs_frag);
+ return (0);
+}
+
+/*
+ * allocate a new directory
+ */
+allocdir(parent, request)
+ ino_t parent, request;
+{
+ ino_t ino;
+ char *cp;
+ DINODE *dp;
+
+ ino = allocino(request, IFDIR|0755);
+ dirhead.dot_ino = ino;
+ dirhead.dotdot_ino = parent;
+ dp = ginode(ino);
+ getblk(&fileblk, dp->di_db[0], sblock.fs_fsize);
+ if (fileblk.b_errs != NULL) {
+ freeino(ino);
+ return (0);
+ }
+ bcopy((char *)&dirhead, dirblk.b_buf, sizeof dirhead);
+ for (cp = &dirblk.b_buf[DIRBLKSIZ];
+ cp < &dirblk.b_buf[sblock.fs_fsize];
+ cp += DIRBLKSIZ)
+ bcopy((char *)&emptydir, cp, sizeof emptydir);
+ dirty(&fileblk);
+ dp->di_nlink = 2;
+ inodirty();
+ if (ino == ROOTINO) {
+ lncntp[ino] = dp->di_nlink;
+ return(ino);
+ }
+ if (statemap[parent] != DSTATE && statemap[parent] != DFOUND) {
+ freeino(ino);
+ return (0);
+ }
+ statemap[ino] = statemap[parent];
+ if (statemap[ino] == DSTATE) {
+ lncntp[ino] = dp->di_nlink;
+ lncntp[parent]++;
+ }
+ dp = ginode(parent);
+ dp->di_nlink++;
+ inodirty();
+ return (ino);
+}
+
+/*
+ * free a directory inode
+ */
+freedir(ino, parent)
+ ino_t ino, parent;
+{
+ DINODE *dp;
+
+ if (ino != parent) {
+ dp = ginode(parent);
+ dp->di_nlink--;
+ inodirty();
+ }
+ freeino(ino);
+}
+