6e74b195f6eb5a2bb132b70baf0a55d6a9528325
[openafs.git] / src / vfsck / inode.c
1 /*
2  * Copyright (c) 1980, 1986 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms are permitted
6  * provided that the above copyright notice and this paragraph are
7  * duplicated in all such forms and that any documentation,
8  * advertising materials, and other materials related to such
9  * distribution and use acknowledge that the software was developed
10  * by the University of California, Berkeley.  The name of the
11  * University may not be used to endorse or promote products derived
12  * from this software without specific prior written permission.
13  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16  */
17
18 #include <afsconfig.h>
19 #include <afs/param.h>
20
21 #include <roken.h>
22
23 #include <ctype.h>
24
25 #define VICE                    /* control whether AFS changes are present */
26
27 #ifdef  AFS_OSF_ENV
28 #include <sys/mount.h>
29 #include <sys/vnode.h>
30 #include <ufs/inode.h>
31 #include <ufs/fs.h>
32 #define _BSD
33 #define _KERNEL
34 #include <ufs/dir.h>
35 #undef  _KERNEL
36 #undef  _BSD
37 #else /* AFS_OSF_ENV */
38 #ifdef AFS_VFSINCL_ENV
39 #define VFS
40 #include <sys/vnode.h>
41 #ifdef    AFS_SUN5_ENV
42 #include <sys/fs/ufs_inode.h>
43 #include <sys/fs/ufs_fs.h>
44 #define _KERNEL
45 #include <sys/fs/ufs_fsdir.h>
46 #undef _KERNEL
47 #else
48 #include <ufs/inode.h>
49 #define KERNEL
50 #include <ufs/fsdir.h>
51 #undef  KERNEL
52 #include <ufs/fs.h>
53 #endif
54 #else /* AFS_VFSINCL_ENV */
55 #include <sys/inode.h>
56 #ifdef  AFS_HPUX_ENV
57 #define LONGFILENAMES   1
58 #include <sys/sysmacros.h>
59 #include <sys/ino.h>
60 #define DIRSIZ_MACRO
61 #ifdef HAVE_USR_OLD_USR_INCLUDE_NDIR_H
62 #include </usr/old/usr/include/ndir.h>
63 #else
64 #include <ndir.h>
65 #endif
66 #else
67 #include <sys/dir.h>
68 #endif
69 #include <sys/fs.h>
70 #endif /* AFS_VFSINCL_ENV */
71 #endif /* AFS_OSF_ENV */
72
73 #include <afs/osi_inode.h>
74 #include <pwd.h>
75 #include "fsck.h"
76
77 #ifdef AFS_SUN_ENV
78 #ifdef  AFS_SUN5_ENV
79 #include <sys/mnttab.h>
80 #include <sys/mntent.h>
81 #else
82 #include <mntent.h>
83 #endif
84 #endif /* AFS_SUN_ENV */
85
86 struct bufarea *pbp = 0;
87
88 ckinode(dp, idesc)
89      struct dinode *dp;
90      struct inodesc *idesc;
91 {
92     daddr_t *ap;
93     long ret, n, ndb, offset;
94     struct dinode dino;
95     UOFF_T indir_data_blks;
96     extern int pass1check();
97
98 #ifdef  AFS_HPUX_ENV
99     if (FASTLNK)
100         return (KEEPON);
101 #endif
102     idesc->id_fix = DONTKNOW;
103     idesc->id_entryno = 0;
104     idesc->id_filesize = dp->di_size;
105     if ((dp->di_mode & IFMT) == IFBLK || (dp->di_mode & IFMT) == IFCHR)
106         return (KEEPON);
107 #ifdef  AFS_OSF_ENV
108     if ((dp->di_flags & IC_FASTLINK) != 0) {
109         return (KEEPON);
110     }
111 #endif /* AFS_OSF_ENV */
112     dino = *dp;
113     ndb = howmany(dino.di_size, (UOFF_T) sblock.fs_bsize);
114     ap = &dino.di_db[0];
115 #ifdef AFS_OSF_ENV
116     /*
117      * Check property lists on pass1
118      */
119     if (idesc->id_func == pass1check && dino.di_flags & IC_PROPLIST && *ap) {
120         ret = proplist_scan(dp, idesc);
121         if (ret & STOP)
122             return (ret);
123     }
124 #endif /* AFS_OSF_ENV */
125     for (; ap < &dino.di_db[NDADDR]; ap++) {
126         if (--ndb == 0 && (offset = blkoff(&sblock, dino.di_size)) != 0)
127             idesc->id_numfrags =
128                 numfrags(&sblock, fragroundup(&sblock, offset));
129         else
130             idesc->id_numfrags = sblock.fs_frag;
131         if (*ap == 0)
132             continue;
133         idesc->id_blkno = *ap;
134         if (idesc->id_type == ADDR)
135             ret = (*idesc->id_func) (idesc);
136         else
137             ret = dirscan(idesc);
138         if (ret & STOP)
139             return (ret);
140     }
141     idesc->id_numfrags = sblock.fs_frag;
142 #if     defined(AFS_SUN56_ENV)
143     /*
144      * indir_data_blks determine the no. of data blocks
145      * in the previous levels. ie., at level 3 it
146      * is the number of data blocks at level 2, 1, and 0.
147      */
148     for (ap = &dino.di_ib[0], n = 1; n <= NIADDR; ap++, n++) {
149         if (n == 1) {
150             /* SINGLE */
151             indir_data_blks = NDADDR;
152         } else if (n == 2) {
153             /* DOUBLE */
154             indir_data_blks = NDADDR + NINDIR(&sblock);
155         } else if (n == 3) {
156             /* TRIPLE */
157             indir_data_blks =
158                 NDADDR + NINDIR(&sblock) +
159                 (NINDIR(&sblock) * NINDIR(&sblock));
160         }
161         if (*ap) {
162             idesc->id_blkno = *ap;
163             ret =
164                 iblock(idesc, n,
165                        (u_offset_t) howmany(dino.di_size,
166                                             (u_offset_t) sblock.fs_bsize) -
167                        indir_data_blks);
168             if (ret & STOP)
169                 return (ret);
170         }
171     }
172 #else
173     for (ap = &dino.di_ib[0], n = 1; n <= NIADDR; ap++, n++) {
174         if (*ap) {
175             idesc->id_blkno = *ap;
176             ret = iblock(idesc, n, dino.di_size - sblock.fs_bsize * NDADDR);
177             if (ret & STOP)
178                 return (ret);
179         }
180     }
181 #endif
182     return (KEEPON);
183 }
184
185 iblock(idesc, ilevel, isize)
186      struct inodesc *idesc;
187      long ilevel;
188      UOFF_T isize;
189 {
190     daddr_t *ap;
191     daddr_t *aplim;
192     int i, n, (*func) ();
193     UOFF_T sizepb;
194     OFF_T nif;
195     struct bufarea *bp;
196     char buf[BUFSIZ];
197     extern int dirscan(), pass1check();
198
199     if (idesc->id_type == ADDR) {
200         func = idesc->id_func;
201         if (((n = (*func) (idesc)) & KEEPON) == 0)
202             return (n);
203     } else
204         func = dirscan;
205     if (chkrange(idesc->id_blkno, idesc->id_numfrags))
206         return (SKIP);
207     bp = getdatablk(idesc->id_blkno, sblock.fs_bsize);
208     ilevel--;
209 #if     defined(AFS_SUN56_ENV)
210     for (sizepb = 1, i = 0; i < ilevel; i++) {
211         sizepb *= (u_offset_t) NINDIR(&sblock);
212     }
213
214     /*
215      * nif indicates the next "free" pointer (as an array index) in this
216      * indirect block, based on counting the blocks remaining in the
217      * file after subtracting all previously processed blocks.
218      * This figure is based on the size field of the inode.
219      *
220      * Note that in normal operation, nif may initially calculated to
221      * be larger than the number of pointers in this block; if that is
222      * the case, nif is limited to the max number of pointers per
223      * indirect block.
224      *
225      * Also note that if an inode is inconsistant (has more blocks
226      * allocated to it than the size field would indicate), the sweep
227      * through any indirect blocks directly pointed at by the inode
228      * continues. Since the block offset of any data blocks referenced
229      * by these indirect blocks is greater than the size of the file,
230      * the index nif may be computed as a negative value.
231      * In this case, we reset nif to indicate that all pointers in
232      * this retrieval block should be zeroed and the resulting
233      * unreferenced data and/or retrieval blocks be recovered
234      * through garbage collection later.
235      */
236     nif = (offset_t) howmany(isize, sizepb);
237     if (nif > NINDIR(&sblock))
238         nif = NINDIR(&sblock);
239     else if (nif < 0)
240         nif = 0;
241 #else
242     for (sizepb = sblock.fs_bsize, i = 0; i < ilevel; i++)
243         sizepb *= (UOFF_T) NINDIR(&sblock);
244     nif = isize / sizepb + 1;
245     if (nif > NINDIR(&sblock))
246         nif = NINDIR(&sblock);
247 #endif
248     if (idesc->id_func == pass1check && nif < NINDIR(&sblock)) {
249         aplim = &bp->b_un.b_indir[NINDIR(&sblock)];
250         for (ap = &bp->b_un.b_indir[nif]; ap < aplim; ap++) {
251             if (*ap == 0)
252                 continue;
253             (void)sprintf(buf, "PARTIALLY TRUNCATED INODE I=%d",
254                           idesc->id_number);
255             if (dofix(idesc, buf)) {
256                 *ap = 0;
257                 dirty(bp);
258             }
259         }
260         flush(fswritefd, bp);
261     }
262     aplim = &bp->b_un.b_indir[nif];
263     for (ap = bp->b_un.b_indir, i = 1; ap < aplim; ap++, i++) {
264         if (*ap) {
265             idesc->id_blkno = *ap;
266             if (ilevel > 0) {
267 #if     defined(AFS_SUN56_ENV)
268                 n = iblock(idesc, ilevel, isize);
269                 /*
270                  * each iteration decrease "remaining block
271                  * count" by however many blocks were accessible
272                  * by a pointer at this indirect block level.
273                  */
274                 isize -= sizepb;
275 #else
276                 n = iblock(idesc, ilevel, isize - i * sizepb);
277 #endif
278             } else
279                 n = (*func) (idesc);
280             if (n & STOP) {
281                 bp->b_flags &= ~B_INUSE;
282                 return (n);
283             }
284         }
285     }
286     bp->b_flags &= ~B_INUSE;
287     return (KEEPON);
288 }
289
290 /*
291  * Check that a block in a legal block number.
292  * Return 0 if in range, 1 if out of range.
293  */
294 chkrange(blk, cnt)
295      daddr_t blk;
296      int cnt;
297 {
298     int c;
299
300     if ((unsigned)(blk + cnt) > maxfsblock)
301         return (1);
302     c = dtog(&sblock, blk);
303     if (blk < cgdmin(&sblock, c)) {
304         if ((blk + cnt) > cgsblock(&sblock, c)) {
305             if (debug) {
306                 printf("blk %d < cgdmin %d;", blk, cgdmin(&sblock, c));
307                 printf(" blk + cnt %d > cgsbase %d\n", blk + cnt,
308                        cgsblock(&sblock, c));
309             }
310             return (1);
311         }
312     } else {
313         if ((blk + cnt) > cgbase(&sblock, c + 1)) {
314             if (debug) {
315                 printf("blk %d >= cgdmin %d;", blk, cgdmin(&sblock, c));
316                 printf(" blk + cnt %d > sblock.fs_fpg %d\n", blk + cnt,
317                        sblock.fs_fpg);
318             }
319             return (1);
320         }
321     }
322     return (0);
323 }
324
325 struct dinode *
326 ginode(inumber)
327      ino_t inumber;
328 {
329     daddr_t iblk;
330
331     if (inumber < ROOTINO || inumber > maxino)
332         errexit("bad inode number %d to ginode\n", inumber);
333     if (mlk_startinum == 0 || inumber < mlk_startinum
334         || inumber >= mlk_startinum + INOPB(&sblock)) {
335         iblk = itod(&sblock, inumber);
336         if (pbp != 0)
337             pbp->b_flags &= ~B_INUSE;
338         pbp = getdatablk(iblk, sblock.fs_bsize);
339         mlk_startinum = (inumber / INOPB(&sblock)) * INOPB(&sblock);
340     }
341     return (&pbp->b_un.b_dinode[inumber % INOPB(&sblock)]);
342 }
343
344 #ifdef  AFS_SUN5_ENVX
345 inocleanup()
346 {
347     struct inoinfo **inpp;
348
349     if (inphead == NULL)
350         return;
351     for (inpp = &inpsort[inplast - 1]; inpp >= inpsort; inpp--)
352         free((char *)(*inpp));
353     free((char *)inphead);
354     free((char *)inpsort);
355     inphead = inpsort = NULL;
356 }
357 #endif
358
359 inodirty()
360 {
361
362     dirty(pbp);
363 }
364
365 clri(idesc, type, flag)
366      struct inodesc *idesc;
367      char *type;
368      int flag;
369 {
370     struct dinode *dp;
371 #if defined(ACLS) && defined(AFS_HPUX_ENV)
372     struct inodesc cidesc;
373 #endif /* ACLS */
374
375     dp = ginode(idesc->id_number);
376     if (flag == 1) {
377         pwarn("%s %s", type, (dp->di_mode & IFMT) == IFDIR ? "DIR" : "FILE");
378         pinode(idesc->id_number);
379 #if defined(ACLS) && defined(AFS_HPUX_ENV)
380     } else if (flag == 2) {
381         pwarn("%s %s", type, "CONTINUATION INODE ");
382         printf(" I=%u ", idesc->id_number);
383 #endif /* ACLS */
384     }
385     if (preen || reply("CLEAR") == 1) {
386         if (preen)
387             printf(" (CLEARED)\n");
388 #if defined(ACLS) && defined(AFS_HPUX_ENV)
389         if (CONT)
390             n_cont--;
391         else
392             n_files--;
393
394         /*
395          * If there is a CI associated with this inode, we must
396          * clear it as well.
397          */
398         if (statemap[idesc->id_number] & HASCINODE) {
399             if (!(dp->di_contin < ROOTINO || dp->di_contin > maxino))
400                 cidesc.id_number = dp->di_contin;
401             clri(&cidesc, "UNREF", 2);
402         }
403 #else /* no ACLS */
404         n_files--;
405 #endif /* ACLS */
406         (void)ckinode(dp, idesc);
407 #ifdef  VICE
408         zapino(dp);
409 #else /* VICE */
410         clearinode(dp);
411 #endif /* VICE */
412         statemap[idesc->id_number] = USTATE;
413         inodirty();
414     }
415 }
416
417 findname(idesc)
418      struct inodesc *idesc;
419 {
420     struct direct *dirp = idesc->id_dirp;
421
422     if (dirp->d_ino != idesc->id_parent)
423         return (KEEPON);
424     memcpy(idesc->id_name, dirp->d_name, (int)dirp->d_namlen + 1);
425     return (STOP | FOUND);
426 }
427
428 findino(idesc)
429      struct inodesc *idesc;
430 {
431     struct direct *dirp = idesc->id_dirp;
432
433     if (dirp->d_ino == 0)
434         return (KEEPON);
435     if (strcmp(dirp->d_name, idesc->id_name) == 0 && dirp->d_ino >= ROOTINO
436         && dirp->d_ino <= maxino) {
437         idesc->id_parent = dirp->d_ino;
438         return (STOP | FOUND);
439     }
440     return (KEEPON);
441 }
442
443 pinode(ino)
444      ino_t ino;
445 {
446     struct dinode *dp;
447     char *p;
448     struct passwd *pw;
449     char *ctime();
450     time_t t;
451
452     printf(" I=%u ", ino);
453     if (ino < ROOTINO || ino > maxino)
454         return;
455     dp = ginode(ino);
456     printf(" OWNER=");
457 #if     defined(AFS_HPUX110_ENV)
458     {
459         char uidbuf[BUFSIZ];
460         char *p;
461         uid_t uid;
462         if (dp == NULL) {
463             pwarn("Could not getinode(%d) in pinode.", ino);
464             return;
465         }
466         uid = _GET_D_UID(dp);
467         if (getpw(uid, uidbuf) == 0) {
468             for (p = uidbuf; *p != ':'; p++);
469             *p = 0;
470             printf("%s ", uidbuf);
471         } else {
472             printf("%d ", uid);
473         }
474     }
475 #else /* AFS_HPUX110_ENV */
476 #if     defined(AFS_HPUX102_ENV)
477     if ((pw = getpwuid(_GET_D_UID(dp))) != 0)
478         printf("%s ", pw->pw_name);
479     else
480         printf("%d ", _GET_D_UID(dp));
481 #else /* AFS_HPUX102_ENV */
482     if ((pw = getpwuid((int)dp->di_uid)) != 0)
483         printf("%s ", pw->pw_name);
484     else
485         printf("%d ", dp->di_uid);
486 #endif /* else AFS_HPUX102_ENV */
487 #endif /* else AFS_HPUX110_ENV */
488     printf("MODE=%o\n", dp->di_mode);
489     if (preen)
490         printf("%s: ", devname);
491 #if     defined(AFS_SUN56_ENV)
492     printf("SIZE=%" AFS_INT64_FMT " ", dp->di_size);
493 #else
494     printf("SIZE=%ld ", dp->di_size);
495 #endif
496     t = dp->di_mtime;
497     p = ctime(&t);
498     printf("MTIME=%12.12s %4.4s ", p + 4, p + 20);
499 }
500
501 blkerror(ino, type, blk)
502      ino_t ino;
503      char *type;
504      daddr_t blk;
505 {
506
507     pfatal("%ld %s I=%u", blk, type, ino);
508     printf("\n");
509     switch (statemap[ino]) {
510
511 #ifdef VICE
512     case VSTATE:
513 #endif /* VICE */
514     case FSTATE:
515 #if defined(ACLS) && defined(AFS_HPUX_ENV)
516         /*
517          *  Keep the continuation inode info
518          */
519         if (statemap[ino] & HASCINODE)
520             statemap[ino] = FCLEAR | HASCINODE;
521         else
522             statemap[ino] = FCLEAR;
523 #else /* no ACLS */
524         statemap[ino] = FCLEAR;
525 #endif /* ACLS */
526         return;
527
528     case DSTATE:
529 #if defined(ACLS) && defined(AFS_HPUX_ENV)
530         /*
531          *  Keep the continuation inode info
532          */
533         if (statemap[ino] & HASCINODE)
534             statemap[ino] = DCLEAR | HASCINODE;
535         else
536             statemap[ino] = DCLEAR;
537 #else /* no ACLS */
538         statemap[ino] = DCLEAR;
539 #endif /* ACLS */
540         return;
541
542     case FCLEAR:
543     case DCLEAR:
544         return;
545
546     default:
547         errexit("BAD STATE %d TO BLKERR", statemap[ino]);
548         /* NOTREACHED */
549     }
550 }
551
552 /*
553  * allocate an unused inode
554  */
555 ino_t
556 allocino(request, type)
557      ino_t request;
558      int type;
559 {
560     ino_t ino;
561     struct dinode *dp;
562
563     if (request == 0)
564         request = ROOTINO;
565     else if (statemap[request] != USTATE)
566         return (0);
567     for (ino = request; ino < maxino; ino++)
568         if (statemap[ino] == USTATE)
569             break;
570     if (ino == maxino)
571         return (0);
572     switch (type & IFMT) {
573     case IFDIR:
574         statemap[ino] = DSTATE;
575         break;
576     case IFREG:
577     case IFLNK:
578         statemap[ino] = FSTATE;
579         break;
580     default:
581         return (0);
582     }
583     dp = ginode(ino);
584     dp->di_db[0] = allocblk((long)1);
585     if (dp->di_db[0] == 0) {
586         statemap[ino] = USTATE;
587         return (0);
588     }
589     dp->di_mode = type;
590     time(&dp->di_atime);
591     dp->di_mtime = dp->di_ctime = dp->di_atime;
592     dp->di_size = sblock.fs_fsize;
593     dp->di_blocks = btodb(sblock.fs_fsize);
594
595     n_files++;
596     inodirty();
597     return (ino);
598 }
599
600 /*
601  * deallocate an inode
602  */
603 freeino(ino)
604      ino_t ino;
605 {
606     struct inodesc idesc;
607     extern int pass4check();
608     struct dinode *dp;
609
610     memset(&idesc, 0, sizeof(struct inodesc));
611     idesc.id_type = ADDR;
612     idesc.id_func = pass4check;
613     idesc.id_number = ino;
614     dp = ginode(ino);
615     (void)ckinode(dp, &idesc);
616 #ifdef VICE
617     zapino(dp);
618 #else /* VICE */
619     clearinode(dp);
620 #endif /* VICE */
621     inodirty();
622     statemap[ino] = USTATE;
623     n_files--;
624 }