reindent-20030715
[openafs.git] / src / vol / listinodes.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 /*
11
12         System:         VICE-TWO
13         Module:         listinodes.c
14         Institution:    The Information Technology Center, Carnegie-Mellon University
15
16  */
17
18 #define ITC                     /* Required by inode.h */
19
20 #include <afsconfig.h>
21 #include <afs/param.h>
22
23 RCSID
24     ("$Header$");
25
26 #ifndef AFS_NAMEI_ENV
27 #if defined(AFS_LINUX20_ENV) || defined(AFS_SUN4_ENV)
28 /* ListViceInodes
29  *
30  * Return codes:
31  * 0 - success
32  * -1 - Unable to read the inodes.
33  * -2 - Unable to completely write temp file. Produces warning message in log.
34  */
35 int
36 ListViceInodes(char *devname, char *mountedOn, char *resultFile,
37                int (*judgeInode) (), int judgeParam, int *forcep, int forceR,
38                char *wpath)
39 {
40     Log("ListViceInodes not implemented for this platform!\n");
41     return -1;
42 }
43 #else
44 #include <ctype.h>
45 #include <sys/param.h>
46 #if defined(AFS_SGI_ENV)
47 #else
48 #ifdef  AFS_OSF_ENV
49 #include <ufs/fs.h>
50 #else /* AFS_OSF_ENV */
51 #ifdef AFS_VFSINCL_ENV
52 #define VFS
53 #ifdef    AFS_SUN5_ENV
54 #include <sys/fs/ufs_fs.h>
55 #else
56 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
57 #include <ufs/ufs/dinode.h>
58 #include <ufs/ffs/fs.h>
59 #define itod ino_to_fsba
60 #else
61 #include <ufs/fs.h>
62 #endif
63 #endif
64 #else /* AFS_VFSINCL_ENV */
65 #ifdef  AFS_AIX_ENV
66 #include <sys/filsys.h>
67 #else
68 #include <sys/fs.h>
69 #endif
70 #endif /* AFS_VFSINCL_ENV */
71 #endif /* AFS_OSF_ENV */
72 #include <sys/time.h>
73 #ifdef AFS_VFSINCL_ENV
74 #include <sys/vnode.h>
75 #ifdef    AFS_SUN5_ENV
76 #include <sys/fs/ufs_inode.h>
77 #else
78 #if !defined(AFS_DARWIN_ENV)
79 #include <ufs/inode.h>
80 #endif
81 #endif
82 #else /* AFS_VFSINCL_ENV */
83 #ifdef AFS_DEC_ENV
84 #include <sys/time.h>
85 #endif /* AFS_DEC_ENV */
86 #ifdef  AFS_OSF_ENV
87 #include <ufs/inode.h>
88 #else /* AFS_OSF_ENV */
89 #include <sys/inode.h>
90 #endif
91 #endif /* AFS_VFSINCL_ENV */
92 #endif /* AFS_SGI_ENV */
93 #include <afs/osi_inode.h>
94 #include <sys/file.h>
95 #include <stdio.h>
96 #include <rx/xdr.h>
97 #include <afs/afsint.h>
98 #include "nfs.h"
99 #include <afs/afssyscalls.h>
100 #include "viceinode.h"
101 #include <sys/stat.h>
102 #if defined (AFS_AIX_ENV) || defined (AFS_HPUX_ENV)
103 #include <sys/ino.h>
104 #endif
105 #ifdef AFS_PTHREAD_ENV
106 #include <assert.h>
107 #else /* AFS_PTHREAD_ENV */
108 #include <afs/assert.h>
109 #endif /* AFS_PTHREAD_ENV */
110 #if defined(AFS_HPUX101_ENV)
111 #include <unistd.h>
112 #endif
113 #include "partition.h"
114
115 /* Notice:  parts of this module have been cribbed from vfsck.c */
116
117 #define ROOTINODE       2
118 static char *partition;
119 extern int Testing;
120 int pfd;
121
122 #ifdef  AFS_AIX32_ENV
123 #include <jfs/filsys.h>
124
125 #ifndef FSBSIZE
126 #define FSBSIZE         (4096)  /* filesystem block size        */
127 #define FSBSHIFT        (12)    /* log2(FSBSIZE)                */
128 #define FSBMASK         (FSBSIZE - 1)   /* FSBSIZE mask                 */
129
130 #define MIN_FSIZE       DISKMAP_B       /* minimum fs size (FSblocks)   */
131 #define LAST_RSVD_I     15      /* last reserved inode          */
132 #endif
133
134 #ifndef INOPB
135 /*
136  * This will hopefully eventually make it into the system include files
137  */
138 #define INOPB           (FSBSIZE / sizeof (struct dinode))
139 #endif
140
141 #ifdef AFS_AIX41_ENV
142 int fragsize;
143 int iagsize;
144 int ag512;
145 int agblocks;
146 #endif /* AFS_AIX41_ENV */
147
148 /*
149  XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
150  XX This was lifted from some `com/cmd/fs/fshlpr_aix3/Fs.h', which indicated X
151  XX a longing to see it make it into a readily accessible include file. XXXXXX
152  XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
153  *
154  * itoo - inode number to offset within disk block
155  */
156 #undef itoo
157 #define itoo(x)         (int) ((unsigned)(x) % INOPB)
158
159 int Bsize = FSBSIZE;            /* block size for this system                   */
160 daddr_t fmax;                   /* total number of blocks n file system         */
161 ino_t imax, inum;               /* total number of I-nodes in file system       */
162
163 static struct superblock fs;
164 struct dinode *ginode();
165
166
167 int
168 ListViceInodes(char *devname, char *mountedOn, char *resultFile,
169                int (*judgeInode) (), int judgeParam, int *forcep, int forceR,
170                char *wpath)
171 {
172     FILE *inodeFile = NULL;
173     char dev[50], rdev[51];
174     struct stat status;
175     struct dinode *p;
176     struct ViceInodeInfo info;
177     struct stat root_inode;
178     int ninodes = 0, err = 0;
179
180     pfd = -1;                   /* initialize so we don't close on error output below. */
181     *forcep = 0;
182     sync();
183     sleep(1);                   /* simulate operator    */
184     sync();
185     sleep(1);
186     sync();
187     sleep(1);
188
189     partition = mountedOn;
190     sprintf(dev, "/dev/%s", devname);
191     sprintf(rdev, "/dev/r%s", devname);
192
193     if (stat(mountedOn, &root_inode) < 0) {
194         Log("cannot stat: %s\n", mountedOn);
195         return -1;
196     }
197
198     if (root_inode.st_ino != ROOTDIR_I) {
199         Log("%s is not root of a filesystem\n", mountedOn);
200         return -1;
201     }
202
203
204     /*
205      * done with the superblock, now try to read the raw device.
206      */
207     if (ReadSuper(&fs, dev) < 0)
208         return -1;
209
210     switch (fs.s_fmod) {
211     default:
212     case FM_CLEAN:              /* clean and unmounted                  */
213         Log("Most peculiar - Super blk in FM_CLEAN state!\n");
214         goto out;
215     case FM_MOUNT:              /* mounted cleanly                      */
216         break;
217
218     case FM_MDIRTY:             /* dirty when mounted or commit fail    */
219     case FM_LOGREDO:            /* log redo attempted but failed        */
220         Log("File system %s is in a bad state.\n", rdev);
221         Log("Call your IBM representative.\n");
222         return -1;
223     }
224 #ifdef AFS_AIX42_ENV
225     if (IsBigFilesFileSystem(&fs, (char *)0)) {
226         Log("%s is a big files filesystem, can't salvage.\n", mountedOn);
227         return -1;
228     }
229 #else
230     if (strncmp(fs.s_magic, fsv3magic, strlen(fsv3magic)) != 0) {
231 #ifdef  AFS_AIX41_ENV
232         if ((strncmp(fs.s_magic, fsv3pmagic, strlen(fsv3pmagic)) != 0)
233             || (fs.s_version != fsv3pvers)) {
234             Log("Super block doesn't have the problem magic (%s vs v3magic %s v3pmagic %s)\n", fs.s_magic, fsv3magic, fsv3pmagic);
235             return -1;
236         }
237 #else
238         Log("Super block doesn't have the problem magic (%s vs v3magic %s)\n",
239             fs.s_magic, fsv3magic);
240         return -1;
241 #endif
242     }
243 #endif
244
245 #ifdef AFS_AIX41_ENV
246     fragsize = (fs.s_fragsize) ? fs.s_fragsize : FSBSIZE;
247     iagsize = (fs.s_iagsize) ? fs.s_iagsize : fs.s_agsize;
248     ag512 = fragsize * fs.s_agsize / 512;
249     agblocks = fragsize * fs.s_agsize >> BSHIFT;
250 #endif /* AFS_AIX41_ENV */
251
252     fmax = fs.s_fsize / (FSBSIZE / 512);        /* first invalid blk num */
253
254     pfd = open(rdev, O_RDONLY);
255     if (pfd < 0) {
256         Log("Unable to open `%s' inode for reading\n", rdev);
257         return -1;
258     }
259
260     inodeFile = fopen(resultFile, "w");
261     if (inodeFile == NULL) {
262         Log("Unable to create inode description file %s\n", resultFile);
263         goto out;
264     }
265
266     /*
267      * calculate the maximum number of inodes possible
268      */
269 #ifdef AFS_AIX41_ENV
270     imax = iagsize * (fs.s_fsize / ag512) - 1;
271 #else /* AFS_AIX41_ENV */
272     imax =
273         ((fmax / fs.s_agsize +
274           ((fmax % fs.s_agsize) >= fs.s_agsize / INOPB ? 1 : 0))
275          * fs.s_agsize) - 1;
276 #endif /* AFS_AIX41_ENV */
277
278     /*
279      * check for "FORCESALVAGE" equivalent:
280      *      LAST_RSVD_I is a vice inode, with dead beef, and
281      *      di_nlink == 2 to indicate the FORCE.
282      */
283     assert(p = ginode(LAST_RSVD_I));
284
285     if (p->di_vicemagic == VICEMAGIC && p->di_vicep1 == 0xdeadbeef
286         && p->di_nlink == 2) {
287         *forcep = 1;
288         idec(root_inode.st_dev, LAST_RSVD_I, 0xdeadbeef);
289     }
290
291     for (inum = LAST_RSVD_I + 1; inum <= imax; ++inum) {
292         if ((p = ginode(inum)) == NULL || p->di_vicemagic != VICEMAGIC
293             || (p->di_mode & IFMT) != IFREG)
294             continue;
295
296         info.inodeNumber = inum;
297         info.byteCount = p->di_size;
298         info.linkCount = p->di_nlink;
299         info.u.param[0] = p->di_vicep1;
300         info.u.param[1] = p->di_vicep2;
301         info.u.param[2] = p->di_vicep3;
302         info.u.param[3] = p->di_vicep4;
303
304         if (judgeInode && (*judgeInode) (&info, judgeParam) == 0)
305             continue;
306
307         if (fwrite(&info, sizeof info, 1, inodeFile) != 1) {
308             Log("Error writing inode file for partition %s\n", partition);
309             goto out;
310         }
311         ++ninodes;
312     }
313
314     if (fflush(inodeFile) == EOF) {
315         Log("Unable to successfully flush inode file for %s\n", partition);
316         err = -2;
317         goto out1;
318     }
319     if (fsync(fileno(inodeFile)) == -1) {
320         Log("Unable to successfully fsync inode file for %s\n", partition);
321         err = -2;
322         goto out1;
323     }
324     if (fclose(inodeFile) == EOF) {
325         Log("Unable to successfully close inode file for %s\n", partition);
326         err = -2;
327         goto out1;
328     }
329
330     /*
331      * Paranoia:  check that the file is really the right size
332      */
333     if (stat(resultFile, &status) == -1) {
334         Log("Unable to successfully stat inode file for %s\n", partition);
335         err = -2;
336         goto out1;
337     }
338     if (status.st_size != ninodes * sizeof(struct ViceInodeInfo)) {
339         Log("Wrong size (%d instead of %d) in inode file for %s\n",
340             status.st_size, ninodes * sizeof(struct ViceInodeInfo),
341             partition);
342         err = -2;
343         goto out1;
344     }
345     close(pfd);
346     return 0;
347
348   out:
349     err = -1;
350   out1:
351     if (pfd >= 0)
352         close(pfd);
353     if (inodeFile)
354         fclose(inodeFile);
355
356     return err;
357 }
358
359 /* Read in the superblock for devName */
360 int
361 ReadSuper(struct superblock *fs, char *devName)
362 {
363     int pfd;
364
365     pfd = open(devName, O_RDONLY);
366     if (pfd < 0) {
367         Log("Unable to open inode on %s for reading superblock.\n", devName);
368         return -1;
369     }
370
371     if (bread(pfd, fs, SUPER_B, sizeof(struct superblock)) < 0) {
372         Log("Unable to read superblock on %s.\n", devName);
373         return -1;
374     }
375     close(pfd);
376     return (0);
377 }
378
379 #ifdef AFS_AIX42_ENV
380 /* IsBigFilesFileSystem returns 1 if it's a big files filesystem, 0 otherwise. */
381 int
382 IsBigFilesFileSystem(struct superblock *sb)
383 {
384     if ((strncmp(sb->s_magic, fsv3pmagic, 4) == 0)
385         && (sb->s_version == fsbigfile)
386         && (sb->s_bigexp))
387         return 1;
388     else
389         return 0;
390 }
391 #endif
392
393 struct dinode *
394 ginode(inum)
395 {
396     int ag;
397     daddr_t pblk;
398     struct dinode *dp;
399     static char buf[FSBSIZE];
400     static daddr_t last_blk = -1;
401
402 #ifdef AFS_AIX41_ENV
403     ag = inum / iagsize;
404     pblk =
405         (ag ==
406          0) ? INODES_B + inum / INOPB : ag * agblocks + (inum -
407                                                          ag * iagsize) /
408         INOPB;
409 #else /* AFS_AIX41_ENV */
410     ag = inum / fs.s_agsize;
411     pblk =
412         (ag ==
413          0) ? INODES_B + inum / INOPB : ag * fs.s_agsize + (inum -
414                                                             ag *
415                                                             fs.s_agsize) /
416         INOPB;
417 #endif /* AFS_AIX41_ENV */
418
419     if (last_blk != pblk) {
420         if (bread(pfd, buf, pblk, sizeof(buf)) < 0) {
421             last_blk = -1;
422             return 0;
423         }
424         last_blk = pblk;
425     }
426
427     dp = (struct dinode *)buf;
428     dp += itoo(inum);
429     return (dp);
430 }
431
432 #else /* !AFS_AIX31_ENV       */
433
434 #if defined(AFS_SGI_ENV)
435
436 /* libefs.h includes <assert.h>, which we don't want */
437 #define __ASSERT_H__
438
439 #ifdef AFS_SGI_EFS_IOPS_ENV
440 #include "sgiefs/libefs.h"
441 extern int Log();
442
443 /* afs_efs_figet() replaces the SGI library routine because we are malloc'ing
444  * memory for all the inodes on all the cylinder groups without releasing
445  * it when we're done. Using afs_efs_figet ensures more efficient use of
446  * memory.
447  */
448 struct efs_dinode *
449 afs_efs_figet(EFS_MOUNT * mp, struct efs_dinode *dinodeBuf, int *last_cgno,
450               ino_t inum)
451 {
452     int cgno = EFS_ITOCG(mp->m_fs, inum);
453
454
455     if (cgno != *last_cgno) {
456         if (efs_readb
457             (mp->m_fd, (char *)dinodeBuf, EFS_CGIMIN(mp->m_fs, cgno),
458              mp->m_fs->fs_cgisize) != mp->m_fs->fs_cgisize) {
459             Log("Unable to read inodes for cylinder group %d.\n", cgno);
460             return NULL;
461         }
462         *last_cgno = cgno;
463     }
464
465     return dinodeBuf + (inum % (mp->m_fs->fs_cgisize * EFS_INOPBB));
466 }
467
468
469 int
470 efs_ListViceInodes(char *devname, char *mountedOn, char *resultFile,
471                    int (*judgeInode) (), int judgeParam, int *forcep,
472                    int forceR, char *wpath)
473 {
474     FILE *inodeFile = NULL;
475     char dev[50], rdev[51];
476     struct stat status;
477     struct efs_dinode *p;
478     struct ViceInodeInfo info;
479     int ninodes = 0, err = 0;
480     struct efs_dinode *dinodeBuf = NULL;
481     int last_cgno;
482     EFS_MOUNT *mp;
483     ino_t imax, inum;           /* total number of I-nodes in file system */
484
485     *forcep = 0;
486
487     partition = mountedOn;
488     sprintf(dev, "/dev/dsk/%s", devname);
489     sprintf(rdev, "/dev/rdsk/%s", devname);
490
491
492     /*
493      * open raw device
494      */
495     efs_init(Log);
496     if ((stat(rdev, &status) == -1)
497         || ((mp = efs_mount(rdev, O_RDONLY)) == NULL)) {
498         sprintf(rdev, "/dev/r%s", devname);
499         mp = efs_mount(rdev, O_RDONLY);
500     }
501     if (mp == NULL) {
502         Log("Unable to open `%s' inode for reading\n", rdev);
503         return -1;
504     }
505
506     inodeFile = fopen(resultFile, "w");
507     if (inodeFile == NULL) {
508         Log("Unable to create inode description file %s\n", resultFile);
509         goto out;
510     }
511
512     /* Allocate space for one cylinder group's worth of inodes. */
513     dinodeBuf = (struct efs_dinode *)malloc(mp->m_fs->fs_cgisize * BBSIZE);
514     if (!dinodeBuf) {
515         Log("Unable to malloc %lu bytes for inode buffer.\n",
516             mp->m_fs->fs_cgisize * BBSIZE);
517         goto out;
518     }
519
520     /*
521      * calculate the maximum number of inodes possible
522      */
523     imax = mp->m_fs->fs_ncg * mp->m_fs->fs_ipcg;
524
525     last_cgno = -1;
526     for (inum = 2; inum < imax; ++inum) {
527         p = afs_efs_figet(mp, dinodeBuf, &last_cgno, inum);
528         if (!p) {
529             Log("Unable to read all inodes from partition.\n");
530             goto out;
531         }
532         if (!IS_DVICEMAGIC(p) || !((p->di_mode & IFMT) == IFREG)) {
533             continue;
534         }
535 #if defined(AFS_SGI_EXMAG)
536         /* volume ID */
537         info.u.param[0] =
538             dmag(p, 0) << 24 | dmag(p, 1) << 16 | dmag(p, 2) << 8 | dmag(p,
539                                                                          3) <<
540             0;
541         if ((p)->di_version == EFS_IVER_AFSSPEC) {
542             info.u.param[1] = INODESPECIAL;
543             /* type */
544             info.u.param[2] = dmag(p, 8);
545             /* parentId */
546             info.u.param[3] =
547                 dmag(p, 4) << 24 | dmag(p, 5) << 16 | dmag(p,
548                                                            6) << 8 | dmag(p,
549                                                                           7)
550                 << 0;
551         } else {
552             /* vnode number */
553             info.u.param[1] =
554                 dmag(p, 4) << 16 | dmag(p, 5) << 8 | dmag(p, 6) << 0;
555             /* disk uniqifier */
556             info.u.param[2] =
557                 dmag(p, 7) << 16 | dmag(p, 8) << 8 | dmag(p, 9) << 0;
558             /* data version */
559             info.u.param[3] =
560                 dmag(p, 10) << 16 | dmag(p, 11) << 8 | (p)->di_spare;
561         }
562 #else
563         BOMB ! !
564 #endif
565             info.inodeNumber = inum;
566         info.byteCount = p->di_size;
567         info.linkCount = p->di_nlink;
568 #ifdef notdef
569         Log("Ino=%d, bytes=%d, linkCnt=%d, [%x,%x,%x,%x]\n", inum, p->di_size,
570             p->di_nlink, info.u.param[0], info.u.param[1], info.u.param[2],
571             info.u.param[3]);
572 #endif
573         if (judgeInode && (*judgeInode) (&info, judgeParam) == 0)
574             continue;
575
576         if (fwrite(&info, sizeof info, 1, inodeFile) != 1) {
577             Log("Error writing inode file for partition %s\n", partition);
578             goto out;
579         }
580         ++ninodes;
581     }
582
583     if (fflush(inodeFile) == EOF) {
584         Log("Unable to successfully flush inode file for %s\n", partition);
585         err = -2;
586         goto out1;
587     }
588     if (fsync(fileno(inodeFile)) == -1) {
589         Log("Unable to successfully fsync inode file for %s\n", partition);
590         err = -2;
591         goto out1;
592     }
593     if (fclose(inodeFile) == EOF) {
594         Log("Unable to successfully close inode file for %s\n", partition);
595         err = -2;
596         goto out1;
597     }
598
599     /*
600      * Paranoia:  check that the file is really the right size
601      */
602     if (stat(resultFile, &status) == -1) {
603         Log("Unable to successfully stat inode file for %s\n", partition);
604         err = -2;
605         goto out1;
606     }
607     if (status.st_size != ninodes * sizeof(struct ViceInodeInfo)) {
608         Log("Wrong size (%d instead of %d) in inode file for %s\n",
609             status.st_size, ninodes * sizeof(struct ViceInodeInfo),
610             partition);
611         err = -2;
612         goto out1;
613     }
614     efs_umount(mp);
615     if (dinodeBuf) {
616         free(dinodeBuf);
617     }
618     return 0;
619
620   out:
621     err = -1;
622   out1:
623     if (dinodeBuf) {
624         free(dinodeBuf);
625     }
626     efs_umount(mp);
627     if (inodeFile)
628         fclose(inodeFile);
629
630     return err;
631 }
632 #endif /* AFS_SGI_EFS_IOPS_ENV */
633
634 #ifdef AFS_SGI_XFS_IOPS_ENV
635 #include <dirent.h>
636 #include <afs/xfsattrs.h>
637 /* xfs_ListViceInodes
638  *
639  * xfs_ListViceInodes verifies and correct the XFS namespace as it collects
640  * the inode information. The name is required for the idec operation to work. 
641  * Steps 2 and 3 below are for the AFS_XFS_NAME_VERS == 1. If the name space
642  * changes, the algorithm will need to change. 
643  * 1) If the parent inode number does not match the directory's inod number,
644  *    change it in the attribute.
645  * 2) If the unqifier in the attribute does not match the name, rename the
646  *    file. This is done by doing an exclusive open, incrementing the tag
647  *    number until a file can be created. If the tag changes, then the
648  *    attribute will need updating.
649  * 3) If the tag in the attribute does not match the name, change the
650  *    attribute.
651  * 4) Verify uid = RW volume id and gid = XFS_VICEMAGIC.
652  *
653  */
654
655 /* xfs_VerifyInode
656  * 
657  * Does the verifications listed above.
658  * We can't change the names until the readdir is complete, so we set the
659  * rename flag if the file needs renaming.
660  */
661 int
662 xfs_VerifyInode(char *dir, uint64_t pino, char *name, i_list_inode_t * info,
663                 int *rename)
664 {
665     char path[1024];
666     int vno;
667     int update_pino = 0;
668     int update_tag = 0;
669     int update_chown = 0;
670     int retCode = 0;
671     char tmpName[32];
672     b64_string_t stmp;
673     int tag;
674
675     *rename = 0;
676     (void)sprintf(path, "%s/%s", dir, name);
677     /* Verify uid and gid fields */
678     if (info->ili_magic != XFS_VICEMAGIC) {
679         Log("%s  magic for %s/%s (inode %s) from %d to %d\n",
680             Testing ? "Would have changed" : "Changing", dir, name,
681             PrintInode(NULL, info->ili_info.inodeNumber), info->ili_magic,
682             XFS_VICEMAGIC);
683         if (!Testing)
684             update_chown = 1;
685     }
686
687     vno = info->ili_info.param[0];
688     if (info->ili_vno != AFS_XFS_VNO_CLIP(vno)) {
689         Log("%s volume id for %s/%s (inode %s) from %d to %d\n",
690             Testing ? "Would have changed" : "Changing", dir, name,
691             PrintInode(NULL, info->ili_info.inodeNumber), info->ili_vno,
692             AFS_XFS_VNO_CLIP(vno));
693         if (!Testing)
694             update_chown = 1;
695     }
696
697     if (update_chown) {
698         if (chown(path, AFS_XFS_VNO_CLIP(vno), XFS_VICEMAGIC) < 0) {
699             Log("Can't chown %s to uid=%d, gid=0x%x\n", path,
700                 AFS_XFS_VNO_CLIP(vno), XFS_VICEMAGIC);
701             retCode = -1;
702         }
703     }
704
705     /* Check Parent inode number. */
706     if (info->ili_pino != pino) {
707         afs_ino_str_t sino, sipino, spino;
708         (void)PrintInode(sino, info->ili_info.inodeNumber);
709         (void)PrintInode(sipino, info->ili_pino);
710         (void)PrintInode(spino, pino);
711         Log("%s parent ino for %s (inode %s) from %s to %s.\n",
712             Testing ? "Would have changed" : "Changing", path, sino, sipino,
713             spino);
714         if (!Testing)
715             update_pino = 1;
716     }
717
718     /* Verify the file name. */
719     (void)strcpy(tmpName, ".");
720     (void)strcat(tmpName, int_to_base64(stmp, info->ili_info.param[2]));
721     if (strncmp(name, tmpName, strlen(tmpName))) {
722         Log("%s name %s (inode %s) in directory %s, unique=%d, tag=%d\n",
723             Testing ? "Would have returned bad" : "Bad", name,
724             PrintInode(NULL, info->ili_info.inodeNumber), dir,
725             info->ili_info.param[2], info->ili_tag);
726         if (!Testing)
727             *rename = 1;
728     }
729
730     if (!*rename) {
731         /* update the tag? */
732         (void)strcat(tmpName, ".");
733         (void)strcat(tmpName, int_to_base64(stmp, info->ili_tag));
734         if (strcmp(name, tmpName)) {
735             char *p;
736             (void)strcpy(tmpName, name);
737             p = strchr(tmpName + 1, '.');
738             if (!p) {
739                 Log("No tag found on name %s (inode %s)in directory, %s.\n",
740                     name, PrintInode(NULL, info->ili_info.inodeNumber), dir,
741                     Testing ? "would have renamed" : "will rename");
742                 if (!Testing)
743                     *rename = 1;
744             } else {
745                 tag = base64_to_int(p + 1);
746                 Log("%s the tag for %s (inode %s) from %d to %d.\n",
747                     Testing ? "Would have changed" : "Will change", path,
748                     PrintInode(NULL, info->ili_info.inodeNumber), dir, tag,
749                     info->ili_tag);
750                 if (!Testing)
751                     update_tag = 1;
752             }
753         }
754     }
755
756     if (update_pino || update_tag) {
757         afs_xfs_attr_t attrs;
758         int length;
759
760         length = SIZEOF_XFS_ATTR_T;
761         if (attr_get(path, AFS_XFS_ATTR, (char *)&attrs, &length, ATTR_ROOT) <
762             0) {
763             Log("Can't get AFS attribute for %s\n", path);
764             return -1;
765         }
766         if (update_pino)
767             attrs.at_pino = pino;
768         if (update_tag)
769             attrs.at_tag = tag;
770         if (attr_set
771             (path, AFS_XFS_ATTR, (char *)&attrs, length,
772              ATTR_ROOT | ATTR_REPLACE) < 0) {
773             Log("Can't set AFS attribute into %s\n", path);
774             retCode = -1;
775         }
776     }
777
778     return retCode;
779 }
780
781 typedef struct {
782     int uniq;
783     char name[28];
784 } xfs_Rename_t;
785
786 int
787 xfs_RenameFiles(char *dir, xfs_Rename_t * renames, int n_renames)
788 {
789     int i, j;
790     char opath[128], nbase[128], npath[128];
791     afs_xfs_attr_t attrs;
792     int length = SIZEOF_XFS_ATTR_T;
793     b64_string_t stmp;
794     int tag;
795     int fd;
796
797     for (i = 0; i < n_renames; i++) {
798         (void)sprintf(opath, "%s/%s", dir, renames[i].name);
799         (void)sprintf(nbase, "%s/.%s", dir,
800                       int_to_base64(stmp, renames[i].uniq));
801         for (tag = 2, j = 0; j < 64; tag++, j++) {
802             (void)sprintf(npath, "%s.%s", nbase, int_to_base64(stmp, tag));
803             fd = open(npath, O_CREAT | O_EXCL | O_RDWR, 0);
804             if (fd > 0) {
805                 close(fd);
806                 break;
807             }
808         }
809         if (j != 64) {
810             Log("Can't find a new name for %s\n", opath);
811             return -1;
812         }
813         if (rename(opath, npath) < 0) {
814             Log("Can't rename %s to %s\n", opath, npath);
815             return -1;
816         }
817         Log("Renamed %s to %s\n", opath, npath);
818         return 0;
819     }
820 }
821
822
823 int
824 xfs_ListViceInodes(char *devname, char *mountedOn, char *resultFile,
825                    int (*judgeInode) (), int judgeParam, int *forcep,
826                    int forceR, char *wpath)
827 {
828     FILE *inodeFile = NULL;
829     i_list_inode_t info;
830     int info_size = sizeof(i_list_inode_t);
831     int fd;
832     DIR *top_dirp;
833     dirent64_t *top_direntp;
834     DIR *vol_dirp;
835     dirent64_t *vol_direntp;
836     struct stat64 sdirbuf;
837     struct stat64 sfilebuf;
838     afs_xfs_attr_t attrs;
839     afs_xfs_dattr_t dattrs;
840     int length;
841     char vol_dirname[1024];
842     int ninodes = 0;
843     int code = 0;
844     xfs_Rename_t *renames = (xfs_Rename_t *) 0;
845     int rename;
846 #define N_RENAME_STEP 64
847     int n_renames = 0;
848     int n_avail = 0;
849     uint64_t pino;
850     struct stat status;
851     int errors = 0;
852
853     *forcep = 0;
854
855     if (stat64(mountedOn, &sdirbuf) < 0) {
856         perror("xfs_ListViceInodes: stat64");
857         return -1;
858     }
859
860     inodeFile = fopen(resultFile, "w");
861     if (inodeFile == NULL) {
862         Log("Unable to create inode description file %s\n", resultFile);
863         return -1;
864     }
865
866     if ((top_dirp = opendir(mountedOn)) == NULL) {
867         Log("Can't open directory %s to read inodes.\n", mountedOn);
868         return -1;
869     }
870
871     while (top_direntp = readdir64(top_dirp)) {
872         /* Only descend directories with the AFSDIR attribute set.
873          * Could also verify the contents of the atribute, but currently
874          * they are not used.
875          * Performance could be improved for single volume salvages by
876          * only going through the directory containing the volume's inodes.
877          * But I'm being complete as a first pass.
878          */
879         (void)sprintf(vol_dirname, "%s/%s", mountedOn, top_direntp->d_name);
880         length = SIZEOF_XFS_DATTR_T;
881         if (attr_get
882             (vol_dirname, AFS_XFS_DATTR, (char *)&dattrs, &length, ATTR_ROOT))
883             continue;
884
885         if ((vol_dirp = opendir(vol_dirname)) == NULL) {
886             if (errno == ENOTDIR)
887                 continue;
888             Log("Can't open directory %s to read inodes.\n", vol_dirname);
889             goto err1_exit;
890         }
891
892         pino = top_direntp->d_ino;
893         n_renames = 0;
894         while (vol_direntp = readdir64(vol_dirp)) {
895             if (vol_direntp->d_name[1] == '\0'
896                 || vol_direntp->d_name[1] == '.')
897                 continue;
898
899             info.ili_version = AFS_XFS_ILI_VERSION;
900             info_size = sizeof(i_list_inode_t);
901             code =
902                 ilistinode64(sdirbuf.st_dev, vol_direntp->d_ino, &info,
903                              &info_size);
904             if (code) {
905                 /* Where possible, give more explicit messages. */
906                 switch (errno) {
907                 case ENXIO:
908                 case ENOSYS:
909                     Log("%s (device id %d) is not on an XFS filesystem.\n",
910                         vol_dirname, sdirbuf.st_dev);
911                     goto err1_exit;
912                     break;
913                 case EINVAL:
914                 case E2BIG:
915                     if (info_size != sizeof(i_list_inode_t)
916                         || info.ili_version != AFS_XFS_ILI_VERSION) {
917                         Log("Version skew between kernel and salvager.\n");
918                         goto err1_exit;
919                     }
920                     break;
921                 }
922                 /* Continue, so we collect all the errors in the first pass. */
923                 Log("Error listing inode named %s/%s: %s\n", vol_dirname,
924                     vol_direntp->d_name, strerror(errno));
925                 errors++;
926                 continue;
927             }
928
929             if (info.ili_attr_version != AFS_XFS_ATTR_VERS) {
930                 Log("Unrecognized XFS attribute version %d in %s/%s. Upgrade salvager\n", info.ili_attr_version, vol_dirname, vol_direntp->d_name);
931                 goto err1_exit;
932             }
933
934             if (judgeInode && (*judgeInode) (&info.ili_info, judgeParam) == 0)
935                 continue;
936
937             rename = 0;
938             if (xfs_VerifyInode
939                 (vol_dirname, pino, vol_direntp->d_name, &info,
940                  &rename) < 0) {
941                 errors++;
942             }
943
944             if (rename) {
945                 /* Add this name to the list of items to rename. */
946                 if (n_renames >= n_avail) {
947                     n_avail += N_RENAME_STEP;
948                     if (n_avail == N_RENAME_STEP)
949                         renames = (xfs_Rename_t *)
950                             malloc(n_avail * sizeof(xfs_Rename_t));
951                     else
952                         renames = (xfs_Rename_t *)
953                             realloc((char *)renames,
954                                     n_avail * sizeof(xfs_Rename_t));
955                     if (!renames) {
956                         Log("Can't %salloc %lu bytes for rename list.\n",
957                             (n_avail == N_RENAME_STEP) ? "m" : "re",
958                             n_avail * sizeof(xfs_Rename_t));
959                         goto err1_exit;
960                     }
961                 }
962                 (void)strcpy(renames[n_renames].name, vol_direntp->d_name);
963                 renames[n_renames].uniq = info.ili_info.param[2];
964                 n_renames++;
965             }
966
967             if (fwrite
968                 (&info.ili_info, sizeof(vice_inode_info_t), 1, inodeFile)
969                 != 1) {
970                 Log("Error writing inode file for partition %s\n", mountedOn);
971                 goto err1_exit;
972             }
973             ninodes++;
974
975         }                       /* end while vol_direntp */
976
977         closedir(vol_dirp);
978         vol_dirp = (DIR *) 0;
979         if (n_renames) {
980             Log("Renaming files.\n");
981             if (xfs_RenameFiles(vol_dirname, renames, n_renames) < 0) {
982                 goto err1_exit;
983             }
984         }
985     }
986
987     closedir(top_dirp);
988     if (renames)
989         free((char *)renames);
990     if (fflush(inodeFile) == EOF) {
991         ("Unable to successfully flush inode file for %s\n", mountedOn);
992         fclose(inodeFile);
993         return errors ? -1 : -2;
994     }
995     if (fsync(fileno(inodeFile)) == -1) {
996         Log("Unable to successfully fsync inode file for %s\n", mountedOn);
997         fclose(inodeFile);
998         return errors ? -1 : -2;
999     }
1000     if (fclose(inodeFile) == EOF) {
1001         Log("Unable to successfully close inode file for %s\n", mountedOn);
1002         return errors ? -1 : -2;
1003     }
1004     /*
1005      * Paranoia:  check that the file is really the right size
1006      */
1007     if (stat(resultFile, &status) == -1) {
1008         Log("Unable to successfully stat inode file for %s\n", partition);
1009         return errors ? -1 : -2;
1010     }
1011     if (status.st_size != ninodes * sizeof(struct ViceInodeInfo)) {
1012         Log("Wrong size (%d instead of %d) in inode file for %s\n",
1013             status.st_size, ninodes * sizeof(struct ViceInodeInfo),
1014             partition);
1015         return errors ? -1 : -2;
1016     }
1017
1018     if (errors) {
1019         Log("Errors encontered listing inodes, not salvaging partition.\n");
1020         return -1;
1021     }
1022
1023     return 0;
1024
1025   err1_exit:
1026     if (vol_dirp)
1027         closedir(vol_dirp);
1028     if (top_dirp)
1029         closedir(top_dirp);
1030     if (renames)
1031         free((char *)renames);
1032     if (inodeFile)
1033         fclose(inodeFile);
1034     return -1;
1035 }
1036
1037 #endif
1038
1039 int
1040 ListViceInodes(char *devname, char *mountedOn, char *resultFile,
1041                int (*judgeInode) (), int judgeParam, int *forcep, int forceR,
1042                char *wpath)
1043 {
1044     FILE *inodeFile = NULL;
1045     char dev[50], rdev[51];
1046     struct stat status;
1047     struct efs_dinode *p;
1048     struct ViceInodeInfo info;
1049     struct stat root_inode;
1050     int ninodes = 0, err = 0;
1051     struct efs_dinode *dinodeBuf = NULL;
1052     int last_cgno;
1053 #ifdef AFS_SGI_EFS_IOPS_ENV
1054     EFS_MOUNT *mp;
1055 #endif
1056     ino_t imax, inum;           /* total number of I-nodes in file system */
1057
1058     *forcep = 0;
1059     sync();
1060     sleep(1);                   /* simulate operator    */
1061     sync();
1062     sleep(1);
1063     sync();
1064     sleep(1);
1065
1066     if (stat(mountedOn, &root_inode) < 0) {
1067         Log("cannot stat: %s\n", mountedOn);
1068         return -1;
1069     }
1070 #ifdef AFS_SGI_XFS_IOPS_ENV
1071     if (!strcmp("xfs", root_inode.st_fstype)) {
1072         return xfs_ListViceInodes(devname, mountedOn, resultFile, judgeInode,
1073                                   judgeParam, forcep, forceR, wpath);
1074     } else
1075 #endif
1076 #ifdef AFS_SGI_EFS_IOPS_ENV
1077     if (root_inode.st_ino == EFS_ROOTINO) {
1078         return efs_ListViceInodes(devname, mountedOn, resultFile, judgeInode,
1079                                   judgeParam, forcep, forceR, wpath);
1080     } else
1081 #endif
1082     {
1083         Log("%s is not root of a filesystem\n", mountedOn);
1084         return -1;
1085     }
1086 }
1087
1088 #else /* AFS_SGI_ENV */
1089
1090 #ifdef AFS_HPUX_ENV
1091 #define SPERB   (MAXBSIZE / sizeof(short))
1092 #define MAXNINDIR (MAXBSIZE / sizeof(daddr_t))
1093
1094 struct bufarea {
1095     struct bufarea *b_next;     /* must be first */
1096     daddr_t b_bno;
1097     int b_size;
1098     union {
1099         char b_buf[MAXBSIZE];   /* buffer space */
1100         short b_lnks[SPERB];    /* link counts */
1101         daddr_t b_indir[MAXNINDIR];     /* indirect block */
1102         struct fs b_fs;         /* super block */
1103         struct cg b_cg;         /* cylinder group */
1104     } b_un;
1105     char b_dirty;
1106 };
1107 typedef struct bufarea BUFAREA;
1108
1109 BUFAREA sblk;
1110 #define sblock sblk.b_un.b_fs
1111 #endif /* AFS_HPUX_ENV */
1112
1113 extern char *afs_rawname();
1114 int
1115 ListViceInodes(char *devname, char *mountedOn, char *resultFile,
1116                int (*judgeInode) (), int judgeParam, int *forcep, int forceR,
1117                char *wpath)
1118 {
1119     union {
1120 #ifdef  AFS_AIX_ENV
1121         struct filsys fs;
1122         char block[BSIZE];
1123 #else                           /* !AFS_AIX_ENV */
1124         struct fs fs;
1125         char block[SBSIZE];
1126 #endif
1127     } super;
1128     int i, c, e, bufsize, code, err = 0;
1129     FILE *inodeFile = NULL;
1130     char dev[50], rdev[100], err1[512], *ptr1;
1131     struct dinode *inodes = NULL, *einodes, *dptr;
1132     struct stat status;
1133     int ninodes = 0;
1134     struct dinode *p;
1135     struct ViceInodeInfo info;
1136
1137     *forcep = 0;
1138     partition = mountedOn;
1139     sprintf(rdev, "%s/%s", wpath, devname);
1140     ptr1 = afs_rawname(rdev);
1141     strcpy(rdev, ptr1);
1142
1143     sync();
1144     /* Bletch:  this is terrible;  is there a better way to do this? Does this work? vfsck doesn't even sleep!! */
1145 #ifdef  AFS_AIX_ENV
1146     sleep(5);                   /* Trying a smaller one for aix */
1147 #else
1148     sleep(10);
1149 #endif
1150
1151     pfd = open(rdev, O_RDONLY);
1152     if (pfd <= 0) {
1153         sprintf(err1, "Could not open device %s to get inode list\n", rdev);
1154         perror(err1);
1155         return -1;
1156     }
1157 #ifdef  AFS_AIX_ENV
1158     if (bread(pfd, (char *)&super.fs, SUPERB, sizeof super.fs) == -1) {
1159 #else
1160 #ifdef AFS_HPUX_ENV
1161     if (bread(pfd, (char *)&sblock, SBLOCK, SBSIZE) == -1) {
1162 #else
1163     if (bread(pfd, super.block, SBLOCK, SBSIZE) == -1) {
1164 #endif /* AFS_HPUX_ENV */
1165 #endif
1166         Log("Unable to read superblock, partition %s\n", partition);
1167         goto out;
1168     }
1169
1170     inodeFile = fopen(resultFile, "w");
1171     if (inodeFile == NULL) {
1172         Log("Unable to create inode description file %s\n", resultFile);
1173         goto out;
1174     }
1175 #ifdef  AFS_AIX_ENV
1176     /*
1177      * char *FSlabel(), *fslabel=0;
1178      * fslabel = FSlabel(&super.fs);
1179      */
1180     if (super.fs.s_bsize == 0)
1181         super.fs.s_bsize = 512;
1182     if (super.fs.s_bsize != BSIZE) {
1183         Log("SuperBlk: Cluster size not %d; run vfsck\n", BSIZE);
1184         goto out;
1185     }
1186     fmax = super.fs.s_fsize;    /* first invalid blk num */
1187     imax = ((ino_t) super.fs.s_isize - (SUPERB + 1)) * INOPB;
1188     if (imax == 0) {
1189         Log("Size check: imax==0!\n");
1190         goto out;
1191     }
1192     if (GetAuxInodeFile(partition, &status) == 0) {
1193         Log("Can't access Aux inode file for partition %s, aborting\n",
1194             partition);
1195         goto out;
1196     }
1197     for (inum = 1; inum <= imax; inum++) {
1198         struct dauxinode *auxp;
1199         if ((auxp = IsAfsInode(inum)) == NULL) {
1200             /* Not an afs inode, keep going */
1201             continue;
1202         }
1203         if ((p = ginode(inum)) == NULL)
1204             continue;
1205         /* deleted/non-existent inode when di_mode == 0 */
1206         if (!p->di_mode)
1207             continue;
1208         info.inodeNumber = (int)inum;
1209         info.byteCount = p->di_size;
1210         info.linkCount = p->di_nlink;
1211         info.u.param[0] = auxp->aux_param1;
1212         info.u.param[1] = auxp->aux_param2;
1213         info.u.param[2] = auxp->aux_param3;
1214         info.u.param[3] = auxp->aux_param4;
1215         if (judgeInode && (*judgeInode) (&info, judgeParam) == 0)
1216             continue;
1217         if (fwrite(&info, sizeof info, 1, inodeFile) != 1) {
1218             Log("Error writing inode file for partition %s\n", partition);
1219             goto out;
1220         }
1221         ninodes++;
1222     }
1223 #else
1224     /*
1225      * run a few consistency checks of the superblock
1226      * (Cribbed from vfsck)
1227      */
1228 #ifdef AFS_HPUX_ENV
1229 #if defined(FD_FSMAGIC)
1230     if ((sblock.fs_magic != FS_MAGIC) && (sblock.fs_magic != FS_MAGIC_LFN)
1231         && (sblock.fs_magic != FD_FSMAGIC)
1232 #if     defined(AFS_HPUX101_ENV)
1233         && (sblock.fs_magic != FD_FSMAGIC_2)
1234 #endif
1235         ) {
1236 #else
1237     if ((sblock.fs_magic != FS_MAGIC) && (sblock.fs_magic != FS_MAGIC_LFN)) {
1238 #endif
1239         Log("There's something wrong with the superblock for partition %s; bad magic (%d) run vfsck\n", partition, sblock.fs_magic);
1240         goto out;
1241     }
1242     if (sblock.fs_ncg < 1) {
1243         Log("There's something wrong with the superblock for partition %s; NCG OUT OF RANGE (%d) run vfsck\n", partition, sblock.fs_ncg);
1244         goto out;
1245     }
1246     if (sblock.fs_cpg < 1 || sblock.fs_cpg > MAXCPG) {
1247         Log("There's something wrong with the superblock for partition %s; CPG OUT OF RANGE (%d) run vfsck\n", partition, sblock.fs_cpg);
1248         goto out;
1249     }
1250     if (sblock.fs_ncg * sblock.fs_cpg < sblock.fs_ncyl
1251         || (sblock.fs_ncg - 1) * sblock.fs_cpg >= sblock.fs_ncyl) {
1252         Log("There's something wrong with the superblock for partition %s; NCYL LESS THAN NCG*CPG run vfsck\n", partition);
1253         goto out;
1254     }
1255     if (sblock.fs_sbsize > SBSIZE) {
1256         Log("There's something wrong with the superblock for partition %s; bsize too large (%d vs. %d) run vfsck\n", partition, sblock.fs_sbsize, sblock.fs_bsize);
1257         goto out;
1258     }
1259 #else
1260     if ((super.fs.fs_magic != FS_MAGIC)
1261         || (super.fs.fs_ncg < 1)
1262 #if     defined(AFS_SUN_ENV) || defined(AFS_OSF_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
1263         || (super.fs.fs_cpg < 1)
1264 #else
1265         || (super.fs.fs_cpg < 1 || super.fs.fs_cpg > MAXCPG)
1266 #endif
1267         || (super.fs.fs_ncg * super.fs.fs_cpg < super.fs.fs_ncyl
1268             || (super.fs.fs_ncg - 1) * super.fs.fs_cpg >= super.fs.fs_ncyl)
1269         || (super.fs.fs_sbsize > SBSIZE)) {
1270         Log("There's something wrong with the superblock for partition %s; run vfsck\n", partition);
1271         goto out;
1272     }
1273 #endif /* AFS_HPUX_ENV */
1274
1275 #ifdef AFS_HPUX_ENV
1276     bufsize = sblock.fs_ipg * sizeof(struct dinode);
1277 #else
1278     bufsize = super.fs.fs_ipg * sizeof(struct dinode);
1279 #endif /* AFS_HPUX_ENV */
1280     inodes = (struct dinode *)malloc(bufsize);
1281     einodes = (struct dinode *)(((char *)inodes) + bufsize);
1282     if (inodes == NULL) {
1283         Log("Unable to allocate enough memory to scan inodes; help!\n");
1284         goto out;
1285     }
1286     Log("Scanning inodes on device %s...\n", rdev);
1287 #ifdef AFS_HPUX_ENV
1288     for (c = 0; c < sblock.fs_ncg; c++) {
1289         i = c * sblock.fs_ipg;
1290         e = i + sblock.fs_ipg;
1291 #if     defined(AFS_HPUX102_ENV)
1292         if (lseek(pfd, dbtoo(fsbtodb(&sblock, itod(&sblock, i))), L_SET) ==
1293             -1) {
1294 #else
1295         if (lseek(pfd, dbtob(fsbtodb(&sblock, itod(&sblock, i))), L_SET) ==
1296             -1) {
1297 #endif
1298 #else
1299     for (c = 0; c < super.fs.fs_ncg; c++) {
1300         daddr_t dblk1;
1301 #if defined(AFS_SUN5_ENV) || defined(AFS_DARWIN_ENV)
1302         daddr_t f1;
1303 #if defined(AFS_DARWIN_ENV)
1304 #define offset_t off_t
1305 #define llseek lseek
1306 #endif
1307         offset_t off;
1308 #endif /* AFS_SUN5_ENV */
1309         i = c * super.fs.fs_ipg;
1310         e = i + super.fs.fs_ipg;
1311 #ifdef  AFS_OSF_ENV
1312         dblk1 = fsbtodb(&super.fs, itod(&super.fs, i));
1313         if (lseek(pfd, (off_t) ((off_t) dblk1 * DEV_BSIZE), L_SET) == -1) {
1314 #else
1315 #if defined(AFS_SUN5_ENV) || defined(AFS_DARWIN_ENV)
1316         f1 = fsbtodb(&super.fs, itod(&super.fs, i));
1317         off = (offset_t) f1 << DEV_BSHIFT;
1318         if (llseek(pfd, off, L_SET) == -1) {
1319 #else
1320         if (lseek(pfd, dbtob(fsbtodb(&super.fs, itod(&super.fs, i))), L_SET)
1321             == -1) {
1322 #endif /* AFS_SUN5_ENV */
1323 #endif /* AFS_OSF_ENV */
1324 #endif /* AFS_HPUX_ENV */
1325             Log("Error reading inodes for partition %s; run vfsck\n",
1326                 partition);
1327             goto out;
1328         }
1329         while (i < e) {
1330             if (!forceR) {
1331                 if (read(pfd, inodes, bufsize) != bufsize) {
1332                     Log("Error reading inodes for partition %s; run vfsck\n",
1333                         partition);
1334                     goto out;
1335                 }
1336             } else {
1337                 register int bj, bk;
1338                 dptr = inodes;
1339                 for (bj = bk = 0; bj < bufsize; bj = bj + 512, bk++) {
1340                     if ((code = read(pfd, dptr, 512)) != 512) {
1341                         Log("Error reading inode %d? for partition %s (errno = %d); run vfsck\n", bk + i, partition, errno);
1342                         if (lseek(pfd, 512, L_SET) == -1) {
1343                             Log("Lseek failed\n");
1344                             goto out;
1345                         }
1346                         dptr->di_mode = 0;
1347                         dptr++;
1348                         dptr->di_mode = 0;
1349                         dptr++;
1350                         dptr->di_mode = 0;
1351                         dptr++;
1352                         dptr->di_mode = 0;
1353                         dptr++;
1354                     } else
1355                         dptr += 4;
1356                 }
1357             }
1358             for (p = inodes; p < einodes && i < e; i++, p++) {
1359 #ifdef notdef
1360                 Log("Ino=%d, v1=%x, v2=%x, v3=%x, mode=%x size=%d, lcnt=%d\n",
1361                     i, p->di_vicep1, p->di_vicep2, p->di_vicep3, p->di_mode,
1362                     p->di_size, p->di_nlink);
1363                 printf
1364                     ("Ino=%d, v1=%x, v2=%x, v3=%x, mode=%x size=%d, lcnt=%d\n",
1365                      i, p->di_vicep1, p->di_vicep2, p->di_vicep3, p->di_mode,
1366                      p->di_size, p->di_nlink);
1367 #endif
1368 #ifdef AFS_OSF_ENV
1369 #ifdef AFS_3DISPARES
1370                 /* Check to see if this inode is a pre-"OSF1 4.0D" inode */
1371                 if ((p->di_uid || p->di_gid)
1372                     && !(p->di_flags & (IC_XUID | IC_XGID))) {
1373                     Log("Found unconverted inode %d: Use 'fs_conv_dux40D convert' on partition %s\n", i, partition);
1374                     goto out;
1375                 }
1376 #else
1377                 assert(0);      /* define AFS_3DISPARES in param.h */
1378 #endif
1379 #endif
1380 #if     defined(AFS_SUN56_ENV)
1381                 /* if this is a pre-sol2.6 unconverted inode, bail out */
1382                 {
1383                     afs_uint32 p1, p2, p3, p4;
1384                     int p5;
1385                     quad *q;
1386
1387                     q = (quad *) & (p->di_ic.ic_lsize);
1388                     p1 = p->di_gen;
1389                     p2 = p->di_ic.ic_flags;
1390                     p3 = q->val[0];
1391                     p4 = p->di_ic.ic_uid;
1392                     p5 = p->di_ic.ic_gid;
1393
1394                     if ((p2 || p3) && !p4 && (p5 == -2)) {
1395                         Log("Found unconverted inode %d\n", i);
1396                         Log("You should run the AFS file conversion utility\n");
1397                         goto out;
1398                     }
1399                 }
1400 #endif
1401                 if (IS_DVICEMAGIC(p) && (p->di_mode & IFMT) == IFREG) {
1402                     afs_uint32 p2 = p->di_vicep2, p3 = DI_VICEP3(p);
1403
1404                     info.u.param[0] = p->di_vicep1;
1405 #ifdef  AFS_3DISPARES
1406                     if (((p2 >> 3) == INODESPECIAL) && (p2 & 0x3)) {
1407                         info.u.param[1] = INODESPECIAL;
1408                         info.u.param[2] = p3;
1409                         info.u.param[3] = p2 & 0x3;
1410                     } else {
1411                         info.u.param[1] = ((p2 >> 27) << 16) + (p3 & 0xffff);
1412                         info.u.param[2] = (p2 & 0x3fffff);
1413                         info.u.param[3] =
1414                             (((p2 >> 22) & 0x1f) << 16) + (p3 >> 16);
1415                     }
1416 #else
1417                     info.u.param[1] = p->di_vicep2;
1418                     info.u.param[2] = DI_VICEP3(p);
1419                     info.u.param[3] = p->di_vicep4;
1420 #endif
1421                     info.inodeNumber = i;
1422                     info.byteCount = p->di_size;
1423                     info.linkCount = p->di_nlink;
1424                     if (judgeInode && (*judgeInode) (&info, judgeParam) == 0)
1425                         continue;
1426                     if (fwrite(&info, sizeof info, 1, inodeFile) != 1) {
1427                         Log("Error writing inode file for partition %s\n",
1428                             partition);
1429                         goto out;
1430                     }
1431                     ninodes++;
1432                 }
1433             }
1434         }
1435     }
1436     if (inodes)
1437         free(inodes);
1438 #endif
1439     if (fflush(inodeFile) == EOF) {
1440         Log("Unable to successfully flush inode file for %s\n", partition);
1441         err = -2;
1442         goto out1;
1443     }
1444     if (fsync(fileno(inodeFile)) == -1) {
1445         Log("Unable to successfully fsync inode file for %s\n", partition);
1446         err = -2;
1447         goto out1;
1448     }
1449     if (fclose(inodeFile) == EOF) {
1450         Log("Unable to successfully close inode file for %s\n", partition);
1451         err = -2;
1452         goto out1;
1453     }
1454
1455     /*
1456      * Paranoia:  check that the file is really the right size
1457      */
1458     if (stat(resultFile, &status) == -1) {
1459         Log("Unable to successfully stat inode file for %s\n", partition);
1460         err = -2;
1461         goto out1;
1462     }
1463     if (status.st_size != ninodes * sizeof(struct ViceInodeInfo)) {
1464         Log("Wrong size (%d instead of %d) in inode file for %s\n",
1465             status.st_size, ninodes * sizeof(struct ViceInodeInfo),
1466             partition);
1467         err = -2;
1468         goto out1;
1469     }
1470     close(pfd);
1471     return 0;
1472
1473   out:
1474     err = -1;
1475   out1:
1476     close(pfd);
1477     if (inodeFile)
1478         fclose(inodeFile);
1479     if (inodes)
1480         free(inodes);
1481     return err;
1482 }
1483 #endif /* !AFS_SGI_ENV */
1484 #endif /* !AFS_AIX31_ENV       */
1485
1486 #ifdef AFS_DARWIN_ENV
1487 #undef dbtob
1488 #define dbtob(db) ((unsigned)(db) << DEV_BSHIFT)
1489 #endif
1490
1491 int
1492 bread(int fd, char *buf, daddr_t blk, afs_int32 size)
1493 {
1494 #ifdef  AFS_AIX_ENV
1495 #ifdef  AFS_AIX41_ENV
1496     offset_t off = (offset_t) blk << FSBSHIFT;
1497     if (llseek(fd, off, 0) < 0) {
1498         Log("Unable to seek to offset %llu for block %u\n", off, blk);
1499         return -1;
1500     }
1501 #else /* AFS_AIX41_ENV */
1502     if (lseek(fd, blk * Bsize, 0) < 0) {
1503         Log("Unable to seek to offset %u for block %u\n", blk * Bsize, blk);
1504     }
1505 #endif /* AFS_AIX41_ENV */
1506 #else
1507     if (lseek(fd, (off_t) dbtob(blk), L_SET) < 0) {
1508         Log("Unable to seek to offset %u for block %u\n", dbtob(blk), blk);
1509     }
1510 #endif
1511     if (read(fd, buf, size) != size) {
1512         Log("Unable to read block %d, partition %s\n", blk, partition);
1513         return -1;
1514     }
1515     return 0;
1516 }
1517
1518 #endif /* AFS_LINUX20_ENV */
1519 #endif /* AFS_NAMEI_ENV */