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