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