Commit | Line | Data |
---|---|---|
76797561 | 1 | /* |
fe32782c KM |
2 | * Copyright (c) 1980, 1986 The Regents of the University of California. |
3 | * All rights reserved. | |
4 | * | |
70ab3c27 | 5 | * %sccs.include.redist.c% |
76797561 DF |
6 | */ |
7 | ||
7026cd3f | 8 | #ifndef lint |
26bdb130 | 9 | static char sccsid[] = "@(#)inode.c 5.24 (Berkeley) %G%"; |
fe32782c | 10 | #endif /* not lint */ |
7026cd3f KM |
11 | |
12 | #include <sys/param.h> | |
44357263 | 13 | #include <sys/time.h> |
558b3a30 KB |
14 | #include <ufs/ufs/dinode.h> |
15 | #include <ufs/ufs/dir.h> | |
16 | #include <ufs/ffs/fs.h> | |
0086a7e5 | 17 | #include <pwd.h> |
d72e970b KM |
18 | #include <stdlib.h> |
19 | #include <string.h> | |
7026cd3f KM |
20 | #include "fsck.h" |
21 | ||
68a34947 | 22 | static ino_t startinum; |
adc5a10c | 23 | |
7026cd3f | 24 | ckinode(dp, idesc) |
569ec282 | 25 | struct dinode *dp; |
7026cd3f KM |
26 | register struct inodesc *idesc; |
27 | { | |
28 | register daddr_t *ap; | |
569ec282 KM |
29 | long ret, n, ndb, offset; |
30 | struct dinode dino; | |
34d3674f | 31 | quad_t remsize, sizepb; |
26bdb130 | 32 | mode_t mode; |
7026cd3f | 33 | |
20c974e6 KM |
34 | if (idesc->id_fix != IGNORE) |
35 | idesc->id_fix = DONTKNOW; | |
7026cd3f | 36 | idesc->id_entryno = 0; |
f0ed004a | 37 | idesc->id_filesize = dp->di_size; |
26bdb130 KM |
38 | mode = dp->di_mode & IFMT; |
39 | if (mode == IFBLK || mode == IFCHR || (mode == IFLNK && | |
40 | dp->di_size < sblock.fs_maxsymlinklen)) | |
f8a97eea KM |
41 | return (KEEPON); |
42 | dino = *dp; | |
7026cd3f KM |
43 | ndb = howmany(dino.di_size, sblock.fs_bsize); |
44 | for (ap = &dino.di_db[0]; ap < &dino.di_db[NDADDR]; ap++) { | |
45 | if (--ndb == 0 && (offset = blkoff(&sblock, dino.di_size)) != 0) | |
46 | idesc->id_numfrags = | |
47 | numfrags(&sblock, fragroundup(&sblock, offset)); | |
48 | else | |
49 | idesc->id_numfrags = sblock.fs_frag; | |
50 | if (*ap == 0) | |
51 | continue; | |
52 | idesc->id_blkno = *ap; | |
53 | if (idesc->id_type == ADDR) | |
54 | ret = (*idesc->id_func)(idesc); | |
55 | else | |
56 | ret = dirscan(idesc); | |
57 | if (ret & STOP) | |
58 | return (ret); | |
59 | } | |
60 | idesc->id_numfrags = sblock.fs_frag; | |
34d3674f KM |
61 | remsize = dino.di_size - sblock.fs_bsize * NDADDR; |
62 | sizepb = sblock.fs_bsize; | |
7718c0e6 | 63 | for (ap = &dino.di_ib[0], n = 1; n <= NIADDR; ap++, n++) { |
7026cd3f KM |
64 | if (*ap) { |
65 | idesc->id_blkno = *ap; | |
34d3674f | 66 | ret = iblock(idesc, n, remsize); |
7026cd3f KM |
67 | if (ret & STOP) |
68 | return (ret); | |
69 | } | |
34d3674f KM |
70 | sizepb *= NINDIR(&sblock); |
71 | remsize -= sizepb; | |
7026cd3f KM |
72 | } |
73 | return (KEEPON); | |
74 | } | |
75 | ||
76 | iblock(idesc, ilevel, isize) | |
77 | struct inodesc *idesc; | |
34d3674f | 78 | long ilevel; |
61d98039 | 79 | quad_t isize; |
7026cd3f KM |
80 | { |
81 | register daddr_t *ap; | |
82 | register daddr_t *aplim; | |
569ec282 | 83 | register struct bufarea *bp; |
44357263 KM |
84 | int i, n, (*func)(), nif; |
85 | quad_t sizepb; | |
8f7c3c7e | 86 | char buf[BUFSIZ]; |
f10a0ae9 | 87 | extern int dirscan(), pass1check(); |
7026cd3f KM |
88 | |
89 | if (idesc->id_type == ADDR) { | |
90 | func = idesc->id_func; | |
91 | if (((n = (*func)(idesc)) & KEEPON) == 0) | |
92 | return (n); | |
93 | } else | |
94 | func = dirscan; | |
569ec282 | 95 | if (chkrange(idesc->id_blkno, idesc->id_numfrags)) |
7026cd3f | 96 | return (SKIP); |
adc5a10c | 97 | bp = getdatablk(idesc->id_blkno, sblock.fs_bsize); |
7026cd3f | 98 | ilevel--; |
7718c0e6 KM |
99 | for (sizepb = sblock.fs_bsize, i = 0; i < ilevel; i++) |
100 | sizepb *= NINDIR(&sblock); | |
34d3674f | 101 | nif = howmany(isize , sizepb); |
7026cd3f KM |
102 | if (nif > NINDIR(&sblock)) |
103 | nif = NINDIR(&sblock); | |
48a66bfb | 104 | if (idesc->id_func == pass1check && nif < NINDIR(&sblock)) { |
adc5a10c KM |
105 | aplim = &bp->b_un.b_indir[NINDIR(&sblock)]; |
106 | for (ap = &bp->b_un.b_indir[nif]; ap < aplim; ap++) { | |
48a66bfb KM |
107 | if (*ap == 0) |
108 | continue; | |
d72e970b | 109 | (void)sprintf(buf, "PARTIALLY TRUNCATED INODE I=%lu", |
8f7c3c7e KM |
110 | idesc->id_number); |
111 | if (dofix(idesc, buf)) { | |
48a66bfb | 112 | *ap = 0; |
adc5a10c | 113 | dirty(bp); |
48a66bfb KM |
114 | } |
115 | } | |
569ec282 | 116 | flush(fswritefd, bp); |
48a66bfb | 117 | } |
adc5a10c | 118 | aplim = &bp->b_un.b_indir[nif]; |
34d3674f | 119 | for (ap = bp->b_un.b_indir; ap < aplim; ap++) { |
7026cd3f KM |
120 | if (*ap) { |
121 | idesc->id_blkno = *ap; | |
34d3674f | 122 | if (ilevel == 0) { |
7026cd3f | 123 | n = (*func)(idesc); |
34d3674f KM |
124 | } else { |
125 | n = iblock(idesc, ilevel, isize); | |
126 | isize -= sizepb; | |
127 | } | |
adc5a10c KM |
128 | if (n & STOP) { |
129 | bp->b_flags &= ~B_INUSE; | |
7026cd3f | 130 | return (n); |
adc5a10c | 131 | } |
7026cd3f | 132 | } |
adc5a10c KM |
133 | } |
134 | bp->b_flags &= ~B_INUSE; | |
7026cd3f KM |
135 | return (KEEPON); |
136 | } | |
137 | ||
569ec282 KM |
138 | /* |
139 | * Check that a block in a legal block number. | |
140 | * Return 0 if in range, 1 if out of range. | |
141 | */ | |
142 | chkrange(blk, cnt) | |
7026cd3f KM |
143 | daddr_t blk; |
144 | int cnt; | |
145 | { | |
146 | register int c; | |
147 | ||
569ec282 | 148 | if ((unsigned)(blk + cnt) > maxfsblock) |
7026cd3f KM |
149 | return (1); |
150 | c = dtog(&sblock, blk); | |
151 | if (blk < cgdmin(&sblock, c)) { | |
569ec282 | 152 | if ((blk + cnt) > cgsblock(&sblock, c)) { |
7026cd3f | 153 | if (debug) { |
d72e970b | 154 | printf("blk %ld < cgdmin %ld;", |
7026cd3f | 155 | blk, cgdmin(&sblock, c)); |
d72e970b | 156 | printf(" blk + cnt %ld > cgsbase %ld\n", |
569ec282 | 157 | blk + cnt, cgsblock(&sblock, c)); |
7026cd3f KM |
158 | } |
159 | return (1); | |
160 | } | |
161 | } else { | |
569ec282 | 162 | if ((blk + cnt) > cgbase(&sblock, c+1)) { |
7026cd3f | 163 | if (debug) { |
d72e970b | 164 | printf("blk %ld >= cgdmin %ld;", |
7026cd3f | 165 | blk, cgdmin(&sblock, c)); |
d72e970b | 166 | printf(" blk + cnt %ld > sblock.fs_fpg %ld\n", |
7026cd3f KM |
167 | blk+cnt, sblock.fs_fpg); |
168 | } | |
169 | return (1); | |
170 | } | |
171 | } | |
172 | return (0); | |
173 | } | |
174 | ||
071ea3c2 KM |
175 | /* |
176 | * General purpose interface for reading inodes. | |
177 | */ | |
569ec282 | 178 | struct dinode * |
7026cd3f KM |
179 | ginode(inumber) |
180 | ino_t inumber; | |
181 | { | |
182 | daddr_t iblk; | |
7026cd3f | 183 | |
569ec282 | 184 | if (inumber < ROOTINO || inumber > maxino) |
39c18287 | 185 | errexit("bad inode number %d to ginode\n", inumber); |
7026cd3f KM |
186 | if (startinum == 0 || |
187 | inumber < startinum || inumber >= startinum + INOPB(&sblock)) { | |
188 | iblk = itod(&sblock, inumber); | |
adc5a10c KM |
189 | if (pbp != 0) |
190 | pbp->b_flags &= ~B_INUSE; | |
191 | pbp = getdatablk(iblk, sblock.fs_bsize); | |
7026cd3f KM |
192 | startinum = (inumber / INOPB(&sblock)) * INOPB(&sblock); |
193 | } | |
adc5a10c KM |
194 | return (&pbp->b_un.b_dinode[inumber % INOPB(&sblock)]); |
195 | } | |
196 | ||
071ea3c2 KM |
197 | /* |
198 | * Special purpose version of ginode used to optimize first pass | |
199 | * over all the inodes in numerical order. | |
200 | */ | |
201 | ino_t nextino, lastinum; | |
202 | long readcnt, readpercg, fullcnt, inobufsize, partialcnt, partialsize; | |
203 | struct dinode *inodebuf; | |
204 | ||
205 | struct dinode * | |
206 | getnextinode(inumber) | |
207 | ino_t inumber; | |
208 | { | |
209 | long size; | |
210 | daddr_t dblk; | |
211 | static struct dinode *dp; | |
212 | ||
213 | if (inumber != nextino++ || inumber > maxino) | |
214 | errexit("bad inode number %d to nextinode\n", inumber); | |
215 | if (inumber >= lastinum) { | |
216 | readcnt++; | |
217 | dblk = fsbtodb(&sblock, itod(&sblock, lastinum)); | |
218 | if (readcnt % readpercg == 0) { | |
219 | size = partialsize; | |
220 | lastinum += partialcnt; | |
221 | } else { | |
222 | size = inobufsize; | |
223 | lastinum += fullcnt; | |
224 | } | |
d72e970b | 225 | (void)bread(fsreadfd, (char *)inodebuf, dblk, size); /* ??? */ |
071ea3c2 KM |
226 | dp = inodebuf; |
227 | } | |
228 | return (dp++); | |
229 | } | |
230 | ||
231 | resetinodebuf() | |
232 | { | |
233 | ||
68a34947 | 234 | startinum = 0; |
071ea3c2 KM |
235 | nextino = 0; |
236 | lastinum = 0; | |
237 | readcnt = 0; | |
238 | inobufsize = blkroundup(&sblock, INOBUFSIZE); | |
239 | fullcnt = inobufsize / sizeof(struct dinode); | |
240 | readpercg = sblock.fs_ipg / fullcnt; | |
241 | partialcnt = sblock.fs_ipg % fullcnt; | |
242 | partialsize = partialcnt * sizeof(struct dinode); | |
243 | if (partialcnt != 0) { | |
244 | readpercg++; | |
245 | } else { | |
246 | partialcnt = fullcnt; | |
247 | partialsize = inobufsize; | |
248 | } | |
249 | if (inodebuf == NULL && | |
250 | (inodebuf = (struct dinode *)malloc((unsigned)inobufsize)) == NULL) | |
251 | errexit("Cannot allocate space for inode buffer\n"); | |
252 | while (nextino < ROOTINO) | |
d72e970b | 253 | (void)getnextinode(nextino); |
071ea3c2 KM |
254 | } |
255 | ||
256 | freeinodebuf() | |
257 | { | |
258 | ||
259 | if (inodebuf != NULL) | |
260 | free((char *)inodebuf); | |
261 | inodebuf = NULL; | |
262 | } | |
263 | ||
264 | /* | |
265 | * Routines to maintain information about directory inodes. | |
266 | * This is built during the first pass and used during the | |
267 | * second and third passes. | |
268 | * | |
269 | * Enter inodes into the cache. | |
270 | */ | |
57117c0f KM |
271 | cacheino(dp, inumber) |
272 | register struct dinode *dp; | |
273 | ino_t inumber; | |
274 | { | |
275 | register struct inoinfo *inp; | |
276 | struct inoinfo **inpp; | |
277 | unsigned int blks; | |
278 | ||
57117c0f KM |
279 | blks = howmany(dp->di_size, sblock.fs_bsize); |
280 | if (blks > NDADDR) | |
281 | blks = NDADDR + NIADDR; | |
282 | inp = (struct inoinfo *) | |
283 | malloc(sizeof(*inp) + (blks - 1) * sizeof(daddr_t)); | |
284 | if (inp == NULL) | |
285 | return; | |
071ea3c2 KM |
286 | inpp = &inphead[inumber % numdirs]; |
287 | inp->i_nexthash = *inpp; | |
57117c0f | 288 | *inpp = inp; |
071ea3c2 KM |
289 | inp->i_parent = (ino_t)0; |
290 | inp->i_dotdot = (ino_t)0; | |
57117c0f | 291 | inp->i_number = inumber; |
071ea3c2 | 292 | inp->i_isize = dp->di_size; |
57117c0f | 293 | inp->i_numblks = blks * sizeof(daddr_t); |
071ea3c2 | 294 | bcopy((char *)&dp->di_db[0], (char *)&inp->i_blks[0], |
d72e970b | 295 | (size_t)inp->i_numblks); |
071ea3c2 KM |
296 | if (inplast == listmax) { |
297 | listmax += 100; | |
298 | inpsort = (struct inoinfo **)realloc((char *)inpsort, | |
299 | (unsigned)listmax * sizeof(struct inoinfo *)); | |
300 | if (inpsort == NULL) | |
301 | errexit("cannot increase directory list"); | |
302 | } | |
303 | inpsort[inplast++] = inp; | |
57117c0f KM |
304 | } |
305 | ||
071ea3c2 KM |
306 | /* |
307 | * Look up an inode cache structure. | |
308 | */ | |
309 | struct inoinfo * | |
310 | getinoinfo(inumber) | |
57117c0f KM |
311 | ino_t inumber; |
312 | { | |
313 | register struct inoinfo *inp; | |
57117c0f | 314 | |
071ea3c2 | 315 | for (inp = inphead[inumber % numdirs]; inp; inp = inp->i_nexthash) { |
57117c0f KM |
316 | if (inp->i_number != inumber) |
317 | continue; | |
071ea3c2 | 318 | return (inp); |
57117c0f | 319 | } |
071ea3c2 KM |
320 | errexit("cannot find inode %d\n", inumber); |
321 | return ((struct inoinfo *)0); | |
57117c0f KM |
322 | } |
323 | ||
071ea3c2 KM |
324 | /* |
325 | * Clean up all the inode cache structure. | |
326 | */ | |
57117c0f KM |
327 | inocleanup() |
328 | { | |
071ea3c2 | 329 | register struct inoinfo **inpp; |
57117c0f KM |
330 | |
331 | if (inphead == NULL) | |
332 | return; | |
071ea3c2 KM |
333 | for (inpp = &inpsort[inplast - 1]; inpp >= inpsort; inpp--) |
334 | free((char *)(*inpp)); | |
335 | free((char *)inphead); | |
336 | free((char *)inpsort); | |
337 | inphead = inpsort = NULL; | |
57117c0f KM |
338 | } |
339 | ||
adc5a10c KM |
340 | inodirty() |
341 | { | |
342 | ||
343 | dirty(pbp); | |
7026cd3f KM |
344 | } |
345 | ||
569ec282 | 346 | clri(idesc, type, flag) |
7026cd3f | 347 | register struct inodesc *idesc; |
569ec282 KM |
348 | char *type; |
349 | int flag; | |
7026cd3f | 350 | { |
569ec282 | 351 | register struct dinode *dp; |
7026cd3f | 352 | |
39c18287 | 353 | dp = ginode(idesc->id_number); |
569ec282 KM |
354 | if (flag == 1) { |
355 | pwarn("%s %s", type, | |
356 | (dp->di_mode & IFMT) == IFDIR ? "DIR" : "FILE"); | |
7026cd3f KM |
357 | pinode(idesc->id_number); |
358 | } | |
359 | if (preen || reply("CLEAR") == 1) { | |
360 | if (preen) | |
361 | printf(" (CLEARED)\n"); | |
362 | n_files--; | |
363 | (void)ckinode(dp, idesc); | |
569ec282 | 364 | clearinode(dp); |
7026cd3f KM |
365 | statemap[idesc->id_number] = USTATE; |
366 | inodirty(); | |
7026cd3f KM |
367 | } |
368 | } | |
369 | ||
3ad2f081 KM |
370 | findname(idesc) |
371 | struct inodesc *idesc; | |
372 | { | |
569ec282 | 373 | register struct direct *dirp = idesc->id_dirp; |
3ad2f081 KM |
374 | |
375 | if (dirp->d_ino != idesc->id_parent) | |
376 | return (KEEPON); | |
d72e970b | 377 | bcopy(dirp->d_name, idesc->id_name, (size_t)dirp->d_namlen + 1); |
315f1422 | 378 | return (STOP|FOUND); |
3ad2f081 KM |
379 | } |
380 | ||
7026cd3f KM |
381 | findino(idesc) |
382 | struct inodesc *idesc; | |
383 | { | |
569ec282 | 384 | register struct direct *dirp = idesc->id_dirp; |
7026cd3f KM |
385 | |
386 | if (dirp->d_ino == 0) | |
387 | return (KEEPON); | |
3ad2f081 | 388 | if (strcmp(dirp->d_name, idesc->id_name) == 0 && |
569ec282 | 389 | dirp->d_ino >= ROOTINO && dirp->d_ino <= maxino) { |
3ad2f081 | 390 | idesc->id_parent = dirp->d_ino; |
315f1422 | 391 | return (STOP|FOUND); |
7026cd3f KM |
392 | } |
393 | return (KEEPON); | |
394 | } | |
395 | ||
396 | pinode(ino) | |
397 | ino_t ino; | |
398 | { | |
569ec282 | 399 | register struct dinode *dp; |
7026cd3f | 400 | register char *p; |
1ccd95ec | 401 | struct passwd *pw; |
7026cd3f KM |
402 | char *ctime(); |
403 | ||
d72e970b | 404 | printf(" I=%lu ", ino); |
569ec282 | 405 | if (ino < ROOTINO || ino > maxino) |
7026cd3f | 406 | return; |
39c18287 | 407 | dp = ginode(ino); |
7026cd3f | 408 | printf(" OWNER="); |
1ccd95ec KM |
409 | if ((pw = getpwuid((int)dp->di_uid)) != 0) |
410 | printf("%s ", pw->pw_name); | |
411 | else | |
d72e970b | 412 | printf("%u ", (unsigned)dp->di_uid); |
7026cd3f KM |
413 | printf("MODE=%o\n", dp->di_mode); |
414 | if (preen) | |
415 | printf("%s: ", devname); | |
44357263 | 416 | printf("SIZE=%qu ", dp->di_size); |
d57d2bb7 | 417 | p = ctime(&dp->di_mtime.ts_sec); |
7314222d | 418 | printf("MTIME=%12.12s %4.4s ", &p[4], &p[20]); |
7026cd3f KM |
419 | } |
420 | ||
569ec282 | 421 | blkerror(ino, type, blk) |
7026cd3f | 422 | ino_t ino; |
569ec282 | 423 | char *type; |
7026cd3f KM |
424 | daddr_t blk; |
425 | { | |
426 | ||
d72e970b | 427 | pfatal("%ld %s I=%lu", blk, type, ino); |
7026cd3f | 428 | printf("\n"); |
993a756c KM |
429 | switch (statemap[ino]) { |
430 | ||
431 | case FSTATE: | |
432 | statemap[ino] = FCLEAR; | |
433 | return; | |
434 | ||
435 | case DSTATE: | |
436 | statemap[ino] = DCLEAR; | |
437 | return; | |
438 | ||
439 | case FCLEAR: | |
440 | case DCLEAR: | |
441 | return; | |
442 | ||
443 | default: | |
444 | errexit("BAD STATE %d TO BLKERR", statemap[ino]); | |
445 | /* NOTREACHED */ | |
446 | } | |
7026cd3f | 447 | } |
ebd05fde KM |
448 | |
449 | /* | |
450 | * allocate an unused inode | |
451 | */ | |
452 | ino_t | |
453 | allocino(request, type) | |
454 | ino_t request; | |
455 | int type; | |
456 | { | |
457 | register ino_t ino; | |
569ec282 | 458 | register struct dinode *dp; |
ebd05fde KM |
459 | |
460 | if (request == 0) | |
461 | request = ROOTINO; | |
462 | else if (statemap[request] != USTATE) | |
463 | return (0); | |
569ec282 | 464 | for (ino = request; ino < maxino; ino++) |
ebd05fde KM |
465 | if (statemap[ino] == USTATE) |
466 | break; | |
569ec282 | 467 | if (ino == maxino) |
ebd05fde KM |
468 | return (0); |
469 | switch (type & IFMT) { | |
470 | case IFDIR: | |
471 | statemap[ino] = DSTATE; | |
472 | break; | |
473 | case IFREG: | |
474 | case IFLNK: | |
475 | statemap[ino] = FSTATE; | |
476 | break; | |
477 | default: | |
478 | return (0); | |
479 | } | |
480 | dp = ginode(ino); | |
569ec282 | 481 | dp->di_db[0] = allocblk((long)1); |
ebd05fde KM |
482 | if (dp->di_db[0] == 0) { |
483 | statemap[ino] = USTATE; | |
484 | return (0); | |
485 | } | |
486 | dp->di_mode = type; | |
d57d2bb7 | 487 | (void)time(&dp->di_atime.ts_sec); |
ebd05fde KM |
488 | dp->di_mtime = dp->di_ctime = dp->di_atime; |
489 | dp->di_size = sblock.fs_fsize; | |
490 | dp->di_blocks = btodb(sblock.fs_fsize); | |
491 | n_files++; | |
492 | inodirty(); | |
493 | return (ino); | |
494 | } | |
495 | ||
496 | /* | |
497 | * deallocate an inode | |
498 | */ | |
499 | freeino(ino) | |
500 | ino_t ino; | |
501 | { | |
502 | struct inodesc idesc; | |
503 | extern int pass4check(); | |
569ec282 | 504 | struct dinode *dp; |
ebd05fde KM |
505 | |
506 | bzero((char *)&idesc, sizeof(struct inodesc)); | |
507 | idesc.id_type = ADDR; | |
508 | idesc.id_func = pass4check; | |
509 | idesc.id_number = ino; | |
510 | dp = ginode(ino); | |
511 | (void)ckinode(dp, &idesc); | |
569ec282 | 512 | clearinode(dp); |
ebd05fde KM |
513 | inodirty(); |
514 | statemap[ino] = USTATE; | |
515 | n_files--; | |
516 | } |