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