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