1*81fb472fSbeck /* $OpenBSD: dir.c,v 1.35 2024/02/03 18:51:57 beck Exp $ */
287304b87Stholo /* $NetBSD: dir.c,v 1.20 1996/09/27 22:45:11 christos Exp $ */
3df930be7Sderaadt
4df930be7Sderaadt /*
5df930be7Sderaadt * Copyright (c) 1980, 1986, 1993
6df930be7Sderaadt * The Regents of the University of California. All rights reserved.
7df930be7Sderaadt *
8df930be7Sderaadt * Redistribution and use in source and binary forms, with or without
9df930be7Sderaadt * modification, are permitted provided that the following conditions
10df930be7Sderaadt * are met:
11df930be7Sderaadt * 1. Redistributions of source code must retain the above copyright
12df930be7Sderaadt * notice, this list of conditions and the following disclaimer.
13df930be7Sderaadt * 2. Redistributions in binary form must reproduce the above copyright
14df930be7Sderaadt * notice, this list of conditions and the following disclaimer in the
15df930be7Sderaadt * documentation and/or other materials provided with the distribution.
161ef0d710Smillert * 3. Neither the name of the University nor the names of its contributors
17df930be7Sderaadt * may be used to endorse or promote products derived from this software
18df930be7Sderaadt * without specific prior written permission.
19df930be7Sderaadt *
20df930be7Sderaadt * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21df930be7Sderaadt * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22df930be7Sderaadt * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23df930be7Sderaadt * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24df930be7Sderaadt * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25df930be7Sderaadt * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26df930be7Sderaadt * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27df930be7Sderaadt * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28df930be7Sderaadt * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29df930be7Sderaadt * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30df930be7Sderaadt * SUCH DAMAGE.
31df930be7Sderaadt */
32df930be7Sderaadt
3378eb0b7eSderaadt #include <sys/param.h> /* DEV_BSIZE roundup btodb */
34df930be7Sderaadt #include <sys/time.h>
35df930be7Sderaadt #include <ufs/ufs/dinode.h>
36df930be7Sderaadt #include <ufs/ufs/dir.h>
37df930be7Sderaadt #include <ufs/ffs/fs.h>
38df930be7Sderaadt
39df930be7Sderaadt #include <stdio.h>
40df930be7Sderaadt #include <stdlib.h>
41df930be7Sderaadt #include <string.h>
42b9fc9a72Sderaadt #include <limits.h>
43df930be7Sderaadt
44df930be7Sderaadt #include "fsck.h"
4587304b87Stholo #include "fsutil.h"
46df930be7Sderaadt #include "extern.h"
47df930be7Sderaadt
48df930be7Sderaadt char *lfname = "lost+found";
4948a4dc1aSkstailey int lfmode = 01700;
50df930be7Sderaadt struct dirtemplate emptydir = { 0, DIRBLKSIZ };
51df930be7Sderaadt struct dirtemplate dirhead = {
52df930be7Sderaadt 0, 12, DT_DIR, 1, ".",
53df930be7Sderaadt 0, DIRBLKSIZ - 12, DT_DIR, 2, ".."
54df930be7Sderaadt };
55df930be7Sderaadt
562fffe0e0Smillert static int expanddir(union dinode *, char *);
57c72b5b24Smillert static void freedir(ino_t, ino_t);
58c72b5b24Smillert static struct direct *fsck_readdir(struct inodesc *);
591abdbfdeSderaadt static struct bufarea *getdirblk(daddr_t, long);
60c72b5b24Smillert static int lftempname(char *, ino_t);
61c72b5b24Smillert static int mkentry(struct inodesc *);
62c72b5b24Smillert static int chgino(struct inodesc *);
63df930be7Sderaadt
64df930be7Sderaadt /*
65df930be7Sderaadt * Propagate connected state through the tree.
66df930be7Sderaadt */
67df930be7Sderaadt void
propagate(ino_t inumber)6860d6b16fSgluk propagate(ino_t inumber)
69df930be7Sderaadt {
701fb4224cSgluk struct inoinfo *inp;
711fb4224cSgluk char state;
72df930be7Sderaadt
731fb4224cSgluk inp = getinoinfo(inumber);
744aab0ea5Sotto state = GET_ISTATE(inp->i_number);
751fb4224cSgluk for (;;) {
764aab0ea5Sotto SET_ISTATE(inp->i_number, state);
7787304b87Stholo if (inp->i_child &&
784aab0ea5Sotto GET_ISTATE(inp->i_child->i_number) != state)
7987304b87Stholo inp = inp->i_child;
801fb4224cSgluk else if (inp->i_number == inumber)
811fb4224cSgluk break;
8287304b87Stholo else if (inp->i_sibling)
8387304b87Stholo inp = inp->i_sibling;
8487304b87Stholo else
85838c4739Sotto inp = getinoinfo(inp->i_parent);
86df930be7Sderaadt }
87df930be7Sderaadt }
88df930be7Sderaadt
89df930be7Sderaadt /*
90df930be7Sderaadt * Scan each entry in a directory block.
91df930be7Sderaadt */
92df930be7Sderaadt int
dirscan(struct inodesc * idesc)9360d6b16fSgluk dirscan(struct inodesc *idesc)
94df930be7Sderaadt {
95e073c79dSmpech struct direct *dp;
96e073c79dSmpech struct bufarea *bp;
97df930be7Sderaadt int dsize, n;
98df930be7Sderaadt long blksiz;
99df930be7Sderaadt char dbuf[DIRBLKSIZ];
100df930be7Sderaadt
101df930be7Sderaadt if (idesc->id_type != DATA)
102df930be7Sderaadt errexit("wrong type to dirscan %d\n", idesc->id_type);
103df930be7Sderaadt if (idesc->id_entryno == 0 &&
104df930be7Sderaadt (idesc->id_filesize & (DIRBLKSIZ - 1)) != 0)
105df930be7Sderaadt idesc->id_filesize = roundup(idesc->id_filesize, DIRBLKSIZ);
106df930be7Sderaadt blksiz = idesc->id_numfrags * sblock.fs_fsize;
107df930be7Sderaadt if (chkrange(idesc->id_blkno, idesc->id_numfrags)) {
108df930be7Sderaadt idesc->id_filesize -= blksiz;
109df930be7Sderaadt return (SKIP);
110df930be7Sderaadt }
111df930be7Sderaadt idesc->id_loc = 0;
112df930be7Sderaadt for (dp = fsck_readdir(idesc); dp != NULL; dp = fsck_readdir(idesc)) {
113df930be7Sderaadt dsize = dp->d_reclen;
114df930be7Sderaadt memcpy(dbuf, dp, (size_t)dsize);
115df930be7Sderaadt idesc->id_dirp = (struct direct *)dbuf;
116df930be7Sderaadt if ((n = (*idesc->id_func)(idesc)) & ALTERED) {
117df930be7Sderaadt bp = getdirblk(idesc->id_blkno, blksiz);
118df930be7Sderaadt memcpy(bp->b_un.b_buf + idesc->id_loc - dsize, dbuf,
119df930be7Sderaadt (size_t)dsize);
120df930be7Sderaadt dirty(bp);
121df930be7Sderaadt sbdirty();
122df930be7Sderaadt }
123df930be7Sderaadt if (n & STOP)
124df930be7Sderaadt return (n);
125df930be7Sderaadt }
126df930be7Sderaadt return (idesc->id_filesize > 0 ? KEEPON : STOP);
127df930be7Sderaadt }
128df930be7Sderaadt
129df930be7Sderaadt /*
130df930be7Sderaadt * get next entry in a directory.
131df930be7Sderaadt */
13287304b87Stholo static struct direct *
fsck_readdir(struct inodesc * idesc)13360d6b16fSgluk fsck_readdir(struct inodesc *idesc)
134df930be7Sderaadt {
135e073c79dSmpech struct direct *dp, *ndp;
136e073c79dSmpech struct bufarea *bp;
137df930be7Sderaadt long size, blksiz, fix, dploc;
138df930be7Sderaadt
139df930be7Sderaadt blksiz = idesc->id_numfrags * sblock.fs_fsize;
140df930be7Sderaadt bp = getdirblk(idesc->id_blkno, blksiz);
141df930be7Sderaadt if (idesc->id_loc % DIRBLKSIZ == 0 && idesc->id_filesize > 0 &&
142df930be7Sderaadt idesc->id_loc < blksiz) {
143df930be7Sderaadt dp = (struct direct *)(bp->b_un.b_buf + idesc->id_loc);
144df930be7Sderaadt if (dircheck(idesc, dp))
145df930be7Sderaadt goto dpok;
146df930be7Sderaadt if (idesc->id_fix == IGNORE)
147df930be7Sderaadt return (0);
148df930be7Sderaadt fix = dofix(idesc, "DIRECTORY CORRUPTED");
149df930be7Sderaadt bp = getdirblk(idesc->id_blkno, blksiz);
150df930be7Sderaadt dp = (struct direct *)(bp->b_un.b_buf + idesc->id_loc);
151df930be7Sderaadt dp->d_reclen = DIRBLKSIZ;
152df930be7Sderaadt dp->d_ino = 0;
153df930be7Sderaadt dp->d_type = 0;
154df930be7Sderaadt dp->d_namlen = 0;
155df930be7Sderaadt dp->d_name[0] = '\0';
156df930be7Sderaadt if (fix)
157df930be7Sderaadt dirty(bp);
158df930be7Sderaadt idesc->id_loc += DIRBLKSIZ;
159df930be7Sderaadt idesc->id_filesize -= DIRBLKSIZ;
160df930be7Sderaadt return (dp);
161df930be7Sderaadt }
162df930be7Sderaadt dpok:
163df930be7Sderaadt if (idesc->id_filesize <= 0 || idesc->id_loc >= blksiz)
164df930be7Sderaadt return NULL;
165df930be7Sderaadt dploc = idesc->id_loc;
166df930be7Sderaadt dp = (struct direct *)(bp->b_un.b_buf + dploc);
167df930be7Sderaadt idesc->id_loc += dp->d_reclen;
168df930be7Sderaadt idesc->id_filesize -= dp->d_reclen;
169df930be7Sderaadt if ((idesc->id_loc % DIRBLKSIZ) == 0)
170df930be7Sderaadt return (dp);
171df930be7Sderaadt ndp = (struct direct *)(bp->b_un.b_buf + idesc->id_loc);
172df930be7Sderaadt if (idesc->id_loc < blksiz && idesc->id_filesize > 0 &&
173df930be7Sderaadt dircheck(idesc, ndp) == 0) {
174df930be7Sderaadt size = DIRBLKSIZ - (idesc->id_loc % DIRBLKSIZ);
175df930be7Sderaadt idesc->id_loc += size;
176df930be7Sderaadt idesc->id_filesize -= size;
177df930be7Sderaadt if (idesc->id_fix == IGNORE)
178df930be7Sderaadt return (0);
179df930be7Sderaadt fix = dofix(idesc, "DIRECTORY CORRUPTED");
180df930be7Sderaadt bp = getdirblk(idesc->id_blkno, blksiz);
181df930be7Sderaadt dp = (struct direct *)(bp->b_un.b_buf + dploc);
182df930be7Sderaadt dp->d_reclen += size;
183df930be7Sderaadt if (fix)
184df930be7Sderaadt dirty(bp);
185df930be7Sderaadt }
186df930be7Sderaadt return (dp);
187df930be7Sderaadt }
188df930be7Sderaadt
189df930be7Sderaadt /*
190df930be7Sderaadt * Verify that a directory entry is valid.
191df930be7Sderaadt * This is a superset of the checks made in the kernel.
192df930be7Sderaadt */
193df930be7Sderaadt int
dircheck(struct inodesc * idesc,struct direct * dp)19460d6b16fSgluk dircheck(struct inodesc *idesc, struct direct *dp)
195df930be7Sderaadt {
196e073c79dSmpech int size;
197e073c79dSmpech char *cp;
198df930be7Sderaadt u_char namlen, type;
199df930be7Sderaadt int spaceleft;
200df930be7Sderaadt
201df930be7Sderaadt spaceleft = DIRBLKSIZ - (idesc->id_loc % DIRBLKSIZ);
202df930be7Sderaadt if (dp->d_ino >= maxino ||
203df930be7Sderaadt dp->d_reclen == 0 ||
204df930be7Sderaadt dp->d_reclen > spaceleft ||
205df930be7Sderaadt (dp->d_reclen & 0x3) != 0)
206df930be7Sderaadt return (0);
207df930be7Sderaadt if (dp->d_ino == 0)
208df930be7Sderaadt return (1);
209da5362d5Sguenther size = DIRSIZ(dp);
210df930be7Sderaadt namlen = dp->d_namlen;
211df930be7Sderaadt type = dp->d_type;
212df930be7Sderaadt if (dp->d_reclen < size ||
213df930be7Sderaadt idesc->id_filesize < size ||
214df930be7Sderaadt type > 15)
215df930be7Sderaadt return (0);
216df930be7Sderaadt for (cp = dp->d_name, size = 0; size < namlen; size++)
217df930be7Sderaadt if (*cp == '\0' || (*cp++ == '/'))
218df930be7Sderaadt return (0);
219df930be7Sderaadt if (*cp != '\0')
220df930be7Sderaadt return (0);
221df930be7Sderaadt return (1);
222df930be7Sderaadt }
223df930be7Sderaadt
224df930be7Sderaadt void
direrror(ino_t ino,char * errmesg)22560d6b16fSgluk direrror(ino_t ino, char *errmesg)
226df930be7Sderaadt {
227df930be7Sderaadt fileerror(ino, ino, errmesg);
228df930be7Sderaadt }
229df930be7Sderaadt
230df930be7Sderaadt void
fileerror(ino_t cwd,ino_t ino,char * errmesg)23160d6b16fSgluk fileerror(ino_t cwd, ino_t ino, char *errmesg)
232df930be7Sderaadt {
2332fffe0e0Smillert union dinode *dp;
234b9fc9a72Sderaadt char pathbuf[PATH_MAX + 1];
235df930be7Sderaadt
236df930be7Sderaadt pwarn("%s ", errmesg);
237df930be7Sderaadt pinode(ino);
238df930be7Sderaadt printf("\n");
23959b30be9Sderaadt getpathname(pathbuf, sizeof pathbuf, cwd, ino);
240df930be7Sderaadt if (ino < ROOTINO || ino > maxino) {
241df930be7Sderaadt pfatal("NAME=%s\n", pathbuf);
242df930be7Sderaadt return;
243df930be7Sderaadt }
244df930be7Sderaadt dp = ginode(ino);
245df930be7Sderaadt if (ftypeok(dp))
246df930be7Sderaadt pfatal("%s=%s\n",
2472fffe0e0Smillert (DIP(dp, di_mode) & IFMT) == IFDIR ? "DIR" : "FILE",
2482fffe0e0Smillert pathbuf);
249df930be7Sderaadt else
250df930be7Sderaadt pfatal("NAME=%s\n", pathbuf);
251df930be7Sderaadt }
252df930be7Sderaadt
253df930be7Sderaadt void
adjust(struct inodesc * idesc,short lcnt)25460d6b16fSgluk adjust(struct inodesc *idesc, short lcnt)
255df930be7Sderaadt {
2562fffe0e0Smillert union dinode *dp;
257df930be7Sderaadt
258df930be7Sderaadt dp = ginode(idesc->id_number);
2592fffe0e0Smillert if (DIP(dp, di_nlink) == lcnt) {
26060d6b16fSgluk if (linkup(idesc->id_number, 0) == 0)
261df930be7Sderaadt clri(idesc, "UNREF", 0);
262df930be7Sderaadt } else {
263df930be7Sderaadt pwarn("LINK COUNT %s", (lfdir == idesc->id_number) ? lfname :
2642fffe0e0Smillert ((DIP(dp, di_mode) & IFMT) == IFDIR ? "DIR" : "FILE"));
265df930be7Sderaadt pinode(idesc->id_number);
2662fffe0e0Smillert printf(" COUNT %d SHOULD BE %d", DIP(dp, di_nlink),
2672fffe0e0Smillert DIP(dp, di_nlink) - lcnt);
268*81fb472fSbeck if (preen) {
269df930be7Sderaadt if (lcnt < 0) {
270df930be7Sderaadt printf("\n");
271df930be7Sderaadt pfatal("LINK COUNT INCREASING");
272df930be7Sderaadt }
273767b3369Sart if (preen)
274df930be7Sderaadt printf(" (ADJUSTED)\n");
275df930be7Sderaadt }
276df930be7Sderaadt if (preen || reply("ADJUST") == 1) {
2772c15fd06Sotto DIP_SET(dp, di_nlink, DIP(dp, di_nlink) - lcnt);
278df930be7Sderaadt inodirty();
279df930be7Sderaadt }
280df930be7Sderaadt }
281df930be7Sderaadt }
282df930be7Sderaadt
28387304b87Stholo static int
mkentry(struct inodesc * idesc)28460d6b16fSgluk mkentry(struct inodesc *idesc)
285df930be7Sderaadt {
286e073c79dSmpech struct direct *dirp = idesc->id_dirp;
287df930be7Sderaadt struct direct newent;
288df930be7Sderaadt int newlen, oldlen;
289df930be7Sderaadt
290df930be7Sderaadt newent.d_namlen = strlen(idesc->id_name);
291da5362d5Sguenther newlen = DIRSIZ(&newent);
292df930be7Sderaadt if (dirp->d_ino != 0)
293da5362d5Sguenther oldlen = DIRSIZ(dirp);
294df930be7Sderaadt else
295df930be7Sderaadt oldlen = 0;
296df930be7Sderaadt if (dirp->d_reclen - oldlen < newlen)
297df930be7Sderaadt return (KEEPON);
298df930be7Sderaadt newent.d_reclen = dirp->d_reclen - oldlen;
299df930be7Sderaadt dirp->d_reclen = oldlen;
300df930be7Sderaadt dirp = (struct direct *)(((char *)dirp) + oldlen);
301df930be7Sderaadt dirp->d_ino = idesc->id_parent; /* ino to be entered is in id_parent */
302df930be7Sderaadt dirp->d_reclen = newent.d_reclen;
3034aab0ea5Sotto dirp->d_type = GET_ITYPE(idesc->id_parent);
304df930be7Sderaadt dirp->d_namlen = newent.d_namlen;
305df930be7Sderaadt memcpy(dirp->d_name, idesc->id_name, (size_t)dirp->d_namlen + 1);
306df930be7Sderaadt return (ALTERED|STOP);
307df930be7Sderaadt }
308df930be7Sderaadt
30987304b87Stholo static int
chgino(struct inodesc * idesc)31060d6b16fSgluk chgino(struct inodesc *idesc)
311df930be7Sderaadt {
312e073c79dSmpech struct direct *dirp = idesc->id_dirp;
313df930be7Sderaadt
314df930be7Sderaadt if (memcmp(dirp->d_name, idesc->id_name, (int)dirp->d_namlen + 1))
315df930be7Sderaadt return (KEEPON);
316df930be7Sderaadt dirp->d_ino = idesc->id_parent;
3174aab0ea5Sotto dirp->d_type = GET_ITYPE(idesc->id_parent);
318df930be7Sderaadt return (ALTERED|STOP);
319df930be7Sderaadt }
320df930be7Sderaadt
321df930be7Sderaadt int
linkup(ino_t orphan,ino_t parentdir)32260d6b16fSgluk linkup(ino_t orphan, ino_t parentdir)
323df930be7Sderaadt {
3242fffe0e0Smillert union dinode *dp;
325df930be7Sderaadt int lostdir;
326df930be7Sderaadt ino_t oldlfdir;
327df930be7Sderaadt struct inodesc idesc;
328df930be7Sderaadt char tempname[BUFSIZ];
329df930be7Sderaadt
330df930be7Sderaadt memset(&idesc, 0, sizeof(struct inodesc));
331df930be7Sderaadt dp = ginode(orphan);
3322fffe0e0Smillert lostdir = (DIP(dp, di_mode) & IFMT) == IFDIR;
333df930be7Sderaadt pwarn("UNREF %s ", lostdir ? "DIR" : "FILE");
334df930be7Sderaadt pinode(orphan);
335*81fb472fSbeck if (preen && DIP(dp, di_size) == 0)
336df930be7Sderaadt return (0);
337df930be7Sderaadt if (preen)
338df930be7Sderaadt printf(" (RECONNECTED)\n");
339df930be7Sderaadt else
340df930be7Sderaadt if (reply("RECONNECT") == 0)
341df930be7Sderaadt return (0);
342df930be7Sderaadt if (lfdir == 0) {
343df930be7Sderaadt dp = ginode(ROOTINO);
344df930be7Sderaadt idesc.id_name = lfname;
345df930be7Sderaadt idesc.id_type = DATA;
346df930be7Sderaadt idesc.id_func = findino;
347df930be7Sderaadt idesc.id_number = ROOTINO;
348df930be7Sderaadt if ((ckinode(dp, &idesc) & FOUND) != 0) {
349df930be7Sderaadt lfdir = idesc.id_parent;
350df930be7Sderaadt } else {
351df930be7Sderaadt pwarn("NO lost+found DIRECTORY");
352df930be7Sderaadt if (preen || reply("CREATE")) {
35360d6b16fSgluk lfdir = allocdir(ROOTINO, 0, lfmode);
354df930be7Sderaadt if (lfdir != 0) {
355df930be7Sderaadt if (makeentry(ROOTINO, lfdir, lfname) != 0) {
356df930be7Sderaadt if (preen)
357df930be7Sderaadt printf(" (CREATED)\n");
358df930be7Sderaadt } else {
359df930be7Sderaadt freedir(lfdir, ROOTINO);
360df930be7Sderaadt lfdir = 0;
361df930be7Sderaadt if (preen)
362df930be7Sderaadt printf("\n");
363df930be7Sderaadt }
364df930be7Sderaadt }
365df930be7Sderaadt }
366df930be7Sderaadt }
367df930be7Sderaadt if (lfdir == 0) {
368df930be7Sderaadt pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY");
369df930be7Sderaadt printf("\n\n");
370df930be7Sderaadt return (0);
371df930be7Sderaadt }
372df930be7Sderaadt }
373df930be7Sderaadt dp = ginode(lfdir);
3742fffe0e0Smillert if ((DIP(dp, di_mode) & IFMT) != IFDIR) {
375df930be7Sderaadt pfatal("lost+found IS NOT A DIRECTORY");
376df930be7Sderaadt if (reply("REALLOCATE") == 0)
377df930be7Sderaadt return (0);
378df930be7Sderaadt oldlfdir = lfdir;
37960d6b16fSgluk if ((lfdir = allocdir(ROOTINO, 0, lfmode)) == 0) {
380df930be7Sderaadt pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY\n\n");
381df930be7Sderaadt return (0);
382df930be7Sderaadt }
383df930be7Sderaadt if ((changeino(ROOTINO, lfname, lfdir) & ALTERED) == 0) {
384df930be7Sderaadt pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY\n\n");
385df930be7Sderaadt return (0);
386df930be7Sderaadt }
387df930be7Sderaadt inodirty();
388df930be7Sderaadt idesc.id_type = ADDR;
389df930be7Sderaadt idesc.id_func = pass4check;
390df930be7Sderaadt idesc.id_number = oldlfdir;
3914d91232bSotto adjust(&idesc, ILNCOUNT(oldlfdir) + 1);
3924d91232bSotto ILNCOUNT(oldlfdir) = 0;
393df930be7Sderaadt dp = ginode(lfdir);
394df930be7Sderaadt }
3954aab0ea5Sotto if (GET_ISTATE(lfdir) != DFOUND) {
396df930be7Sderaadt pfatal("SORRY. NO lost+found DIRECTORY\n\n");
397df930be7Sderaadt return (0);
398df930be7Sderaadt }
399df930be7Sderaadt (void)lftempname(tempname, orphan);
400df930be7Sderaadt if (makeentry(lfdir, orphan, tempname) == 0) {
401df930be7Sderaadt pfatal("SORRY. NO SPACE IN lost+found DIRECTORY");
402df930be7Sderaadt printf("\n\n");
403df930be7Sderaadt return (0);
404df930be7Sderaadt }
4054d91232bSotto ILNCOUNT(orphan)--;
406df930be7Sderaadt if (lostdir) {
407df930be7Sderaadt if ((changeino(orphan, "..", lfdir) & ALTERED) == 0 &&
408df930be7Sderaadt parentdir != (ino_t)-1)
409df930be7Sderaadt (void)makeentry(orphan, lfdir, "..");
410df930be7Sderaadt dp = ginode(lfdir);
4112fffe0e0Smillert DIP_SET(dp, di_nlink, DIP(dp, di_nlink) + 1);
412df930be7Sderaadt inodirty();
4134d91232bSotto ILNCOUNT(lfdir)++;
4143b92bd08Sderaadt pwarn("DIR I=%llu CONNECTED. ",
4153b92bd08Sderaadt (unsigned long long)orphan);
416e931c121Stholo if (parentdir != (ino_t)-1) {
4173b92bd08Sderaadt printf("PARENT WAS I=%llu\n",
4183b92bd08Sderaadt (unsigned long long)parentdir);
419e931c121Stholo /*
420e931c121Stholo * The parent directory, because of the ordering
421e931c121Stholo * guarantees, has had the link count incremented
422e931c121Stholo * for the child, but no entry was made. This
423e931c121Stholo * fixes the parent link count so that fsck does
424e931c121Stholo * not need to be rerun.
425e931c121Stholo */
4264d91232bSotto ILNCOUNT(parentdir)++;
427e931c121Stholo }
428df930be7Sderaadt if (preen == 0)
429df930be7Sderaadt printf("\n");
430df930be7Sderaadt }
431df930be7Sderaadt return (1);
432df930be7Sderaadt }
433df930be7Sderaadt
434df930be7Sderaadt /*
435df930be7Sderaadt * fix an entry in a directory.
436df930be7Sderaadt */
437df930be7Sderaadt int
changeino(ino_t dir,char * name,ino_t newnum)438c969aecdStb changeino(ino_t dir, char *name, ino_t newnum)
439df930be7Sderaadt {
440df930be7Sderaadt struct inodesc idesc;
441df930be7Sderaadt
442df930be7Sderaadt memset(&idesc, 0, sizeof(struct inodesc));
443df930be7Sderaadt idesc.id_type = DATA;
444df930be7Sderaadt idesc.id_func = chgino;
445df930be7Sderaadt idesc.id_number = dir;
446df930be7Sderaadt idesc.id_fix = DONTKNOW;
447df930be7Sderaadt idesc.id_name = name;
448df930be7Sderaadt idesc.id_parent = newnum; /* new value for name */
449df930be7Sderaadt return (ckinode(ginode(dir), &idesc));
450df930be7Sderaadt }
451df930be7Sderaadt
452df930be7Sderaadt /*
453df930be7Sderaadt * make an entry in a directory
454df930be7Sderaadt */
455df930be7Sderaadt int
makeentry(ino_t parent,ino_t ino,char * name)45660d6b16fSgluk makeentry(ino_t parent, ino_t ino, char *name)
457df930be7Sderaadt {
4582fffe0e0Smillert union dinode *dp;
459df930be7Sderaadt struct inodesc idesc;
460b9fc9a72Sderaadt char pathbuf[PATH_MAX + 1];
461df930be7Sderaadt
462df930be7Sderaadt if (parent < ROOTINO || parent >= maxino ||
463df930be7Sderaadt ino < ROOTINO || ino >= maxino)
464df930be7Sderaadt return (0);
465df930be7Sderaadt memset(&idesc, 0, sizeof(struct inodesc));
466df930be7Sderaadt idesc.id_type = DATA;
467df930be7Sderaadt idesc.id_func = mkentry;
468df930be7Sderaadt idesc.id_number = parent;
469df930be7Sderaadt idesc.id_parent = ino; /* this is the inode to enter */
470df930be7Sderaadt idesc.id_fix = DONTKNOW;
471df930be7Sderaadt idesc.id_name = name;
472df930be7Sderaadt dp = ginode(parent);
4732fffe0e0Smillert if (DIP(dp, di_size) % DIRBLKSIZ) {
4742fffe0e0Smillert DIP_SET(dp, di_size, roundup(DIP(dp, di_size), DIRBLKSIZ));
475df930be7Sderaadt inodirty();
476df930be7Sderaadt }
477df930be7Sderaadt if ((ckinode(dp, &idesc) & ALTERED) != 0)
478df930be7Sderaadt return (1);
47959b30be9Sderaadt getpathname(pathbuf, sizeof pathbuf, parent, parent);
480df930be7Sderaadt dp = ginode(parent);
481df930be7Sderaadt if (expanddir(dp, pathbuf) == 0)
482df930be7Sderaadt return (0);
483df930be7Sderaadt return (ckinode(dp, &idesc) & ALTERED);
484df930be7Sderaadt }
485df930be7Sderaadt
486df930be7Sderaadt /*
487df930be7Sderaadt * Attempt to expand the size of a directory
488df930be7Sderaadt */
48987304b87Stholo static int
expanddir(union dinode * dp,char * name)4902fffe0e0Smillert expanddir(union dinode *dp, char *name)
491df930be7Sderaadt {
4921abdbfdeSderaadt daddr_t lastbn, newblk;
493e073c79dSmpech struct bufarea *bp;
494df930be7Sderaadt char *cp, firstblk[DIRBLKSIZ];
49585109c5eSotto u_int64_t dis;
496df930be7Sderaadt
4972fffe0e0Smillert dis = lblkno(&sblock, DIP(dp, di_size));
49885109c5eSotto if (dis > (u_int64_t)INT_MAX)
49985109c5eSotto return (0);
50085109c5eSotto lastbn = dis;
5012fffe0e0Smillert if (lastbn >= NDADDR - 1 || DIP(dp, di_db[lastbn]) == 0 ||
5022fffe0e0Smillert DIP(dp, di_size) == 0)
503df930be7Sderaadt return (0);
504df930be7Sderaadt if ((newblk = allocblk(sblock.fs_frag)) == 0)
505df930be7Sderaadt return (0);
5062fffe0e0Smillert DIP_SET(dp, di_db[lastbn + 1], DIP(dp, di_db[lastbn]));
5072fffe0e0Smillert DIP_SET(dp, di_db[lastbn], newblk);
5082fffe0e0Smillert DIP_SET(dp, di_size, DIP(dp, di_size) + sblock.fs_bsize);
5092fffe0e0Smillert DIP_SET(dp, di_blocks, DIP(dp, di_blocks) + btodb(sblock.fs_bsize));
5102fffe0e0Smillert bp = getdirblk(DIP(dp, di_db[lastbn + 1]),
5112fffe0e0Smillert sblksize(&sblock, DIP(dp, di_size), lastbn + 1));
512df930be7Sderaadt if (bp->b_errs)
513df930be7Sderaadt goto bad;
514df930be7Sderaadt memcpy(firstblk, bp->b_un.b_buf, DIRBLKSIZ);
515df930be7Sderaadt bp = getdirblk(newblk, sblock.fs_bsize);
516df930be7Sderaadt if (bp->b_errs)
517df930be7Sderaadt goto bad;
518df930be7Sderaadt memcpy(bp->b_un.b_buf, firstblk, DIRBLKSIZ);
519df930be7Sderaadt for (cp = &bp->b_un.b_buf[DIRBLKSIZ];
520df930be7Sderaadt cp < &bp->b_un.b_buf[sblock.fs_bsize];
521df930be7Sderaadt cp += DIRBLKSIZ)
522df930be7Sderaadt memcpy(cp, &emptydir, sizeof emptydir);
523df930be7Sderaadt dirty(bp);
5242fffe0e0Smillert bp = getdirblk(DIP(dp, di_db[lastbn + 1]),
5252fffe0e0Smillert sblksize(&sblock, DIP(dp, di_size), lastbn + 1));
526df930be7Sderaadt if (bp->b_errs)
527df930be7Sderaadt goto bad;
528df930be7Sderaadt memcpy(bp->b_un.b_buf, &emptydir, sizeof emptydir);
529df930be7Sderaadt pwarn("NO SPACE LEFT IN %s", name);
530df930be7Sderaadt if (preen)
531df930be7Sderaadt printf(" (EXPANDED)\n");
532df930be7Sderaadt else if (reply("EXPAND") == 0)
533df930be7Sderaadt goto bad;
534df930be7Sderaadt dirty(bp);
535df930be7Sderaadt inodirty();
536df930be7Sderaadt return (1);
537df930be7Sderaadt bad:
5382fffe0e0Smillert DIP_SET(dp, di_db[lastbn], DIP(dp, di_db[lastbn + 1]));
5392fffe0e0Smillert DIP_SET(dp, di_db[lastbn + 1], 0);
5402fffe0e0Smillert DIP_SET(dp, di_size, DIP(dp, di_size) - sblock.fs_bsize);
5412fffe0e0Smillert DIP_SET(dp, di_blocks, DIP(dp, di_blocks) - btodb(sblock.fs_bsize));
542df930be7Sderaadt freeblk(newblk, sblock.fs_frag);
543df930be7Sderaadt return (0);
544df930be7Sderaadt }
545df930be7Sderaadt
546df930be7Sderaadt /*
547df930be7Sderaadt * allocate a new directory
548df930be7Sderaadt */
5496a0422b3Sguenther ino_t
allocdir(ino_t parent,ino_t request,int mode)55060d6b16fSgluk allocdir(ino_t parent, ino_t request, int mode)
551df930be7Sderaadt {
552df930be7Sderaadt ino_t ino;
553ffb42f9cSbluhm uid_t uid;
554ffb42f9cSbluhm gid_t gid;
555df930be7Sderaadt char *cp;
5562fffe0e0Smillert union dinode *dp;
557e073c79dSmpech struct bufarea *bp;
558df930be7Sderaadt struct dirtemplate *dirp;
5591fb4224cSgluk struct inoinfo *inp;
560df930be7Sderaadt
561df930be7Sderaadt ino = allocino(request, IFDIR|mode);
562df930be7Sderaadt dirp = &dirhead;
563df930be7Sderaadt dirp->dot_ino = ino;
564df930be7Sderaadt dirp->dotdot_ino = parent;
565df930be7Sderaadt dp = ginode(ino);
5662fffe0e0Smillert bp = getdirblk(DIP(dp, di_db[0]), sblock.fs_fsize);
567df930be7Sderaadt if (bp->b_errs) {
568df930be7Sderaadt freeino(ino);
569df930be7Sderaadt return (0);
570df930be7Sderaadt }
571df930be7Sderaadt memcpy(bp->b_un.b_buf, dirp, sizeof(struct dirtemplate));
572df930be7Sderaadt for (cp = &bp->b_un.b_buf[DIRBLKSIZ];
573df930be7Sderaadt cp < &bp->b_un.b_buf[sblock.fs_fsize];
574df930be7Sderaadt cp += DIRBLKSIZ)
575df930be7Sderaadt memcpy(cp, &emptydir, sizeof emptydir);
576df930be7Sderaadt dirty(bp);
5772fffe0e0Smillert DIP_SET(dp, di_nlink, 2);
578df930be7Sderaadt inodirty();
579df930be7Sderaadt if (ino == ROOTINO) {
5804d91232bSotto ILNCOUNT(ino) = DIP(dp, di_nlink);
581df930be7Sderaadt cacheino(dp, ino);
582df930be7Sderaadt return(ino);
583df930be7Sderaadt }
5844aab0ea5Sotto if (GET_ISTATE(parent) != DSTATE && GET_ISTATE(parent) != DFOUND) {
585df930be7Sderaadt freeino(ino);
586df930be7Sderaadt return (0);
587df930be7Sderaadt }
588df930be7Sderaadt cacheino(dp, ino);
5891fb4224cSgluk inp = getinoinfo(ino);
5901fb4224cSgluk inp->i_parent = parent;
5911fb4224cSgluk inp->i_dotdot = parent;
5924aab0ea5Sotto SET_ISTATE(ino, GET_ISTATE(parent));
5934aab0ea5Sotto if (GET_ISTATE(ino) == DSTATE) {
5944d91232bSotto ILNCOUNT(ino) = DIP(dp, di_nlink);
5954d91232bSotto ILNCOUNT(parent)++;
596df930be7Sderaadt }
597df930be7Sderaadt dp = ginode(parent);
5982fffe0e0Smillert DIP_SET(dp, di_nlink, DIP(dp, di_nlink) + 1);
5992fffe0e0Smillert uid = DIP(dp, di_uid);
6002fffe0e0Smillert gid = DIP(dp, di_gid);
601ffb42f9cSbluhm inodirty();
602ffb42f9cSbluhm dp = ginode(ino);
6032fffe0e0Smillert DIP_SET(dp, di_uid, uid);
6042fffe0e0Smillert DIP_SET(dp, di_gid, gid);
605df930be7Sderaadt inodirty();
606df930be7Sderaadt return (ino);
607df930be7Sderaadt }
608df930be7Sderaadt
609df930be7Sderaadt /*
610df930be7Sderaadt * free a directory inode
611df930be7Sderaadt */
61287304b87Stholo static void
freedir(ino_t ino,ino_t parent)61360d6b16fSgluk freedir(ino_t ino, ino_t parent)
614df930be7Sderaadt {
6152fffe0e0Smillert union dinode *dp;
616df930be7Sderaadt
617df930be7Sderaadt if (ino != parent) {
618df930be7Sderaadt dp = ginode(parent);
6192fffe0e0Smillert DIP_SET(dp, di_nlink, DIP(dp, di_nlink) - 1);
620df930be7Sderaadt inodirty();
621df930be7Sderaadt }
622df930be7Sderaadt freeino(ino);
623df930be7Sderaadt }
624df930be7Sderaadt
625df930be7Sderaadt /*
626df930be7Sderaadt * generate a temporary name for the lost+found directory.
627df930be7Sderaadt */
62887304b87Stholo static int
lftempname(char * bufp,ino_t ino)62960d6b16fSgluk lftempname(char *bufp, ino_t ino)
630df930be7Sderaadt {
631e073c79dSmpech ino_t in;
632e073c79dSmpech char *cp;
633df930be7Sderaadt int namlen;
634df930be7Sderaadt
635df930be7Sderaadt cp = bufp + 2;
636df930be7Sderaadt for (in = maxino; in > 0; in /= 10)
637df930be7Sderaadt cp++;
638df930be7Sderaadt *--cp = 0;
639df930be7Sderaadt namlen = cp - bufp;
640df930be7Sderaadt in = ino;
641df930be7Sderaadt while (cp > bufp) {
642df930be7Sderaadt *--cp = (in % 10) + '0';
643df930be7Sderaadt in /= 10;
644df930be7Sderaadt }
645df930be7Sderaadt *cp = '#';
646df930be7Sderaadt return (namlen);
647df930be7Sderaadt }
648df930be7Sderaadt
649df930be7Sderaadt /*
650df930be7Sderaadt * Get a directory block.
651df930be7Sderaadt * Insure that it is held until another is requested.
652df930be7Sderaadt */
65387304b87Stholo static struct bufarea *
getdirblk(daddr_t blkno,long size)6541abdbfdeSderaadt getdirblk(daddr_t blkno, long size)
655df930be7Sderaadt {
656df930be7Sderaadt
657df930be7Sderaadt if (pdirbp != 0)
658df930be7Sderaadt pdirbp->b_flags &= ~B_INUSE;
659df930be7Sderaadt pdirbp = getdatablk(blkno, size);
660df930be7Sderaadt return (pdirbp);
661df930be7Sderaadt }
662