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