include-afsconfig-before-param-h-20010712
[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("$Header$");
22
23 #define VICE    /* control whether AFS changes are present */
24 #include <stdio.h>
25
26 #include <sys/time.h>
27 #include <sys/param.h>
28
29 #ifdef  AFS_OSF_ENV
30 #include <sys/mount.h>
31 #include <sys/vnode.h>
32 #include <ufs/inode.h>
33 #include <ufs/fs.h>
34 #define _BSD
35 #define _KERNEL
36 #include <ufs/dir.h>
37 #undef  _KERNEL
38 #undef  _BSD
39 #else   /* AFS_OSF_ENV */
40 #ifdef AFS_VFSINCL_ENV
41 #define VFS
42 #include <sys/vnode.h>
43 #ifdef    AFS_SUN5_ENV
44 #include <sys/fs/ufs_inode.h>
45 #include <sys/fs/ufs_fs.h>
46 #define _KERNEL
47 #include <sys/fs/ufs_fsdir.h>
48 #undef _KERNEL
49 #else
50 #include <ufs/inode.h>
51 #define KERNEL
52 #include <ufs/fsdir.h>
53 #undef  KERNEL
54 #include <ufs/fs.h>
55 #endif
56 #else /* AFS_VFSINCL_ENV */
57 #include <sys/inode.h>
58 #ifdef  AFS_HPUX_ENV
59 #include <ctype.h>
60 #define LONGFILENAMES   1
61 #include <sys/sysmacros.h>
62 #include <sys/ino.h>
63 #define DIRSIZ_MACRO
64 #include <ndir.h>
65 #else
66 #include <sys/dir.h>
67 #endif
68 #include <sys/fs.h>
69 #endif /* AFS_VFSINCL_ENV */
70 #endif  /* AFS_OSF_ENV */
71
72 #include <afs/osi_inode.h>
73 #include <pwd.h>
74 #include "fsck.h"
75
76 #ifdef AFS_SUN_ENV
77 #ifdef  AFS_SUN5_ENV
78 #include <sys/mnttab.h>
79 #include <sys/mntent.h>
80 #else
81 #include <mntent.h>
82 #endif
83 #endif /* AFS_SUN_ENV */
84
85 struct bufarea *pbp = 0;
86
87 ckinode(dp, idesc)
88         struct dinode *dp;
89         register struct inodesc *idesc;
90 {
91         register daddr_t *ap;
92         long ret, n, ndb, offset;
93         struct dinode dino;
94         UOFF_T  indir_data_blks;
95         extern int pass1check();
96
97 #ifdef  AFS_HPUX_ENV
98         if (FASTLNK)
99             return (KEEPON);
100 #endif
101         idesc->id_fix = DONTKNOW;
102         idesc->id_entryno = 0;
103         idesc->id_filesize = dp->di_size;
104         if ((dp->di_mode & IFMT) == IFBLK || (dp->di_mode & IFMT) == IFCHR)
105                 return (KEEPON);
106 #ifdef  AFS_OSF_ENV
107         if ((dp->di_flags & IC_FASTLINK) != 0) {
108             return(KEEPON);
109         }
110 #endif  /* AFS_OSF_ENV */
111         dino = *dp;
112         ndb = howmany(dino.di_size, (UOFF_T)sblock.fs_bsize);
113         ap = &dino.di_db[0];
114 #ifdef AFS_OSF_ENV
115         /*
116          * Check property lists on pass1
117          */
118         if (idesc->id_func == pass1check &&
119             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 = NDADDR + NINDIR(&sblock) +
158                             (NINDIR(&sblock) * NINDIR(&sblock));
159                 }
160                 if (*ap) {
161                         idesc->id_blkno = *ap;
162                         ret = iblock(idesc, n,
163                             (u_offset_t)howmany(dino.di_size,
164                             (u_offset_t)sblock.fs_bsize) - indir_data_blks);
165                         if (ret & STOP)
166                                 return (ret);
167                 }
168         }
169 #else
170         for (ap = &dino.di_ib[0], n = 1; n <= NIADDR; ap++, n++) {
171                 if (*ap) {
172                         idesc->id_blkno = *ap;
173                         ret = iblock(idesc, n,
174                                 dino.di_size - sblock.fs_bsize * NDADDR);
175                         if (ret & STOP)
176                                 return (ret);
177                 }
178         }
179 #endif
180         return (KEEPON);
181 }
182
183 iblock(idesc, ilevel, isize)
184         struct inodesc *idesc;
185         register long ilevel;
186         UOFF_T isize;
187 {
188         register daddr_t *ap;
189         register daddr_t *aplim;
190         int i, n, (*func)();
191         UOFF_T  sizepb;
192         OFF_T   nif;
193         register struct bufarea *bp;
194         char buf[BUFSIZ];
195         extern int dirscan(), pass1check();
196
197         if (idesc->id_type == ADDR) {
198                 func = idesc->id_func;
199                 if (((n = (*func)(idesc)) & KEEPON) == 0)
200                         return (n);
201         } else
202                 func = dirscan;
203         if (chkrange(idesc->id_blkno, idesc->id_numfrags))
204                 return (SKIP);
205         bp = getdatablk(idesc->id_blkno, sblock.fs_bsize);
206         ilevel--;
207 #if     defined(AFS_SUN56_ENV)
208         for (sizepb = 1, i = 0; i < ilevel; i++) {
209                 sizepb *= (u_offset_t)NINDIR(&sblock);
210         }
211
212         /*
213          * nif indicates the next "free" pointer (as an array index) in this
214          * indirect block, based on counting the blocks remaining in the
215          * file after subtracting all previously processed blocks.
216          * This figure is based on the size field of the inode.
217          *
218          * Note that in normal operation, nif may initially calculated to
219          * be larger than the number of pointers in this block; if that is
220          * the case, nif is limited to the max number of pointers per
221          * indirect block.
222          *
223          * Also note that if an inode is inconsistant (has more blocks
224          * allocated to it than the size field would indicate), the sweep
225          * through any indirect blocks directly pointed at by the inode
226          * continues. Since the block offset of any data blocks referenced
227          * by these indirect blocks is greater than the size of the file,
228          * the index nif may be computed as a negative value.
229          * In this case, we reset nif to indicate that all pointers in
230          * this retrieval block should be zeroed and the resulting
231          * unreferenced data and/or retrieval blocks be recovered
232          * through garbage collection later.
233          */
234         nif = (offset_t)howmany(isize, sizepb);
235         if (nif > NINDIR(&sblock))
236                 nif = NINDIR(&sblock);
237         else if (nif < 0)
238                 nif = 0;
239 #else
240         for (sizepb = sblock.fs_bsize, i = 0; i < ilevel; i++)
241                 sizepb *= (UOFF_T)NINDIR(&sblock);
242         nif = isize / sizepb + 1;
243         if (nif > NINDIR(&sblock))
244                 nif = NINDIR(&sblock);
245 #endif
246         if (idesc->id_func == pass1check && nif < NINDIR(&sblock)) {
247                 aplim = &bp->b_un.b_indir[NINDIR(&sblock)];
248                 for (ap = &bp->b_un.b_indir[nif]; ap < aplim; ap++) {
249                         if (*ap == 0)
250                                 continue;
251                         (void)sprintf(buf, "PARTIALLY TRUNCATED INODE I=%d",
252                                 idesc->id_number);
253                         if (dofix(idesc, buf)) {
254                                 *ap = 0;
255                                 dirty(bp);
256                         }
257                 }
258                 flush(fswritefd, bp);
259         }
260         aplim = &bp->b_un.b_indir[nif];
261         for (ap = bp->b_un.b_indir, i = 1; ap < aplim; ap++, i++) {
262                 if (*ap) {
263                         idesc->id_blkno = *ap;
264                         if (ilevel > 0) {
265 #if     defined(AFS_SUN56_ENV)
266                                 n = iblock(idesc, ilevel, isize);
267                                 /*
268                                  * each iteration decrease "remaining block
269                                  * count" by however many blocks were accessible
270                                  * by a pointer at this indirect block level.
271                                  */
272                                 isize -= sizepb;
273 #else
274                                 n = iblock(idesc, ilevel, isize - i * sizepb);
275 #endif
276                         }
277                         else
278                                 n = (*func)(idesc);
279                         if (n & STOP) {
280                                 bp->b_flags &= ~B_INUSE;
281                                 return (n);
282                         }
283                 }
284         }
285         bp->b_flags &= ~B_INUSE;
286         return (KEEPON);
287 }
288
289 /*
290  * Check that a block in a legal block number.
291  * Return 0 if in range, 1 if out of range.
292  */
293 chkrange(blk, cnt)
294         daddr_t blk;
295         int cnt;
296 {
297         register int c;
298
299         if ((unsigned)(blk + cnt) > maxfsblock)
300                 return (1);
301         c = dtog(&sblock, blk);
302         if (blk < cgdmin(&sblock, c)) {
303                 if ((blk + cnt) > cgsblock(&sblock, c)) {
304                         if (debug) {
305                                 printf("blk %d < cgdmin %d;",
306                                     blk, cgdmin(&sblock, c));
307                                 printf(" blk + cnt %d > cgsbase %d\n",
308                                     blk + cnt, 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;",
316                                     blk, cgdmin(&sblock, c));
317                                 printf(" blk + cnt %d > sblock.fs_fpg %d\n",
318                                     blk+cnt, sblock.fs_fpg);
319                         }
320                         return (1);
321                 }
322         }
323         return (0);
324 }
325
326 struct dinode *
327 ginode(inumber)
328         ino_t inumber;
329 {
330         daddr_t iblk;
331
332         if (inumber < ROOTINO || inumber > maxino)
333                 errexit("bad inode number %d to ginode\n", inumber);
334         if (mlk_startinum == 0 ||
335             inumber < mlk_startinum || inumber >= mlk_startinum + INOPB(&sblock)) {
336                 iblk = itod(&sblock, inumber);
337                 if (pbp != 0)
338                         pbp->b_flags &= ~B_INUSE;
339                 pbp = getdatablk(iblk, sblock.fs_bsize);
340                 mlk_startinum = (inumber / INOPB(&sblock)) * INOPB(&sblock);
341         }
342         return (&pbp->b_un.b_dinode[inumber % INOPB(&sblock)]);
343 }
344
345 #ifdef  AFS_SUN5_ENVX
346 inocleanup()
347 {
348         register struct inoinfo **inpp;
349
350         if (inphead == NULL)
351                 return;
352         for (inpp = &inpsort[inplast - 1]; inpp >= inpsort; inpp--)
353                 free((char *)(*inpp));
354         free((char *)inphead);
355         free((char *)inpsort);
356         inphead = inpsort = NULL;
357 }
358 #endif
359
360 inodirty()
361 {
362         
363         dirty(pbp);
364 }
365
366 clri(idesc, type, flag)
367         register struct inodesc *idesc;
368         char *type;
369         int flag;
370 {
371         register struct dinode *dp;
372 #if defined(ACLS) && defined(AFS_HPUX_ENV)
373         struct inodesc cidesc;
374 #endif /* ACLS */
375
376         dp = ginode(idesc->id_number);
377         if (flag == 1) {
378                 pwarn("%s %s", type,
379                     (dp->di_mode & IFMT) == IFDIR ? "DIR" : "FILE");
380                 pinode(idesc->id_number);
381 #if defined(ACLS) && defined(AFS_HPUX_ENV)
382         } else if (flag == 2) {
383                 pwarn("%s %s", type, "CONTINUATION INODE ");
384                 printf(" I=%u ", idesc->id_number);
385 #endif /* ACLS */
386         }
387         if (preen || reply("CLEAR") == 1) {
388                 if (preen)
389                         printf(" (CLEARED)\n");
390 #if defined(ACLS) && defined(AFS_HPUX_ENV)
391                 if (CONT)
392                         n_cont--;
393                 else
394                         n_files--;
395
396                 /*
397                  * If there is a CI associated with this inode, we must 
398                  * clear it as well.  
399                  */
400                 if (statemap[idesc->id_number] & HASCINODE) {
401                     if (!(dp->di_contin < ROOTINO || dp->di_contin > maxino))
402                         cidesc.id_number = dp->di_contin;
403                         clri(&cidesc, "UNREF", 2);
404                 }
405 #else /* no ACLS */
406                 n_files--;
407 #endif /* ACLS */
408                 (void)ckinode(dp, idesc);
409 #ifdef  VICE
410                 zapino(dp);
411 #else /* VICE */
412                 clearinode(dp);
413 #endif /* VICE */
414                 statemap[idesc->id_number] = USTATE;
415                 inodirty();
416         }
417 }
418
419 findname(idesc)
420         struct inodesc *idesc;
421 {
422         register struct direct *dirp = idesc->id_dirp;
423
424         if (dirp->d_ino != idesc->id_parent)
425                 return (KEEPON);
426         bcopy(dirp->d_name, idesc->id_name, (int)dirp->d_namlen + 1);
427         return (STOP|FOUND);
428 }
429
430 findino(idesc)
431         struct inodesc *idesc;
432 {
433         register struct direct *dirp = idesc->id_dirp;
434
435         if (dirp->d_ino == 0)
436                 return (KEEPON);
437         if (strcmp(dirp->d_name, idesc->id_name) == 0 &&
438             dirp->d_ino >= ROOTINO && dirp->d_ino <= maxino) {
439                 idesc->id_parent = dirp->d_ino;
440                 return (STOP|FOUND);
441         }
442         return (KEEPON);
443 }
444
445 pinode(ino)
446         ino_t ino;
447 {
448         register struct dinode *dp;
449         register char *p;
450         struct passwd *pw;
451         char *ctime();
452
453         printf(" I=%u ", ino);
454         if (ino < ROOTINO || ino > maxino)
455                 return;
456         dp = ginode(ino);
457         printf(" OWNER=");
458 #if     defined(AFS_HPUX110_ENV)
459         {
460            char uidbuf[BUFSIZ];
461            char *p;
462            uid_t uid;
463            if (dp == NULL) {
464               pwarn("Could not getinode(%d) in pinode.", ino);
465               return;
466            }
467            uid = _GET_D_UID(dp);
468            if (getpw(uid, uidbuf) == 0) {
469               for (p = uidbuf; *p != ':'; p++);
470               *p = 0;
471               printf("%s ", uidbuf);
472            } else {
473               printf("%d ", uid);
474            }
475         }
476 #else   /* AFS_HPUX110_ENV */
477 #if     defined(AFS_HPUX102_ENV)
478         if ((pw = getpwuid(_GET_D_UID(dp))) != 0)
479                 printf("%s ", pw->pw_name);
480         else
481                 printf("%d ", _GET_D_UID(dp));
482 #else   /* AFS_HPUX102_ENV */
483         if ((pw = getpwuid((int)dp->di_uid)) != 0)
484                 printf("%s ", pw->pw_name);
485         else
486                 printf("%d ", dp->di_uid);
487 #endif  /* else AFS_HPUX102_ENV */
488 #endif  /* else AFS_HPUX110_ENV */
489         printf("MODE=%o\n", dp->di_mode);
490         if (preen)
491                 printf("%s: ", devname);
492 #if     defined(AFS_SUN56_ENV)
493         printf("SIZE=%lld ", dp->di_size);
494 #else
495         printf("SIZE=%ld ", dp->di_size);
496 #endif
497         p = ctime(&dp->di_mtime);
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         register ino_t ino;
561         register 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         bzero((char *)&idesc, 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 }