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