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