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