Commit | Line | Data |
---|---|---|
250baf55 KM |
1 | #ifndef lint |
2 | static char version[] = "@(#)dir.c 3.1 (Berkeley) %G%"; | |
3 | #endif | |
4 | ||
5 | #include <sys/param.h> | |
6 | #include <sys/inode.h> | |
7 | #include <sys/fs.h> | |
8 | #define KERNEL | |
9 | #include <sys/dir.h> | |
10 | #undef KERNEL | |
11 | #include "fsck.h" | |
12 | ||
13 | #define MINDIRSIZE (sizeof (struct dirtemplate)) | |
14 | ||
15 | char *endpathname = &pathname[BUFSIZ - 2]; | |
16 | char *lfname = "lost+found"; | |
17 | ||
18 | DIRECT *fsck_readdir(); | |
19 | ||
20 | descend(parentino, inumber) | |
21 | struct inodesc *parentino; | |
22 | ino_t inumber; | |
23 | { | |
24 | register DINODE *dp; | |
25 | struct inodesc curino; | |
26 | ||
27 | bzero((char *)&curino, sizeof(struct inodesc)); | |
28 | statemap[inumber] = FSTATE; | |
29 | if ((dp = ginode(inumber)) == NULL) | |
30 | return; | |
31 | if (dp->di_size == 0) { | |
32 | direrr(inumber, "ZERO LENGTH DIRECTORY"); | |
33 | if (reply("REMOVE") == 1) | |
34 | statemap[inumber] = CLEAR; | |
35 | return; | |
36 | } | |
37 | if (dp->di_size < MINDIRSIZE) { | |
38 | direrr(inumber, "DIRECTORY TOO SHORT"); | |
39 | dp->di_size = MINDIRSIZE; | |
40 | if (reply("FIX") == 1) | |
41 | inodirty(); | |
42 | } | |
43 | curino.id_type = DATA; | |
44 | curino.id_func = parentino->id_func; | |
45 | curino.id_parent = parentino->id_number; | |
46 | curino.id_number = inumber; | |
47 | curino.id_filesize = dp->di_size; | |
48 | (void)ckinode(dp, &curino); | |
49 | } | |
50 | ||
51 | dirscan(idesc) | |
52 | register struct inodesc *idesc; | |
53 | { | |
54 | register DIRECT *dp; | |
55 | int dsize, n; | |
56 | long blksiz; | |
57 | char dbuf[DIRBLKSIZ]; | |
58 | ||
59 | if (idesc->id_type != DATA) | |
60 | errexit("wrong type to dirscan %d\n", idesc->id_type); | |
61 | blksiz = idesc->id_numfrags * sblock.fs_fsize; | |
62 | if (outrange(idesc->id_blkno, idesc->id_numfrags)) { | |
63 | idesc->id_filesize -= blksiz; | |
64 | return (SKIP); | |
65 | } | |
66 | idesc->id_loc = 0; | |
67 | for (dp = fsck_readdir(idesc); dp != NULL; dp = fsck_readdir(idesc)) { | |
68 | dsize = dp->d_reclen; | |
69 | bcopy((char *)dp, dbuf, dsize); | |
70 | idesc->id_dirp = (DIRECT *)dbuf; | |
71 | if ((n = (*idesc->id_func)(idesc)) & ALTERED) { | |
72 | if (getblk(&fileblk, idesc->id_blkno, blksiz) != NULL) { | |
73 | bcopy(dbuf, (char *)dp, dsize); | |
74 | dirty(&fileblk); | |
75 | sbdirty(); | |
76 | } else | |
77 | n &= ~ALTERED; | |
78 | } | |
79 | if (n & STOP) | |
80 | return (n); | |
81 | } | |
82 | return (idesc->id_filesize > 0 ? KEEPON : STOP); | |
83 | } | |
84 | ||
85 | /* | |
86 | * get next entry in a directory. | |
87 | */ | |
88 | DIRECT * | |
89 | fsck_readdir(idesc) | |
90 | register struct inodesc *idesc; | |
91 | { | |
92 | register DIRECT *dp, *ndp; | |
93 | long size, blksiz; | |
94 | ||
95 | blksiz = idesc->id_numfrags * sblock.fs_fsize; | |
96 | if (getblk(&fileblk, idesc->id_blkno, blksiz) == NULL) { | |
97 | idesc->id_filesize -= blksiz - idesc->id_loc; | |
98 | return NULL; | |
99 | } | |
100 | if (idesc->id_loc % DIRBLKSIZ == 0 && idesc->id_filesize > 0 && | |
101 | idesc->id_loc < blksiz) { | |
102 | dp = (DIRECT *)(dirblk.b_buf + idesc->id_loc); | |
103 | if (dircheck(idesc, dp)) | |
104 | goto dpok; | |
105 | idesc->id_loc += DIRBLKSIZ; | |
106 | idesc->id_filesize -= DIRBLKSIZ; | |
107 | dp->d_reclen = DIRBLKSIZ; | |
108 | dp->d_ino = 0; | |
109 | dp->d_namlen = 0; | |
110 | dp->d_name[0] = '\0'; | |
111 | if (dofix(idesc)) | |
112 | dirty(&fileblk); | |
113 | return (dp); | |
114 | } | |
115 | dpok: | |
116 | if (idesc->id_filesize <= 0 || idesc->id_loc >= blksiz) | |
117 | return NULL; | |
118 | dp = (DIRECT *)(dirblk.b_buf + idesc->id_loc); | |
119 | idesc->id_loc += dp->d_reclen; | |
120 | idesc->id_filesize -= dp->d_reclen; | |
121 | if ((idesc->id_loc % DIRBLKSIZ) == 0) | |
122 | return (dp); | |
123 | ndp = (DIRECT *)(dirblk.b_buf + idesc->id_loc); | |
124 | if (idesc->id_loc < blksiz && idesc->id_filesize > 0 && | |
125 | dircheck(idesc, ndp) == 0) { | |
126 | size = DIRBLKSIZ - (idesc->id_loc % DIRBLKSIZ); | |
127 | dp->d_reclen += size; | |
128 | idesc->id_loc += size; | |
129 | idesc->id_filesize -= size; | |
130 | if (dofix(idesc)) | |
131 | dirty(&fileblk); | |
132 | } | |
133 | return (dp); | |
134 | } | |
135 | ||
136 | /* | |
137 | * Verify that a directory entry is valid. | |
138 | * This is a superset of the checks made in the kernel. | |
139 | */ | |
140 | dircheck(idesc, dp) | |
141 | struct inodesc *idesc; | |
142 | register DIRECT *dp; | |
143 | { | |
144 | register int size; | |
145 | register char *cp; | |
146 | int spaceleft; | |
147 | ||
148 | size = DIRSIZ(dp); | |
149 | spaceleft = DIRBLKSIZ - (idesc->id_loc % DIRBLKSIZ); | |
150 | if (dp->d_ino < imax && | |
151 | dp->d_reclen != 0 && | |
152 | dp->d_reclen <= spaceleft && | |
153 | (dp->d_reclen & 0x3) == 0 && | |
154 | dp->d_reclen >= size && | |
155 | idesc->id_filesize >= size && | |
156 | dp->d_namlen <= MAXNAMLEN) { | |
157 | if (dp->d_ino == 0) | |
158 | return (1); | |
159 | for (cp = dp->d_name, size = 0; size < dp->d_namlen; size++) | |
160 | if (*cp == 0 || (*cp++ & 0200)) | |
161 | return (0); | |
162 | if (*cp == 0) | |
163 | return (1); | |
164 | } | |
165 | return (0); | |
166 | } | |
167 | ||
168 | direrr(ino, s) | |
169 | ino_t ino; | |
170 | char *s; | |
171 | { | |
172 | register DINODE *dp; | |
173 | ||
174 | pwarn("%s ", s); | |
175 | pinode(ino); | |
176 | printf("\n"); | |
177 | if ((dp = ginode(ino)) != NULL && ftypeok(dp)) | |
178 | pfatal("%s=%s\n", DIRCT?"DIR":"FILE", pathname); | |
179 | else | |
180 | pfatal("NAME=%s\n", pathname); | |
181 | } | |
182 | ||
183 | adjust(idesc, lcnt) | |
184 | register struct inodesc *idesc; | |
185 | short lcnt; | |
186 | { | |
187 | register DINODE *dp; | |
188 | ||
189 | if ((dp = ginode(idesc->id_number)) == NULL) | |
190 | return; | |
191 | if (dp->di_nlink == lcnt) { | |
192 | if (linkup(idesc->id_number, (ino_t)0) == 0) | |
193 | clri(idesc, "UNREF", 0); | |
194 | } | |
195 | else { | |
196 | pwarn("LINK COUNT %s", | |
197 | (lfdir==idesc->id_number)?lfname:(DIRCT?"DIR":"FILE")); | |
198 | pinode(idesc->id_number); | |
199 | printf(" COUNT %d SHOULD BE %d", | |
200 | dp->di_nlink, dp->di_nlink-lcnt); | |
201 | if (preen) { | |
202 | if (lcnt < 0) { | |
203 | printf("\n"); | |
204 | preendie(); | |
205 | } | |
206 | printf(" (ADJUSTED)\n"); | |
207 | } | |
208 | if (preen || reply("ADJUST") == 1) { | |
209 | dp->di_nlink -= lcnt; | |
210 | inodirty(); | |
211 | } | |
212 | } | |
213 | } | |
214 | ||
215 | mkentry(idesc) | |
216 | struct inodesc *idesc; | |
217 | { | |
218 | register DIRECT *dirp = idesc->id_dirp; | |
219 | DIRECT newent; | |
220 | int newlen, oldlen; | |
221 | ||
222 | newent.d_namlen = 11; | |
223 | newlen = DIRSIZ(&newent); | |
224 | if (dirp->d_ino != 0) | |
225 | oldlen = DIRSIZ(dirp); | |
226 | else | |
227 | oldlen = 0; | |
228 | if (dirp->d_reclen - oldlen < newlen) | |
229 | return (KEEPON); | |
230 | newent.d_reclen = dirp->d_reclen - oldlen; | |
231 | dirp->d_reclen = oldlen; | |
232 | dirp = (struct direct *)(((char *)dirp) + oldlen); | |
233 | dirp->d_ino = idesc->id_parent; /* ino to be entered is in id_parent */ | |
234 | dirp->d_reclen = newent.d_reclen; | |
235 | dirp->d_namlen = lftempname(dirp->d_name, idesc->id_parent); | |
236 | return (ALTERED|STOP); | |
237 | } | |
238 | ||
239 | chgdd(idesc) | |
240 | struct inodesc *idesc; | |
241 | { | |
242 | register DIRECT *dirp = idesc->id_dirp; | |
243 | ||
244 | if (dirp->d_name[0] == '.' && dirp->d_name[1] == '.' && | |
245 | dirp->d_name[2] == 0) { | |
246 | dirp->d_ino = lfdir; | |
247 | return (ALTERED|STOP); | |
248 | } | |
249 | return (KEEPON); | |
250 | } | |
251 | ||
252 | linkup(orphan, pdir) | |
253 | ino_t orphan; | |
254 | ino_t pdir; | |
255 | { | |
256 | register DINODE *dp; | |
257 | int lostdir, len; | |
258 | struct inodesc idesc; | |
259 | ||
260 | bzero((char *)&idesc, sizeof(struct inodesc)); | |
261 | if ((dp = ginode(orphan)) == NULL) | |
262 | return (0); | |
263 | lostdir = DIRCT; | |
264 | pwarn("UNREF %s ", lostdir ? "DIR" : "FILE"); | |
265 | pinode(orphan); | |
266 | if (preen && dp->di_size == 0) | |
267 | return (0); | |
268 | if (preen) | |
269 | printf(" (RECONNECTED)\n"); | |
270 | else | |
271 | if (reply("RECONNECT") == 0) | |
272 | return (0); | |
273 | pathp = pathname; | |
274 | *pathp++ = '/'; | |
275 | *pathp = '\0'; | |
276 | if (lfdir == 0) { | |
277 | if ((dp = ginode(ROOTINO)) == NULL) | |
278 | return (0); | |
279 | srchname = lfname; | |
280 | idesc.id_type = DATA; | |
281 | idesc.id_func = findino; | |
282 | idesc.id_number = ROOTINO; | |
283 | idesc.id_filesize = dp->di_size; | |
284 | (void)ckinode(dp, &idesc); | |
285 | if ((lfdir = idesc.id_parent) == 0) { | |
286 | pfatal("SORRY. NO lost+found DIRECTORY"); | |
287 | printf("\n\n"); | |
288 | return (0); | |
289 | } | |
290 | } | |
291 | if ((dp = ginode(lfdir)) == NULL || | |
292 | !DIRCT || statemap[lfdir] != FSTATE) { | |
293 | pfatal("SORRY. NO lost+found DIRECTORY"); | |
294 | printf("\n\n"); | |
295 | return (0); | |
296 | } | |
297 | if (fragoff(&sblock, dp->di_size)) { | |
298 | dp->di_size = fragroundup(&sblock, dp->di_size); | |
299 | inodirty(); | |
300 | } | |
301 | len = strlen(lfname); | |
302 | bcopy(lfname, pathp, len + 1); | |
303 | pathp += len; | |
304 | idesc.id_type = DATA; | |
305 | idesc.id_func = mkentry; | |
306 | idesc.id_number = lfdir; | |
307 | idesc.id_filesize = dp->di_size; | |
308 | idesc.id_parent = orphan; /* this is the inode to enter */ | |
309 | idesc.id_fix = DONTKNOW; | |
310 | if ((ckinode(dp, &idesc) & ALTERED) == 0) { | |
311 | pfatal("SORRY. NO SPACE IN lost+found DIRECTORY"); | |
312 | printf("\n\n"); | |
313 | return (0); | |
314 | } | |
315 | lncntp[orphan]--; | |
316 | *pathp++ = '/'; | |
317 | pathp += lftempname(pathp, orphan); | |
318 | if (lostdir) { | |
319 | dp = ginode(orphan); | |
320 | idesc.id_type = DATA; | |
321 | idesc.id_func = chgdd; | |
322 | idesc.id_number = orphan; | |
323 | idesc.id_filesize = dp->di_size; | |
324 | idesc.id_fix = DONTKNOW; | |
325 | (void)ckinode(dp, &idesc); | |
326 | if ((dp = ginode(lfdir)) != NULL) { | |
327 | dp->di_nlink++; | |
328 | inodirty(); | |
329 | lncntp[lfdir]++; | |
330 | } | |
331 | pwarn("DIR I=%u CONNECTED. ", orphan); | |
332 | printf("PARENT WAS I=%u\n", pdir); | |
333 | if (preen == 0) | |
334 | printf("\n"); | |
335 | } | |
336 | return (1); | |
337 | } | |
338 | ||
339 | /* | |
340 | * generate a temporary name for the lost+found directory. | |
341 | */ | |
342 | lftempname(bufp, ino) | |
343 | char *bufp; | |
344 | ino_t ino; | |
345 | { | |
346 | register ino_t in; | |
347 | register char *cp; | |
348 | int namlen; | |
349 | ||
350 | cp = bufp + 2; | |
351 | for (in = imax; in > 0; in /= 10) | |
352 | cp++; | |
353 | *--cp = 0; | |
354 | namlen = cp - bufp; | |
355 | in = ino; | |
356 | while (cp > bufp) { | |
357 | *--cp = (in % 10) + '0'; | |
358 | in /= 10; | |
359 | } | |
360 | *cp = '#'; | |
361 | return (namlen); | |
362 | } |