2 * Copyright 2000, International Business Machines Corporation and others.
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
10 /* I/O operations for the Unix open by name (namei) interface. */
12 #include <afsconfig.h>
13 #include <afs/param.h>
37 #include <sys/param.h>
40 #include <afs/afs_assert.h>
43 #include <afs/afsutil.h>
46 #include <afs/afsint.h>
50 #include "viceinode.h"
52 #include "partition.h"
54 #include "volume_inline.h"
56 #include <afs/errors.h>
58 #include <afs/errmap_nt.h>
61 /*@+fcnmacros +macrofcndecl@*/
64 #endif /*S_SPLINT_S */
65 #define afs_stat stat64
66 #define afs_fstat fstat64
68 #define afs_open nt_open
70 #define afs_open open64
72 #define afs_fopen fopen64
73 #else /* !O_LARGEFILE */
75 #endif /*S_SPLINT_S */
77 #define afs_fstat fstat
79 #define afs_open nt_open
83 #define afs_fopen fopen
84 #endif /* !O_LARGEFILE */
85 /*@=fcnmacros =macrofcndecl@*/
88 #define LOCK_SH 1 /* shared lock */
89 #define LOCK_EX 2 /* exclusive lock */
90 #define LOCK_NB 4 /* don't block when locking */
91 #define LOCK_UN 8 /* unlock */
96 #include <afs/work_queue.h>
97 #include <afs/thread_pool.h>
98 #include <vol/vol-salvage.h>
101 #if !defined(HAVE_FLOCK) && !defined(AFS_NT40_ENV)
105 * This function emulates a subset of flock()
108 emul_flock(int fd, int cmd)
111 memset(&f, 0, sizeof (f));
120 return fcntl(fd, (cmd & LOCK_NB) ? F_SETLK : F_SETLKW, &f);
123 #define flock(f,c) emul_flock(f,c)
130 namei_iread(IHandle_t * h, afs_foff_t offset, char *buf, afs_fsize_t size)
139 nBytes = FDH_PREAD(fdP, buf, size, offset);
145 namei_iwrite(IHandle_t * h, afs_foff_t offset, char *buf, afs_fsize_t size)
154 nBytes = FDH_PWRITE(fdP, buf, size, offset);
162 /* Inode number format:
163 * low 32 bits - if a regular file or directory, the vnode; else the type.
164 * 32-36 - uniquifier tag and index into counts array for this vnode. Only
165 * two of the available bits are currently used. The rest are
166 * present in case we ever increase the number of types of volumes
167 * in the volume group.
168 * bit 37 : 1 == special, 0 == regular
170 # define NAMEI_VNODEMASK 0x00ffffffff
171 # define NAMEI_TAGSHIFT 32
172 # define NAMEI_INODESPECIAL 0x2000000000
173 # define NAMEI_SPECDIR "R"
174 # define NAMEI_SPECDIRC 'R'
175 #else /* !AFS_NT40_ENV */
176 /* Inode number format:
177 * low 26 bits - vnode number - all 1's if volume special file.
179 * next 3 bits spare (0's)
180 * high 32 bits - uniquifier (regular) or type if spare
182 # define NAMEI_VNODEMASK 0x003ffffff
183 # define NAMEI_TAGSHIFT 26
184 # define NAMEI_UNIQMASK 0xffffffff
185 # define NAMEI_UNIQSHIFT 32
186 # define NAMEI_INODESPECIAL ((Inode)NAMEI_VNODEMASK)
187 /* dir1 is the high 8 bits of the 26 bit vnode */
188 # define VNO_DIR1(vno) ((vno >> 14) & 0xff)
189 /* dir2 is the next 9 bits */
190 # define VNO_DIR2(vno) ((vno >> 9) & 0x1ff)
191 /* "name" is the low 9 bits of the vnode, the 3 bit tag and the uniq */
192 # define NAMEI_SPECDIR "special"
193 #endif /* !AFS_NT40_ENV */
194 #define NAMEI_TAGMASK 0x7
195 #define NAMEI_VNODESPECIAL NAMEI_VNODEMASK
197 #define NAMEI_SPECDIRLEN (sizeof(NAMEI_SPECDIR)-1)
199 #define NAMEI_MAXVOLS 5 /* Maximum supported number of volumes per volume
200 * group, not counting temporary (move) volumes.
201 * This is the number of separate files, all having
202 * the same vnode number, which can occur in a volume
214 static int GetFreeTag(IHandle_t * ih, int vno);
216 /* namei_HandleToInodeDir
218 * Construct the path name of the directory holding the inode data.
219 * Format: /<vicepx>/INODEDIR
224 namei_HandleToInodeDir(namei_t * name, IHandle_t * ih)
226 memset(name, '\0', sizeof(*name));
227 nt_DevToDrive(name->n_drive, ih->ih_dev);
228 strlcpy(name->n_path, name->n_drive, sizeof(name->n_path));
232 /* Format: /<vicepx>/INODEDIR */
233 #define PNAME_BLEN 64
235 namei_HandleToInodeDir(namei_t * name, IHandle_t * ih)
239 memset(name, '\0', sizeof(*name));
242 * Add the /vicepXX string to the start of name->n_base and then calculate
243 * offset as the number of bytes we know we added.
245 * FIXME: This embeds knowledge of the vice partition naming scheme and
246 * mapping from device numbers. There needs to be an API that tells us
249 volutil_PartitionName_r(ih->ih_dev, name->n_base, sizeof(name->n_base));
250 offset = VICE_PREFIX_SIZE + (ih->ih_dev > 25 ? 2 : 1);
251 name->n_base[offset] = OS_DIRSEPC;
253 strlcpy(name->n_base + offset, INODEDIR, sizeof(name->n_base) - offset);
254 strlcpy(name->n_path, name->n_base, sizeof(name->n_path));
258 #define addtoname(N, C) \
260 if ((N)->n_path[strlen((N)->n_path)-1] != OS_DIRSEPC) \
261 strlcat((N)->n_path, OS_DIRSEP, sizeof((N)->n_path)); \
262 strlcat((N)->n_path, (C), sizeof((N)->n_path)); \
268 namei_HandleToVolDir(namei_t * name, IHandle_t * ih)
270 /* X:\Vol_XXXXXXX.data */
274 namei_HandleToInodeDir(name, ih);
275 /* nt_drive added to name by namei_HandleToInodeDir() */
276 namep = name->n_voldir;
277 (void)memcpy(namep, "\\Vol_", 5);
279 (void)strcpy(namep, int_to_base32(str1, ih->ih_vid));
280 namep += strlen(namep);
281 memcpy(namep, ".data", 5);
284 addtoname(name, name->n_voldir);
288 namei_HandleToVolDir(namei_t * name, IHandle_t * ih)
292 namei_HandleToInodeDir(name, ih);
293 (void)int32_to_flipbase64(tmp, (int64_t) (ih->ih_vid & 0xff));
294 strlcpy(name->n_voldir1, tmp, sizeof(name->n_voldir1));
295 addtoname(name, name->n_voldir1);
296 (void)int32_to_flipbase64(tmp, (int64_t) ih->ih_vid);
297 strlcpy(name->n_voldir2, tmp, sizeof(name->n_voldir2));
298 addtoname(name, name->n_voldir2);
302 /* namei_HandleToName
304 * Constructs a file name for the fully qualified handle.
307 /* Note that special files end up in X:\Vol_XXXXXXX.data\R */
309 namei_HandleToName(namei_t * name, IHandle_t * ih)
311 int vno = (int)(ih->ih_ino & NAMEI_VNODEMASK);
312 int special = (ih->ih_ino & NAMEI_INODESPECIAL)?1:0;
313 int tag = (int)((ih->ih_ino >> NAMEI_TAGSHIFT) & NAMEI_TAGMASK);
316 namei_HandleToVolDir(name, ih);
319 name->n_dir[0] = NAMEI_SPECDIRC;
322 name->n_dir[0] = 'Q';
324 name->n_dir[0] = ((vno & 0x1f) >> 1) + 'A';
327 name->n_dir[1] = '\0';
328 addtoname(name, name->n_dir);
329 /* X:\Vol_XXXXXXX.data\X\V_XXXXXXX.XXX */
330 namep = name->n_inode;
331 (void)memcpy(namep, "\\V_", 3);
333 (void)strcpy(namep, int_to_base32(str1, vno));
334 namep += strlen(namep);
336 (void)strcpy(namep, int_to_base32(str1, tag));
337 namep += strlen(namep);
338 addtoname(name, name->n_inode);
341 /* Note that special files end up in /vicepX/InodeDir/Vxx/V*.data/special */
343 namei_HandleToName(namei_t * name, IHandle_t * ih)
345 int vno = (int)(ih->ih_ino & NAMEI_VNODEMASK);
348 namei_HandleToVolDir(name, ih);
350 if (vno == NAMEI_VNODESPECIAL) {
351 strlcpy(name->n_dir1, NAMEI_SPECDIR, sizeof(name->n_dir1));
352 addtoname(name, name->n_dir1);
353 name->n_dir2[0] = '\0';
355 (void)int32_to_flipbase64(str, VNO_DIR1(vno));
356 strlcpy(name->n_dir1, str, sizeof(name->n_dir1));
357 addtoname(name, name->n_dir1);
358 (void)int32_to_flipbase64(str, VNO_DIR2(vno));
359 strlcpy(name->n_dir2, str, sizeof(name->n_dir2));
360 addtoname(name, name->n_dir2);
362 (void)int64_to_flipbase64(str, (int64_t) ih->ih_ino);
363 strlcpy(name->n_inode, str, sizeof(name->n_inode));
364 addtoname(name, name->n_inode);
369 /* The following is a warning to tell sys-admins to not muck about in this
372 #define VICE_README "These files and directories are a part of the AFS \
373 namespace. Modifying them\nin any way will result in loss of AFS data,\n\
374 ownership and permissions included.\n"
376 namei_ViceREADME(char *partition)
381 /* Create the inode directory if we're starting for the first time */
382 (void)afs_snprintf(filename, sizeof filename, "%s" OS_DIRSEP "%s", partition,
384 mkdir(filename, 0700);
386 (void)afs_snprintf(filename, sizeof filename, "%s" OS_DIRSEP "%s" OS_DIRSEP "README",
387 partition, INODEDIR);
388 fd = afs_open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0444);
390 (void)write(fd, VICE_README, strlen(VICE_README));
397 /* namei_CreateDataDirectories
399 * If creating the file failed because of ENOENT or ENOTDIR, try
400 * creating all the directories first.
404 namei_CreateDataDirectories(namei_t * name, int *created)
411 afs_snprintf(tmp, 256, "%s" OS_DIRSEP "%s", name->n_drive, name->n_voldir);
413 if (mkdir(tmp) < 0) {
424 for (i = 'A'; i <= NAMEI_SPECDIRC; i++) {
426 if (mkdir(tmp) < 0 && errno != EEXIST)
432 #define create_dir() \
434 if (mkdir(tmp, 0700)<0) { \
435 if (errno != EEXIST) \
443 #define create_nextdir(A) \
445 strcat(tmp, OS_DIRSEP); strcat(tmp, A); create_dir(); \
449 namei_CreateDataDirectories(namei_t * name, int *created)
455 strlcpy(tmp, name->n_base, sizeof(tmp));
458 create_nextdir(name->n_voldir1);
459 create_nextdir(name->n_voldir2);
460 create_nextdir(name->n_dir1);
461 if (name->n_dir2[0]) {
462 create_nextdir(name->n_dir2);
469 /* delTree(): Deletes an entire tree of directories (no files)
471 * root : Full path to the subtree. Should be big enough for PATH_MAX
472 * tree : the subtree to be deleted is rooted here. Specifies only the
473 * subtree beginning at tree (not the entire path). It should be
474 * a pointer into the "root" buffer.
476 * errp : errno of the first error encountered during the directory cleanup.
477 * *errp should have been initialized to 0.
480 * -1 : If errors were encountered during cleanup and error is set to
484 * If there are errors, we try to work around them and delete as many
485 * directories as possible. We don't attempt to remove directories that still
486 * have non-dir entries in them.
489 delTree(char *root, char *tree, int *errp)
497 /* delete the children first */
498 cp = strchr(tree, OS_DIRSEPC);
500 delTree(root, cp + 1, errp);
503 cp = tree + strlen(tree); /* move cp to the end of string tree */
505 /* now delete all entries in this dir */
506 if ((ds = opendir(root)) != (DIR *) NULL) {
508 while ((dirp = readdir(ds))) {
509 /* ignore . and .. */
510 if (!strcmp(dirp->d_name, ".") || !strcmp(dirp->d_name, ".."))
512 /* since root is big enough, we reuse the space to
513 * concatenate the dirname to the current tree
515 strcat(root, OS_DIRSEP);
516 strcat(root, dirp->d_name);
517 if (afs_stat(root, &st) == 0 && S_ISDIR(st.st_mode)) {
518 /* delete this subtree */
519 delTree(root, cp + 1, errp);
521 *errp = *errp ? *errp : errno;
523 /* recover path to our cur tree by truncating it to
528 /* if (!errno) -- closedir not implicit if we got an error */
532 /* finally axe the current dir */
534 *errp = *errp ? *errp : errno;
536 #ifndef AFS_PTHREAD_ENV /* let rx get some work done */
538 #endif /* !AFS_PTHREAD_ENV */
543 /* if we encountered errors during cleanup, we return a -1 */
552 /* namei_RemoveDataDirectories
554 * Returns 0 on success.
555 * Returns -1 on error. Typically, callers ignore this error because we
556 * can continue running if the removes fail. The salvage process will
557 * finish tidying up for us.
562 namei_RemoveDataDirectories(namei_t * name)
569 afs_snprintf(tmp, 256, "%s" OS_DIRSEP "%s", name->n_drive, name->n_voldir);
572 path += strlen(path);
573 *path++ = OS_DIRSEPC;
575 for (i = 'A'; i <= NAMEI_SPECDIRC; i++) {
577 if (rmdir(name->n_path) < 0 && errno != ENOENT)
582 /* Delete the Vol_NNNNNN.data directory. */
585 if (rmdir(name->n_path) < 0 && errno != ENOENT) {
593 * We only use the n_base and n_voldir1 entries
594 * and only do rmdir's.
597 namei_RemoveDataDirectories(namei_t * name)
601 int prefixlen = strlen(name->n_base), err = 0;
602 int vollen = strlen(name->n_voldir1);
603 char pbuf[MAXPATHLEN];
607 strlcpy(path, name->n_path, sizeof(pbuf));
609 /* move past the prefix and n_voldir1 */
610 path = path + prefixlen + 1 + vollen + 1; /* skip over the trailing / */
612 /* now delete all dirs upto path */
613 code = delTree(pbuf, path, &err);
615 /* We've now deleted everything under /n_base/n_voldir1/n_voldir2 that
616 * we could. Do not delete /n_base/n_voldir1, since doing such might
617 * interrupt another thread trying to create a volume. We could introduce
618 * some locking to make this safe (or only remove it for whole-partition
619 * salvages), but by not deleting it we only leave behind a maximum of
620 * 256 empty directories. So at least for now, don't bother. */
625 /* Create the file in the name space.
627 * Parameters stored as follows:
629 * p1 - volid - implied in containing directory.
630 * p2 - vnode - name is <vno:31-23>/<vno:22-15>/<vno:15-0><uniq:31-5><tag:2-0>
631 * p3 - uniq -- bits 4-0 are in mode bits 4-0
632 * p4 - dv ---- dv:15-0 in uid, dv:29-16 in gid, dv:31-30 in mode:6-5
634 * p1 - volid - creation time - dwHighDateTime
635 * p2 - vnode - -1 means special, file goes in "S" subdirectory.
636 * p3 - type -- name is <type>.<tag> where tag is a file name unqiquifier.
637 * p4 - parid - parent volume id - implied in containing directory.
639 * Return value is the inode number or (Inode)-1 if error.
640 * We "know" there is only one link table, so return EEXIST if there already
641 * is a link table. It's up to the calling code to test errno and increment
647 * This function is called by VCreateVolume to hide the implementation
648 * details of the inode numbers. This only allows for 7 volume special
649 * types, but if we get that far, this could should be dead by then.
652 namei_MakeSpecIno(int volid, int type)
655 ino = NAMEI_INODESPECIAL;
658 /* tag is always 0 for special */
660 type &= NAMEI_TAGMASK;
661 ino |= ((Inode) type) << NAMEI_TAGSHIFT;
662 ino |= ((Inode) volid) << NAMEI_UNIQSHIFT;
670 SetOGM(FD_t fd, int parm, int tag)
676 CheckOGM(namei_t *name, FdHandle_t *fdP, int p1)
678 WIN32_FIND_DATA info;
682 FindFirstFileEx(name->n_path, FindExInfoStandard, &info,
683 FindExSearchNameMatch, NULL,
684 FIND_FIRST_EX_CASE_SENSITIVE);
687 return -1; /* Can't get info, leave alone */
691 if (info.ftCreationTime.dwHighDateTime != (unsigned int)p1)
696 #else /* AFS_NT40_ENV */
697 /* SetOGM - set owner group and mode bits from parm and tag */
699 SetOGM(FD_t fd, int parm, int tag)
702 * owner - low 15 bits of parm.
703 * group - next 15 bits of parm.
704 * mode - 2 bits of parm, then lowest = 3 bits of tag.
706 int owner, group, mode;
708 owner = parm & 0x7fff;
709 group = (parm >> 15) & 0x7fff;
710 if (fchown(fd, owner, group) < 0)
713 mode = (parm >> 27) & 0x18;
715 if (fchmod(fd, mode) < 0)
720 /* GetOGM - get parm and tag from owner, group and mode bits. */
722 GetOGMFromStat(struct afs_stat *status, int *parm, int *tag)
724 *parm = status->st_uid | (status->st_gid << 15);
725 *parm |= (status->st_mode & 0x18) << 27;
726 *tag = status->st_mode & 0x7;
730 CheckOGM(namei_t *name, FdHandle_t *fdP, int p1)
732 struct afs_stat status;
734 if (afs_fstat(fdP->fd_fd, &status) < 0)
737 GetOGMFromStat(&status, &parm, &tag);
743 #endif /* !AFS_NT40_ENV */
745 int big_vno = 0; /* Just in case we ever do 64 bit vnodes. */
747 /* Derive the name and create it O_EXCL. If that fails we have an error.
748 * Get the tag from a free column in the link table.
752 namei_icreate(IHandle_t * lh, char *part, afs_uint32 p1, afs_uint32 p2, afs_uint32 p3, afs_uint32 p4)
755 FD_t fd = INVALID_FD;
766 memset((void *)&tmp, 0, sizeof(IHandle_t));
767 memset(&tfd, 0, sizeof(FdHandle_t));
769 tmp.ih_dev = nt_DriveToDev(part);
770 if (tmp.ih_dev == -1) {
775 if (p2 == INODESPECIAL) {
776 /* Parameters for special file:
777 * p1 - volume id - goes into owner/group/mode
778 * p2 - vnode == INODESPECIAL
780 * p4 - parent volume id
782 ftime.dwHighDateTime = p1;
783 ftime.dwLowDateTime = p2;
785 tmp.ih_vid = p4; /* Use parent volume id, where this file will be. */
786 tmp.ih_ino = namei_MakeSpecIno(p1, p3);
788 int vno = p2 & NAMEI_VNODEMASK;
789 /* Parameters for regular file:
803 tmp.ih_ino = (Inode) p2;
804 ftime.dwHighDateTime = p3;
805 ftime.dwLowDateTime = p4;
808 namei_HandleToName(&name, &tmp);
809 p = strrchr((char *)&name.n_path, '.');
811 for (tag = 0; tag < NAMEI_MAXVOLS; tag++) {
812 *p = *int_to_base32(str1, tag);
813 fd = afs_open((char *)&name.n_path, O_CREAT | O_RDWR | O_TRUNC | O_EXCL, 0666);
814 if (fd == INVALID_FD) {
815 if (errno == ENOTDIR || errno == ENOENT) {
816 if (namei_CreateDataDirectories(&name, &created_dir) == 0)
817 fd = afs_open((char *)&name.n_path, O_CREAT | O_RDWR | O_TRUNC | O_EXCL, 0666);
821 if (fd != INVALID_FD)
823 if (p2 == INODESPECIAL && p3 == VI_LINKTABLE)
826 if (fd == INVALID_FD) {
830 tmp.ih_ino &= ~(((Inode) NAMEI_TAGMASK) << NAMEI_TAGSHIFT);
831 tmp.ih_ino |= (((Inode) tag) << NAMEI_TAGSHIFT);
834 if (!SetFileTime((HANDLE) fd, &ftime, NULL, NULL)) {
835 errno = OS_ERROR(EBADF);
841 if (p2 != INODESPECIAL) {
842 if (fd == INVALID_FD) {
844 code = nt_unlink((char *)&name.n_path);
853 code = namei_SetLinkCount(fdP, tmp.ih_ino, 1, 0);
855 } else if (p2 == INODESPECIAL && p3 == VI_LINKTABLE) {
856 if (fd == INVALID_FD)
858 /* hack at tmp to setup for set link count call. */
860 code = namei_SetLinkCount(&tfd, (Inode) 0, 1, 0);
865 if (fd != INVALID_FD)
868 if (code || (fd == INVALID_FD)) {
869 if (p2 != INODESPECIAL) {
872 namei_SetLinkCount(fdP, tmp.ih_ino, 0, 0);
878 int save_errno = errno;
879 namei_RemoveDataDirectories(&name);
883 return (code || (fd == INVALID_FD)) ? (Inode) -1 : tmp.ih_ino;
885 #else /* !AFS_NT40_ENV */
887 namei_icreate(IHandle_t * lh, char *part, afs_uint32 p1, afs_uint32 p2, afs_uint32 p3, afs_uint32 p4)
899 memset((void *)&tmp, 0, sizeof(IHandle_t));
900 memset(&tfd, 0, sizeof(FdHandle_t));
902 tmp.ih_dev = volutil_GetPartitionID(part);
903 if (tmp.ih_dev == -1) {
909 /* Parameters for special file:
910 * p1 - volume id - goes into owner/group/mode
913 * p4 - parent volume id
918 tmp.ih_vid = p4; /* Use parent volume id, where this file will be. */
919 tmp.ih_ino = namei_MakeSpecIno(p1, p3);
921 int vno = p2 & NAMEI_VNODEMASK;
922 /* Parameters for regular file:
934 /* If GetFreeTag succeeds, it atomically sets link count to 1. */
935 tag = GetFreeTag(lh, p2);
940 tmp.ih_ino = (Inode) p2;
941 /* name is <uniq(p3)><tag><vno(p2)> */
942 tmp.ih_ino |= ((Inode) tag) << NAMEI_TAGSHIFT;
943 tmp.ih_ino |= ((Inode) p3) << NAMEI_UNIQSHIFT;
948 namei_HandleToName(&name, &tmp);
949 fd = afs_open(name.n_path, O_CREAT | O_EXCL | O_TRUNC | O_RDWR, 0);
951 if (errno == ENOTDIR || errno == ENOENT) {
952 if (namei_CreateDataDirectories(&name, &created_dir) < 0)
954 fd = afs_open(name.n_path, O_CREAT | O_EXCL | O_TRUNC | O_RDWR,
962 if (SetOGM(fd, ogm_parm, tag) < 0) {
968 if (p2 == (afs_uint32)-1 && p3 == VI_LINKTABLE) {
969 /* hack at tmp to setup for set link count call. */
970 memset((void *)&tfd, 0, sizeof(FdHandle_t)); /* minimalistic still, but a little cleaner */
973 code = namei_SetLinkCount(&tfd, (Inode) 0, 1, 0);
981 if (code || (fd < 0)) {
985 namei_SetLinkCount(fdP, tmp.ih_ino, 0, 0);
990 return (code || (fd < 0)) ? (Inode) - 1 : tmp.ih_ino;
996 namei_iopen(IHandle_t * h)
1001 /* Convert handle to file name. */
1002 namei_HandleToName(&name, h);
1003 fd = afs_open((char *)&name.n_path, O_RDWR, 0666);
1007 /* Need to detect vol special file and just unlink. In those cases, the
1008 * handle passed in _is_ for the inode. We only check p1 for the special
1012 namei_dec(IHandle_t * ih, Inode ino, int p1)
1019 if ((ino & NAMEI_INODESPECIAL) == NAMEI_INODESPECIAL) {
1021 int type = (int)((ino >> NAMEI_TAGSHIFT) & NAMEI_TAGMASK);
1023 /* Verify this is the right file. */
1024 IH_INIT(tmp, ih->ih_dev, ih->ih_vid, ino);
1026 namei_HandleToName(&name, tmp);
1031 errno = OS_ERROR(ENOENT);
1035 if (CheckOGM(&name, fdP, p1) < 0) {
1036 FDH_REALLYCLOSE(fdP);
1038 errno = OS_ERROR(EINVAL);
1042 /* If it's the link table itself, decrement the link count. */
1043 if (type == VI_LINKTABLE) {
1044 if ((count = namei_GetLinkCount(fdP, (Inode) 0, 1, 0, 1)) < 0) {
1045 FDH_REALLYCLOSE(fdP);
1051 if (namei_SetLinkCount(fdP, (Inode) 0, count < 0 ? 0 : count, 1) <
1053 FDH_REALLYCLOSE(fdP);
1059 FDH_REALLYCLOSE(fdP);
1065 if ((code = OS_UNLINK(name.n_path)) == 0) {
1066 if (type == VI_LINKTABLE) {
1067 /* Try to remove directory. If it fails, that's ok.
1068 * Salvage will clean up.
1070 (void)namei_RemoveDataDirectories(&name);
1073 FDH_REALLYCLOSE(fdP);
1076 /* Get a file descriptor handle for this Inode */
1082 if ((count = namei_GetLinkCount(fdP, ino, 1, 0, 1)) < 0) {
1083 FDH_REALLYCLOSE(fdP);
1089 if (namei_SetLinkCount(fdP, ino, count, 1) < 0) {
1090 FDH_REALLYCLOSE(fdP);
1095 IH_INIT(th, ih->ih_dev, ih->ih_vid, ino);
1096 Log("Warning: Lost ref on ihandle dev %d vid %d ino %" AFS_INT64_FMT "\n",
1097 th->ih_dev, th->ih_vid, (afs_int64)th->ih_ino);
1100 /* If we're less than 0, someone presumably unlinked;
1101 don't bother setting count to 0, but we need to drop a lock */
1102 if (namei_SetLinkCount(fdP, ino, 0, 1) < 0) {
1103 FDH_REALLYCLOSE(fdP);
1109 IH_INIT(th, ih->ih_dev, ih->ih_vid, ino);
1111 namei_HandleToName(&name, th);
1113 code = OS_UNLINK(name.n_path);
1122 namei_inc(IHandle_t * h, Inode ino, int p1)
1128 if ((ino & NAMEI_INODESPECIAL) == NAMEI_INODESPECIAL) {
1129 int type = (int)((ino >> NAMEI_TAGSHIFT) & NAMEI_TAGMASK);
1130 if (type != VI_LINKTABLE)
1135 /* Get a file descriptor handle for this Inode */
1141 if ((count = namei_GetLinkCount(fdP, ino, 1, 0, 1)) < 0)
1146 errno = OS_ERROR(EINVAL);
1150 if (namei_SetLinkCount(fdP, ino, count, 1) < 0)
1154 FDH_REALLYCLOSE(fdP);
1161 #ifndef AFS_NT40_ENV
1163 namei_replace_file_by_hardlink(IHandle_t *hLink, IHandle_t *hTarget)
1169 /* Convert handle to file name. */
1170 namei_HandleToName(&nameLink, hLink);
1171 namei_HandleToName(&nameTarget, hTarget);
1173 OS_UNLINK(nameLink.n_path);
1174 code = link(nameTarget.n_path, nameLink.n_path);
1179 namei_copy_on_write(IHandle_t *h)
1181 afs_int32 fd, code = 0;
1184 struct afs_stat tstat;
1187 namei_HandleToName(&name, h);
1188 if (afs_stat(name.n_path, &tstat) < 0)
1190 if (tstat.st_nlink > 1) { /* do a copy on write */
1199 afs_snprintf(path, sizeof(path), "%s-tmp", name.n_path);
1200 fd = afs_open(path, O_CREAT | O_EXCL | O_TRUNC | O_RDWR, 0);
1212 size = tstat.st_size;
1215 tlen = size > 8192 ? 8192 : size;
1216 if (FDH_PREAD(fdP, buf, tlen, offset) != tlen)
1218 if (write(fd, buf, tlen) != tlen)
1224 FDH_REALLYCLOSE(fdP);
1229 OS_UNLINK(name.n_path);
1230 code = rename(path, name.n_path);
1237 /************************************************************************
1238 * File Name Structure
1239 ************************************************************************
1241 * Each AFS file needs a unique name and it needs to be findable with
1242 * minimal lookup time. Note that the constraint on the number of files and
1243 * directories in a volume is the size of the vnode index files and the
1244 * max file size AFS supports (for internal files) of 2^31. Since a record
1245 * in the small vnode index file is 64 bytes long, we can have at most
1246 * (2^31)/64 or 33554432 files. A record in the large index file is
1247 * 256 bytes long, giving a maximum of (2^31)/256 = 8388608 directories.
1248 * Another layout parameter is that there is roughly a 16 to 1 ratio between
1249 * the number of files and the number of directories.
1251 * Using this information we can see that a layout of 256 directories, each
1252 * with 512 subdirectories and each of those having 512 files gives us
1253 * 256*512*512 = 67108864 AFS files and directories.
1255 * The volume, vnode, uniquifier and data version, as well as the tag
1256 * are required, either for finding the file or for salvaging. It's best to
1257 * restrict the name to something that can be mapped into 64 bits so the
1258 * "Inode" is easily comparable (using "==") to other "Inodes". The tag
1259 * is used to distinguish between different versions of the same file
1260 * which are currently in the RW and clones of a volume. See "Link Table
1261 * Organization" below for more information on the tag. The tag is
1262 * required in the name of the file to ensure a unique name.
1264 * ifdef AFS_NT40_ENV
1265 * The data for each volume group is in a separate directory. The name of the
1266 * volume is of the form: Vol_NNNNNN.data, where NNNNNN is a base 32
1267 * representation of the RW volume ID (even where the RO is the only volume
1268 * on the partition). Below that are separate subdirectories for the
1269 * AFS directories and special files. There are also 16 directories for files,
1270 * hashed on the low 5 bits (recall bit0 is always 0) of the vnode number.
1271 * These directories are named:
1272 * A - P - 16 file directories.
1273 * Q ----- data directory
1274 * R ----- special files directory
1276 * The vnode is hashed into the directory using the low bits of the
1279 * The format of a file name for a regular file is:
1280 * Y:\Vol_NNNNNN.data\X\V_IIIIII.J
1281 * Y - partition encoded as drive letter, starting with D
1282 * NNNNNN - base 32 encoded volume number of RW volume
1283 * X - hash directory, as above
1284 * IIIIII - base 32 encoded vnode number
1285 * J - base 32 encoded tag
1287 * uniq is stored in the dwHighDateTime creation time field
1288 * dv is stored in the dwLowDateTime creation time field
1290 * Special inodes are always in the R directory, as above, and are
1292 * True child volid is stored in the dwHighDateTime creation time field
1293 * vnode number is always -1 (Special)
1294 * type is the IIIIII part of the filename
1295 * uniq is the J part of the filename
1296 * parent volume id is implied in the containing directory
1299 * We can store data in the uid, gid and mode bits of the files, provided
1300 * the directories have root only access. This gives us 15 bits for each
1301 * of uid and gid (GNU chown considers 65535 to mean "don't change").
1302 * There are 9 available mode bits. Adn we need to store a total of
1303 * 32 (volume id) + 26 (vnode) + 32 (uniquifier) + 32 (data-version) + 3 (tag)
1304 * or 131 bits somewhere.
1306 * The format of a file name for a regular file is:
1307 * /vicepX/AFSIDat/V1/V2/AA/BB/<tag><uniq><vno>
1308 * V1 - low 8 bits of RW volume id
1309 * V2 - all bits of RW volume id
1310 * AA - high 8 bits of vnode number.
1311 * BB - next 9 bits of vnode number.
1312 * <tag><uniq><vno> - file name
1314 * Volume special files are stored in a separate directory:
1315 * /vicepX/AFSIDat/V1/V2/special/<tag><uniq><vno>
1318 * The vnode is hashed into the directory using the high bits of the
1319 * vnode number. This is so that consecutively created vnodes are in
1320 * roughly the same area on the disk. This will at least be optimal if
1321 * the user is creating many files in the same AFS directory. The name
1322 * should be formed so that the leading characters are different as quickly
1323 * as possible, leading to faster discards of incorrect matches in the
1331 /************************************************************************
1332 * Link Table Organization
1333 ************************************************************************
1335 * The link table volume special file is used to hold the link counts that
1336 * are held in the inodes in inode based AFS vice filesystems. For user
1337 * space access, the link counts are being kept in a separate
1338 * volume special file. The file begins with the usual version stamp
1339 * information and is then followed by one row per vnode number. vnode 0
1340 * is used to hold the link count of the link table itself. That is because
1341 * the same link table is shared among all the volumes of the volume group
1342 * and is deleted only when the last volume of a volume group is deleted.
1344 * Within each row, the columns are 3 bits wide. They can each hold a 0 based
1345 * link count from 0 through 7. Each colume represents a unique instance of
1346 * that vnode. Say we have a file shared between the RW and a RO and a
1347 * different version of the file (or a different uniquifer) for the BU volume.
1348 * Then one column would be holding the link count of 2 for the RW and RO
1349 * and a different column would hold the link count of 1 for the BU volume.
1350 * # ifdef AFS_NT40_ENV
1351 * The column used is determined for NT by the uniquifier tag applied to
1352 * generate a unique file name in the NTFS namespace. The file name is
1353 * of the form "V_<vno>.<tag>" . And the <tag> is also the column number
1354 * in the link table.
1356 * Note that we allow only 5 volumes per file, giving 15 bits used in the
1360 #define LINKTABLE_WIDTH 2
1361 #define LINKTABLE_SHIFT 1 /* log 2 = 1 */
1364 * compute namei link table file and bit offset from inode number.
1366 * @param[in] ino inode number
1367 * @param[out] offset link table file offset
1368 * @param[out] index bit offset within 2-byte record
1373 namei_GetLCOffsetAndIndexFromIno(Inode ino, afs_foff_t * offset, int *index)
1375 int toff = (int)(ino & NAMEI_VNODEMASK);
1376 int tindex = (int)((ino >> NAMEI_TAGSHIFT) & NAMEI_TAGMASK);
1378 *offset = (afs_foff_t) ((toff << LINKTABLE_SHIFT) + 8); /* * 2 + sizeof stamp */
1379 *index = (tindex << 1) + tindex;
1382 #ifdef AFS_PTHREAD_ENV
1383 /* XXX do static initializers work for WINNT/pthread? */
1384 pthread_mutex_t _namei_glc_lock = PTHREAD_MUTEX_INITIALIZER;
1385 #define NAMEI_GLC_LOCK MUTEX_ENTER(&_namei_glc_lock)
1386 #define NAMEI_GLC_UNLOCK MUTEX_EXIT(&_namei_glc_lock)
1387 #else /* !AFS_PTHREAD_ENV */
1388 #define NAMEI_GLC_LOCK
1389 #define NAMEI_GLC_UNLOCK
1390 #endif /* !AFS_PTHREAD_ENV */
1393 * get the link count of an inode.
1395 * @param[in] h namei link count table file handle
1396 * @param[in] ino inode number for which we are requesting a link count
1397 * @param[in] lockit if asserted, return with lock held on link table file
1398 * @param[in] fixup if asserted, write 1 to link count when read() returns
1400 * @param[in] nowrite return success on zero byte read or ZLC
1402 * @post if lockit asserted and lookup was successful, will return with write
1403 * lock on link table file descriptor
1405 * @return link count
1406 * @retval -1 namei link table i/o error
1411 namei_GetLinkCount(FdHandle_t * h, Inode ino, int lockit, int fixup, int nowrite)
1413 unsigned short row = 0;
1418 /* there's no linktable yet. the salvager will create one later */
1419 if (h->fd_fd == INVALID_FD && fixup)
1421 namei_GetLCOffsetAndIndexFromIno(ino, &offset, &index);
1424 if (FDH_LOCKFILE(h, offset) != 0)
1428 rc = FDH_PREAD(h, (char*)&row, sizeof(row), offset);
1429 if ((rc == 0 || !((row >> index) & NAMEI_TAGMASK)) && fixup && nowrite)
1431 if (rc == 0 && fixup) {
1433 * extend link table and write a link count of 1 for ino
1435 * in order to make MT-safe, truncation (extension really)
1436 * must happen under a mutex
1439 if (FDH_SIZE(h) >= offset+sizeof(row)) {
1441 goto bad_getLinkByte;
1443 FDH_TRUNC(h, offset+sizeof(row));
1445 rc = FDH_PWRITE(h, (char *)&row, sizeof(row), offset);
1448 if (rc != sizeof(row)) {
1449 goto bad_getLinkByte;
1452 if (fixup && !((row >> index) & NAMEI_TAGMASK)) {
1456 * in order to make this mt-safe, we need to do the read-modify-write
1457 * under a mutex. thus, we repeat the read inside the lock.
1460 rc = FDH_PREAD(h, (char *)&row, sizeof(row), offset);
1461 if (rc == sizeof(row)) {
1463 rc = FDH_PWRITE(h, (char *)&row, sizeof(row), offset);
1466 if (rc != sizeof(row))
1467 goto bad_getLinkByte;
1470 return (int)((row >> index) & NAMEI_TAGMASK);
1474 FDH_UNLOCKFILE(h, offset);
1479 namei_SetNonZLC(FdHandle_t * h, Inode ino)
1481 return namei_GetLinkCount(h, ino, 0, 1, 0);
1484 /* Return a free column index for this vnode. */
1486 GetFreeTag(IHandle_t * ih, int vno)
1500 /* Only one manipulates at a time. */
1501 if (FDH_LOCKFILE(fdP, offset) != 0) {
1502 FDH_REALLYCLOSE(fdP);
1506 offset = (vno << LINKTABLE_SHIFT) + 8; /* * 2 + sizeof stamp */
1508 nBytes = FDH_PREAD(fdP, (char *)&row, sizeof(row), offset);
1509 if (nBytes != sizeof(row)) {
1515 /* Now find a free column in this row and claim it. */
1516 for (col = 0; col < NAMEI_MAXVOLS; col++) {
1517 coldata = 7 << (col * 3);
1518 if ((row & coldata) == 0)
1521 if (col >= NAMEI_MAXVOLS) {
1526 coldata = 1 << (col * 3);
1529 if (FDH_PWRITE(fdP, (char *)&row, sizeof(row), offset) != sizeof(row)) {
1533 FDH_UNLOCKFILE(fdP, offset);
1534 FDH_REALLYCLOSE(fdP);
1538 FDH_UNLOCKFILE(fdP, offset);
1539 FDH_REALLYCLOSE(fdP);
1545 /* namei_SetLinkCount
1546 * If locked is set, assume file is locked. Otherwise, lock file before
1547 * proceeding to modify it.
1550 namei_SetLinkCount(FdHandle_t * fdP, Inode ino, int count, int locked)
1556 ssize_t nBytes = -1;
1558 namei_GetLCOffsetAndIndexFromIno(ino, &offset, &index);
1561 if (FDH_LOCKFILE(fdP, offset) != 0) {
1566 nBytes = FDH_PREAD(fdP, (char *)&row, sizeof(row), offset);
1567 if (nBytes != sizeof(row)) {
1569 errno = OS_ERROR(EBADF);
1570 goto bad_SetLinkCount;
1575 bytesRead = 7 << index;
1577 row &= (unsigned short)~bytesRead;
1578 row |= (unsigned short)count;
1580 if (FDH_PWRITE(fdP, (char *)&row, sizeof(short), offset) != sizeof(short)) {
1581 errno = OS_ERROR(EBADF);
1582 goto bad_SetLinkCount;
1590 FDH_UNLOCKFILE(fdP, offset);
1592 /* disallowed above 7, so... */
1597 /* ListViceInodes - write inode data to a results file. */
1598 static int DecodeInode(char *dpath, char *name, struct ViceInodeInfo *info,
1599 unsigned int volid);
1600 static int DecodeVolumeName(char *name, unsigned int *vid);
1601 static int namei_ListAFSSubDirs(IHandle_t * dirIH,
1602 int (*write_fun) (FILE *,
1603 struct ViceInodeInfo *,
1604 char *, char *), FILE * fp,
1605 int (*judgeFun) (struct ViceInodeInfo *,
1606 afs_uint32 vid, void *),
1607 afs_uint32 singleVolumeNumber, void *rock);
1612 * Write the inode data to the results file.
1614 * Returns -2 on error, 0 on success.
1616 * This is written as a callback simply so that other listing routines
1617 * can use the same inode reading code.
1620 WriteInodeInfo(FILE * fp, struct ViceInodeInfo *info, char *dir, char *name)
1623 n = fwrite(info, sizeof(*info), 1, fp);
1624 return (n == 1) ? 0 : -2;
1628 int mode_errors; /* Number of errors found in mode bits on directories. */
1630 VerifyDirPerms(char *path)
1632 struct afs_stat status;
1634 if (afs_stat(path, &status) < 0) {
1635 Log("Unable to stat %s. Please manually verify mode bits for this"
1636 " directory\n", path);
1638 if (((status.st_mode & 0777) != 0700) || (status.st_uid != 0))
1644 * Fill the results file with the requested inode information.
1646 * This code optimizes single volume salvages by just looking at that one
1647 * volume's directory.
1649 * @param[in] devname device name string
1650 * @param[in] moutnedOn vice partition mount point
1651 * @param[in] resultFile result file in which to write inode
1652 * metadata. If NULL, write routine is not
1654 * @param[in] judgeInode filter function pointer. if not NULL, only
1655 * inodes for which this routine returns non-
1656 * zero will be written to the results file.
1657 * @param[in] singleVolumeNumber volume id filter
1658 * @param[out] forcep always set to 0 for namei impl
1659 * @param[in] forceR not used by namei impl
1660 * @param[in] wpath not used by namei impl
1661 * @param[in] rock opaque pointer passed to judgeInode
1663 * @return operation status
1665 * @retval -1 complete failure, salvage should terminate.
1666 * @retval -2 not enough space on partition, salvager has error message
1670 ListViceInodes(char *devname, char *mountedOn, FILE *inodeFile,
1671 int (*judgeInode) (struct ViceInodeInfo * info, afs_uint32 vid, void *rock),
1672 afs_uint32 singleVolumeNumber, int *forcep, int forceR, char *wpath,
1676 struct afs_stat status;
1678 *forcep = 0; /* no need to salvage until further notice */
1680 /* Verify protections on directories. */
1682 VerifyDirPerms(mountedOn);
1685 namei_ListAFSFiles(mountedOn, WriteInodeInfo, inodeFile, judgeInode,
1686 singleVolumeNumber, rock);
1695 if (fflush(inodeFile) == EOF) {
1696 Log("Unable to successfully flush inode file for %s\n", mountedOn);
1699 if (fsync(fileno(inodeFile)) == -1) {
1700 Log("Unable to successfully fsync inode file for %s\n", mountedOn);
1705 * Paranoia: check that the file is really the right size
1707 if (afs_fstat(fileno(inodeFile), &status) == -1) {
1708 Log("Unable to successfully stat inode file for %s\n", mountedOn);
1711 if (status.st_size != ninodes * sizeof(struct ViceInodeInfo)) {
1712 Log("Wrong size (%d instead of %lu) in inode file for %s\n",
1713 (int) status.st_size,
1714 (long unsigned int) ninodes * sizeof(struct ViceInodeInfo),
1723 * Collect all the matching AFS files on the drive.
1724 * If singleVolumeNumber is non-zero, just return files for that volume.
1726 * @param[in] dev vice partition path
1727 * @param[in] writeFun function pointer to a function which
1728 * writes inode information to FILE fp
1729 * @param[in] fp file stream where inode metadata is sent
1730 * @param[in] judgeFun filter function pointer. if not NULL,
1731 * only entries for which a non-zero value
1732 * is returned are written to fp
1733 * @param[in] singleVolumeNumber volume id filter. if nonzero, only
1734 * process files for that specific volume id
1735 * @param[in] rock opaque pointer passed into writeFun and
1738 * @return operation status
1740 * @retval >=0 number of matching files found
1743 namei_ListAFSFiles(char *dev,
1744 int (*writeFun) (FILE *, struct ViceInodeInfo *, char *,
1747 int (*judgeFun) (struct ViceInodeInfo *, afs_uint32, void *),
1748 afs_uint32 singleVolumeNumber, void *rock)
1755 #ifndef AFS_NT40_ENV
1761 static void FreeZLCList(void);
1764 memset((void *)&ih, 0, sizeof(IHandle_t));
1766 ih.ih_dev = nt_DriveToDev(dev);
1768 ih.ih_dev = volutil_GetPartitionID(dev);
1771 if (singleVolumeNumber) {
1772 ih.ih_vid = singleVolumeNumber;
1773 namei_HandleToVolDir(&name, &ih);
1775 namei_ListAFSSubDirs(&ih, writeFun, fp, judgeFun,
1776 singleVolumeNumber, rock);
1780 /* Find all volume data directories and descend through them. */
1781 namei_HandleToInodeDir(&name, &ih);
1783 dirp1 = opendir(name.n_path);
1786 while ((dp1 = readdir(dirp1))) {
1788 /* Heirarchy is one level on Windows */
1789 if (!DecodeVolumeName(dp1->d_name, &ih.ih_vid)) {
1791 namei_ListAFSSubDirs(&ih, writeFun, fp, judgeFun,
1795 if (*dp1->d_name == '.')
1797 afs_snprintf(path2, sizeof(path2), "%s" OS_DIRSEP "%s", name.n_path,
1799 dirp2 = opendir(path2);
1801 while ((dp2 = readdir(dirp2))) {
1802 if (*dp2->d_name == '.')
1804 if (!DecodeVolumeName(dp2->d_name, &ih.ih_vid)) {
1806 namei_ListAFSSubDirs(&ih, writeFun, fp, judgeFun,
1823 static void AddToZLCDeleteList(char dir, char *name);
1824 static void DeleteZLCFiles(char *path);
1828 * examine a namei volume special file.
1830 * @param[in] path1 volume special directory path
1831 * @param[in] dname directory entry name
1832 * @param[in] myIH inode handle to volume directory
1833 * @param[out] linkHandle namei link count fd handle. if
1834 * the inode in question is the link
1835 * table, then the FdHandle is populated
1836 * @param[in] writeFun metadata write function pointer
1837 * @param[in] fp file pointer where inode metadata
1838 * is written by (*writeFun)()
1839 * @param[in] judgeFun inode filter function pointer. if
1840 * not NULL, only inodes for which this
1841 * function returns non-zero are recorded
1842 * into fp by writeFun
1843 * @param[in] singleVolumeNumer volume id filter. if non-zero, only
1844 * inodes associated with this volume id
1845 * are recorded by writeFun
1846 * @param[in] rock opaque pointer passed to writeFun and
1849 * @return operation status
1850 * @retval 1 count this inode
1851 * @retval 0 don't count this inode
1852 * @retval -1 failure
1857 _namei_examine_special(char * path1,
1860 FdHandle_t * linkHandle,
1861 int (*writeFun) (FILE *, struct ViceInodeInfo *, char *,
1864 int (*judgeFun) (struct ViceInodeInfo *, afs_uint32, void *),
1865 int singleVolumeNumber,
1869 struct ViceInodeInfo info;
1870 afs_uint32 inode_vgid;
1872 if (DecodeInode(path1, dname, &info, myIH->ih_vid) < 0) {
1878 inode_vgid = myIH->ih_vid;
1880 inode_vgid = (info.inodeNumber >> NAMEI_UNIQSHIFT) & NAMEI_UNIQMASK;
1883 if (info.u.param[2] != VI_LINKTABLE) {
1885 } else if ((info.u.param[0] != myIH->ih_vid) ||
1886 (inode_vgid != myIH->ih_vid)) {
1887 /* VGID encoded in linktable filename and/or OGM data isn't
1888 * consistent with VGID encoded in namei path */
1889 Log("namei_ListAFSSubDirs: warning: inconsistent linktable "
1890 "filename \"%s" OS_DIRSEP "%s\"; salvager will delete it "
1891 "(dir_vgid=%u, inode_vgid=%u, ogm_vgid=%u)\n",
1892 path1, dname, myIH->ih_vid,
1893 (unsigned int)inode_vgid,
1897 /* Open this handle */
1898 (void)afs_snprintf(path2, sizeof(path2),
1899 "%s" OS_DIRSEP "%s", path1, dname);
1900 linkHandle->fd_fd = afs_open(path2, Testing ? O_RDONLY : O_RDWR, 0666);
1902 namei_GetLinkCount(linkHandle, (Inode) 0, 1, 1, Testing);
1906 (*judgeFun) (&info, singleVolumeNumber, rock)) {
1908 if ((*writeFun) (fp, &info, path1, dname) < 0) {
1918 * examine a namei file.
1920 * @param[in] path3 volume special directory path
1921 * @param[in] dname directory entry name
1922 * @param[in] myIH inode handle to volume directory
1923 * @param[in] linkHandle namei link count fd handle.
1924 * @param[in] writeFun metadata write function pointer
1925 * @param[in] fp file pointer where inode metadata
1926 * is written by (*writeFun)()
1927 * @param[in] judgeFun inode filter function pointer. if
1928 * not NULL, only inodes for which this
1929 * function returns non-zero are recorded
1930 * into fp by writeFun
1931 * @param[in] singleVolumeNumer volume id filter. if non-zero, only
1932 * inodes associated with this volume id
1933 * are recorded by writeFun
1934 * @param[in] rock opaque pointer passed to writeFun and
1937 * @return operation status
1938 * @retval 1 count this inode
1939 * @retval 0 don't count this inode
1940 * @retval -1 failure
1941 * @retval -2 request ZLC delete
1946 _namei_examine_reg(char * path3,
1949 FdHandle_t * linkHandle,
1950 int (*writeFun) (FILE *, struct ViceInodeInfo *, char *,
1953 int (*judgeFun) (struct ViceInodeInfo *, afs_uint32, void *),
1954 int singleVolumeNumber,
1958 struct ViceInodeInfo info;
1960 int dirl; /* Windows-only (one level hash dir) */
1963 if (DecodeInode(path3, dname, &info, myIH->ih_vid) < 0) {
1968 namei_GetLinkCount(linkHandle,
1969 info.inodeNumber, 1, 1, Testing);
1970 if (info.linkCount == 0) {
1972 Log("Found 0 link count file %s" OS_DIRSEP "%s, deleting it.\n", path3, dname);
1973 #ifdef AFS_SALSRV_ENV
1974 /* defer -- the AddToZLCDeleteList() interface is not MT-safe */
1976 #else /* !AFS_SALSRV_ENV */
1977 dirl = path3[strlen(path3)-1];
1978 AddToZLCDeleteList((char)dirl, dname);
1979 #endif /* !AFS_SALSRV_ENV */
1980 #else /* !DELETE_ZLC */
1981 Log("Found 0 link count file %s" OS_DIRSEP "%s.\n", path3,
1988 (*judgeFun) (&info, singleVolumeNumber, rock)) {
1990 if ((*writeFun) (fp, &info, path3, dname) < 0) {
2000 * listsubdirs work queue node.
2002 struct listsubdirs_work_node {
2003 #ifdef AFS_SALSRV_ENV
2004 int *error; /**< *error set if an error was
2005 * encountered in any listsubdirs
2009 IHandle_t * IH; /**< volume directory handle */
2010 FdHandle_t *linkHandle; /**< namei link count fd handle. when
2011 * examinining the link table special
2012 * inode, this will be pointed at the
2015 FILE * fp; /**< file pointer for writeFun */
2017 /** function which will write inode metadata to fp */
2018 int (*writeFun) (FILE *, struct ViceInodeInfo *, char *, char *);
2020 /** inode filter function */
2021 int (*judgeFun) (struct ViceInodeInfo *, afs_uint32, void *);
2022 int singleVolumeNumber; /**< volume id filter */
2023 void * rock; /**< pointer passed to writeFun and judgeFun */
2024 int code; /**< return code from examine function */
2025 int special; /**< asserted when this is a volume
2030 * simple wrapper around _namei_examine_special and _namei_examine_reg.
2032 * @param[in] work the struct listsubdirs_work_node for the associated
2033 * "list subdirs" job
2034 * @param[in] dir the directory to examine
2035 * @param[in] filename the filename in 'dir' to examine
2037 * @return operation status
2038 * @retval 1 count this inode
2039 * @retval 0 don't count this inode
2040 * @retval -1 failure
2043 _namei_examine_file(const struct listsubdirs_work_node *work, char *dir,
2046 if (work->special) {
2047 return _namei_examine_special(dir, filename, work->IH,
2048 work->linkHandle, work->writeFun, work->fp,
2049 work->judgeFun, work->singleVolumeNumber,
2052 return _namei_examine_reg(dir, filename, work->IH,
2053 work->linkHandle, work->writeFun, work->fp,
2054 work->judgeFun, work->singleVolumeNumber,
2060 #ifdef AFS_SALSRV_ENV
2061 /** @addtogroup afs_vol_salsrv_pario */
2065 * arguments for the _namei_examine_file_cbk callback function.
2067 struct listsubdirs_args {
2068 const struct listsubdirs_work_node *work; /**< arguments that are the same
2069 * for all invocations of
2070 * _namei_examine_file_cbk, in
2072 int *result; /**< where we can store the return code of _namei_examine_file */
2074 char dir[512]; /**< directory to examine */
2075 char filename[256]; /**< filename in 'dir' to examine */
2079 * a node in the list of results of listsubdir jobs.
2081 struct listsubdirs_result {
2083 int inodes; /**< return value from _namei_examine_file */
2087 * clean up a list of 'struct listsubdirs_result's and interpret the results.
2089 * @param[in] resultlist a list of 'struct listsubdirs_result's
2091 * @return number of inodes found
2095 _namei_listsubdirs_cleanup_results(struct rx_queue *resultlist)
2097 struct listsubdirs_result *res, *nres;
2100 for(queue_Scan(resultlist, res, nres, listsubdirs_result)) {
2102 /* noop, retain erroneous error code */
2103 } else if (res->inodes < 0) {
2118 * wait for the spawned listsubdirs jobs to finish, and return how many inodes
2121 * @param[in] queue queue to wait to finish
2122 * @param[in] resultlist list of 'struct listsubdirs_result's that the queued
2123 * jobs are storing their results in
2125 * @return number of inodes found
2129 _namei_listsubdirs_wait(struct afs_work_queue *queue, struct rx_queue *resultlist)
2133 code = afs_wq_wait_all(queue);
2138 return _namei_listsubdirs_cleanup_results(resultlist);
2142 * work queue entry point for examining namei files.
2144 * @param[in] queue pointer to struct Vwork_queue
2145 * @param[in] node pointer to struct Vwork_queue_node
2146 * @param[in] queue_rock opaque pointer to struct salsrv_pool_state
2147 * @param[in] node_rock opaque pointer to struct listsubdirs_work_node
2148 * @param[in] caller_rock opaque pointer to struct salsrv_worker_thread_state
2150 * @return operation status
2152 * @see Vwork_queue_callback_func_t
2157 _namei_examine_file_cbk(struct afs_work_queue *queue,
2158 struct afs_work_queue_node *node,
2164 struct listsubdirs_args *args = node_rock;
2165 const struct listsubdirs_work_node * work = args->work;
2166 char *dir = args->dir;
2167 char *filename = args->filename;
2169 code = _namei_examine_file(work, dir, filename);
2171 *(args->result) = code;
2175 /* we've errored, so no point in letting more jobs continue */
2176 afs_wq_shutdown(queue);
2182 static pthread_once_t wq_once = PTHREAD_ONCE_INIT;
2183 static pthread_key_t wq_key;
2186 * create the wq_key key for storing a work queue.
2189 _namei_wq_keycreate(void)
2191 osi_Assert(pthread_key_create(&wq_key, NULL) == 0);
2195 * set the work queue for this thread to use for backgrounding namei ops.
2197 * The work queue will be used in ListAFSSubdirs (called indirectly by
2198 * ListViceInodes) to examine files in parallel.
2200 * @param[in] wq the work queue to use
2203 namei_SetWorkQueue(struct afs_work_queue *wq)
2205 osi_Assert(pthread_once(&wq_once, _namei_wq_keycreate) == 0);
2207 osi_Assert(pthread_setspecific(wq_key, wq) == 0);
2211 * enqueue an examine file work unit.
2213 * @param[in] work the _namei_examine_file arguments that are common to
2214 * all callers within the same ListAFSFiles operation
2215 * @param[in] dir the specific directory to look at (string will be
2216 * copied; can be stack/temporary memory)
2217 * @param[in] filename the filename to look at (string will be copied; can be
2218 * stack/temporary memory)
2219 * @param[in] wq work queue to enqueue this work unit to
2220 * @param[in] resultlist the list to append the 'struct listsubdirs_result' to
2221 * for the enqueued work unit
2223 * @return operation status
2225 * @retval -1 fatal error
2227 * @note errors MUST be indicated by a -1 error code and nothing else, to be
2228 * compatible with _namei_examine_reg and _namei_examine_special
2233 _namei_examine_file_spawn(const struct listsubdirs_work_node *work,
2234 const char *dir, const char *filename,
2235 struct afs_work_queue *wq,
2236 struct rx_queue *resultlist)
2239 struct listsubdirs_args *args = NULL;
2240 struct listsubdirs_result *result = NULL;
2241 struct afs_work_queue_node *node = NULL;
2242 struct afs_work_queue_add_opts opts;
2244 args = malloc(sizeof(*args));
2250 result = malloc(sizeof(*result));
2251 if (result == NULL) {
2256 code = afs_wq_node_alloc(&node);
2261 code = afs_wq_node_set_detached(node);
2268 args->result = &result->inodes;
2269 strlcpy(args->dir, dir, sizeof(args->dir));
2270 strlcpy(args->filename, filename, sizeof(args->filename));
2272 code = afs_wq_node_set_callback(node,
2273 &_namei_examine_file_cbk,
2281 afs_wq_add_opts_init(&opts);
2284 code = afs_wq_add(wq, node, &opts);
2291 queue_Append(resultlist, result);
2296 afs_wq_node_put(node);
2312 #else /* !AFS_SALSRV_ENV */
2313 # define _namei_examine_file_spawn(work, dir, file, wq, resultlist) \
2314 _namei_examine_file(work, dir, file)
2315 #endif /* !AFS_SALSRV_ENV */
2318 * traverse and check inodes.
2320 * @param[in] dirIH volume group directory handle
2321 * @param[in] writeFun function pointer which will write inode
2322 * metadata to FILE stream fp
2323 * @param[in] fp file stream where inode metadata gets
2325 * @param[in] judgeFun inode filter function. if not NULL, only
2326 * inodes for which the filter returns non-zero
2327 * will be written out by writeFun
2328 * @param[in] singleVolumeNumber volume id filter. only inodes matching this
2329 * filter are written out by writeFun
2330 * @param[in] rock opaque pointer passed to judgeFun and writeFun
2332 * @return operation status
2334 * @retval >=0 number of matching inodes found
2336 * @todo the salsrv implementation may consume a lot of
2337 * memory for a large volume. at some point we should
2338 * probably write a background thread to asynchronously
2339 * clean up the resultlist nodes to reduce memory footprint
2344 namei_ListAFSSubDirs(IHandle_t * dirIH,
2345 int (*writeFun) (FILE *, struct ViceInodeInfo *, char *,
2348 int (*judgeFun) (struct ViceInodeInfo *, afs_uint32, void *),
2349 afs_uint32 singleVolumeNumber, void *rock)
2351 int code = 0, ret = 0;
2352 IHandle_t myIH = *dirIH;
2354 char path1[512], path3[512];
2356 #ifndef AFS_NT40_ENV
2361 struct dirent *dp1, *dp3;
2362 FdHandle_t linkHandle;
2364 struct listsubdirs_work_node work;
2365 #ifdef AFS_SALSRV_ENV
2367 struct afs_work_queue *wq;
2369 struct rx_queue resultlist;
2372 namei_HandleToVolDir(&name, &myIH);
2373 strlcpy(path1, name.n_path, sizeof(path1));
2375 /* Do the directory containing the special files first to pick up link
2378 (void)strcat(path1, OS_DIRSEP);
2379 (void)strcat(path1, NAMEI_SPECDIR);
2381 linkHandle.fd_fd = INVALID_FD;
2382 #ifdef AFS_SALSRV_ENV
2383 osi_Assert(pthread_once(&wq_once, _namei_wq_keycreate) == 0);
2385 wq = pthread_getspecific(wq_key);
2391 queue_Init(&resultlist);
2394 memset(&work, 0, sizeof(work));
2395 work.linkHandle = &linkHandle;
2398 work.writeFun = writeFun;
2399 work.judgeFun = judgeFun;
2400 work.singleVolumeNumber = singleVolumeNumber;
2403 #ifdef AFS_SALSRV_ENV
2404 work.error = &error;
2407 dirp1 = opendir(path1);
2409 while ((dp1 = readdir(dirp1))) {
2410 if (*dp1->d_name == '.')
2413 #ifdef AFS_SALSRV_ENV
2419 #endif /* AFS_SALSRV_ENV */
2421 code = _namei_examine_file_spawn(&work, path1, dp1->d_name, wq, &resultlist);
2431 /* count this inode */
2432 #ifndef AFS_SALSRV_ENV
2441 #ifdef AFS_SALSRV_ENV
2442 /* effectively a barrier */
2443 code = _namei_listsubdirs_wait(wq, &resultlist);
2444 if (code < 0 || error) {
2452 if (linkHandle.fd_fd == INVALID_FD) {
2453 Log("namei_ListAFSSubDirs: warning: VG %u does not have a link table; "
2454 "salvager will recreate it.\n", dirIH->ih_vid);
2457 /* Now run through all the other subdirs */
2458 namei_HandleToVolDir(&name, &myIH);
2459 strlcpy(path1, name.n_path, sizeof(path1));
2463 dirp1 = opendir(path1);
2465 while ((dp1 = readdir(dirp1))) {
2466 #ifndef AFS_NT40_ENV
2467 if (*dp1->d_name == '.')
2470 if (!strcmp(dp1->d_name, NAMEI_SPECDIR))
2473 #ifndef AFS_NT40_ENV /* This level missing on Windows */
2474 /* Now we've got a next level subdir. */
2475 afs_snprintf(path2, sizeof(path2), "%s" OS_DIRSEP "%s", path1, dp1->d_name);
2476 dirp2 = opendir(path2);
2478 while ((dp2 = readdir(dirp2))) {
2479 if (*dp2->d_name == '.')
2482 /* Now we've got to the actual data */
2483 afs_snprintf(path3, sizeof(path3), "%s" OS_DIRSEP "%s", path2,
2486 /* Now we've got to the actual data */
2487 afs_snprintf(path3, sizeof(path3), "%s" OS_DIRSEP "%s", path1,
2490 dirp3 = opendir(path3);
2492 while ((dp3 = readdir(dirp3))) {
2493 #ifndef AFS_NT40_ENV
2494 if (*dp3->d_name == '.')
2498 #ifdef AFS_SALSRV_ENV
2501 #ifndef AFS_NT40_ENV
2508 #endif /* AFS_SALSRV_ENV */
2510 code = _namei_examine_file_spawn(&work, path3,
2517 #ifndef AFS_NT40_ENV
2525 #ifndef AFS_SALSRV_ENV
2533 #ifndef AFS_NT40_ENV /* This level missing on Windows */
2542 #ifdef AFS_SALSRV_ENV
2543 /* effectively a barrier */
2544 code = _namei_listsubdirs_wait(wq, &resultlist);
2545 if (code < 0 || error) {
2555 /* Then why does this directory exist? Blow it away. */
2556 namei_HandleToVolDir(&name, dirIH);
2557 namei_RemoveDataDirectories(&name);
2561 #ifdef AFS_SALSRV_ENV
2563 afs_wq_wait_all(wq);
2565 _namei_listsubdirs_cleanup_results(&resultlist);
2567 if (linkHandle.fd_fd != INVALID_FD)
2568 OS_CLOSE(linkHandle.fd_fd);
2580 DecodeVolumeName(char *name, unsigned int *vid)
2582 /* Name begins with "Vol_" and ends with .data. See nt_HandleToVolDir() */
2589 if (strncmp(name, "Vol_", 4))
2591 if (strcmp(name + len - 5, ".data"))
2594 stmp[len - 5] = '\0';
2595 *vid = base32_to_int(stmp + 4);
2600 DecodeVolumeName(char *name, unsigned int *vid)
2602 if (strlen(name) < 1)
2604 *vid = (unsigned int)flipbase64_to_int64(name);
2612 * Get the inode number from the name.
2617 DecodeInode(char *dpath, char *name, struct ViceInodeInfo *info,
2622 WIN32_FIND_DATA data;
2626 FdHandle_t linkHandle;
2629 afs_snprintf(fpath, sizeof(fpath), "%s" OS_DIRSEP "%s", dpath, name);
2631 dirH = FindFirstFileEx(fpath, FindExInfoStandard, &data,
2632 FindExSearchNameMatch, NULL,
2633 FIND_FIRST_EX_CASE_SENSITIVE);
2634 if (dirH == INVALID_HANDLE_VALUE)
2637 (void)strcpy(stmp, name);
2638 s = strrchr(stmp, '_');
2642 t = strrchr(s, '.');
2647 vno = base32_to_int(s); /* type for special files */
2648 tag = base32_to_int(t+1);
2649 info->inodeNumber = ((Inode) tag) << NAMEI_TAGSHIFT;
2650 info->inodeNumber |= vno;
2651 info->byteCount = data.nFileSizeLow;
2653 dirl = dpath[strlen(dpath)-1];
2654 if (dirl == NAMEI_SPECDIRC) { /* Special inode. */
2655 info->inodeNumber |= NAMEI_INODESPECIAL;
2656 info->u.param[0] = data.ftCreationTime.dwHighDateTime;
2657 info->u.param[1] = data.ftCreationTime.dwLowDateTime;
2658 info->u.param[2] = vno; /* type */
2659 info->u.param[3] = volid;
2660 if (vno != VI_LINKTABLE)
2661 info->linkCount = 1;
2663 /* Open this handle */
2665 (void)sprintf(lpath, "%s" OS_DIRSEP "%s", fpath, data.cFileName);
2666 linkHandle.fd_fd = afs_open(lpath, O_RDONLY, 0666);
2668 namei_GetLinkCount(&linkHandle, (Inode) 0, 0, 0, 0);
2672 namei_GetLinkCount(&linkHandle, info->inodeNumber, 0, 0, 0);
2673 if (info->linkCount == 0) {
2675 Log("Found 0 link count file %s" OS_DIRSEP "%s, deleting it.\n",
2676 fpath, data.cFileName);
2677 AddToZLCDeleteList(dirl, data.cFileName);
2679 Log("Found 0 link count file %s" OS_DIRSEP "%s.\n", path,
2683 info->u.param[2] = data.ftCreationTime.dwHighDateTime;
2684 info->u.param[3] = data.ftCreationTime.dwLowDateTime;
2685 info->u.param[1] = vno;
2686 info->u.param[0] = volid;
2693 DecodeInode(char *dpath, char *name, struct ViceInodeInfo *info,
2697 struct afs_stat status;
2699 lb64_string_t check;
2701 afs_snprintf(fpath, sizeof(fpath), "%s" OS_DIRSEP "%s", dpath, name);
2703 if (afs_stat(fpath, &status) < 0) {
2707 info->byteCount = status.st_size;
2708 info->inodeNumber = (Inode) flipbase64_to_int64(name);
2710 int64_to_flipbase64(check, info->inodeNumber);
2711 if (strcmp(name, check))
2714 GetOGMFromStat(&status, &parm, &tag);
2715 if ((info->inodeNumber & NAMEI_INODESPECIAL) == NAMEI_INODESPECIAL) {
2716 /* p1 - vid, p2 - -1, p3 - type, p4 - rwvid */
2717 info->u.param[0] = parm;
2718 info->u.param[1] = -1;
2719 info->u.param[2] = tag;
2720 info->u.param[3] = volid;
2722 /* p1 - vid, p2 - vno, p3 - uniq, p4 - dv */
2723 info->u.param[0] = volid;
2724 info->u.param[1] = (int)(info->inodeNumber & NAMEI_VNODEMASK);
2725 info->u.param[2] = (int)((info->inodeNumber >> NAMEI_UNIQSHIFT)
2726 & (Inode) NAMEI_UNIQMASK);
2727 info->u.param[3] = parm;
2734 * Convert the VolumeInfo file from RO to RW
2735 * this routine is called by namei_convertROtoRWvolume()
2738 #ifdef FSSYNC_BUILD_CLIENT
2740 convertVolumeInfo(FD_t fdr, FD_t fdw, afs_uint32 vid)
2742 struct VolumeDiskData vd;
2745 if (OS_READ(fdr, &vd, sizeof(struct VolumeDiskData)) !=
2746 sizeof(struct VolumeDiskData)) {
2747 Log("1 convertVolumeInfo: read failed for %lu with code %d\n",
2748 afs_printable_uint32_lu(vid),
2752 vd.restoredFromId = vd.id; /* remember the RO volume here */
2754 vd.id = vd.parentId;
2758 vd.uniquifier += 5000; /* just in case there are still file copies from
2759 * the old RW volume around */
2760 p = strrchr(vd.name, '.');
2761 if (p && !strcmp(p, ".readonly")) {
2764 if (OS_WRITE(fdw, &vd, sizeof(struct VolumeDiskData)) !=
2765 sizeof(struct VolumeDiskData)) {
2766 Log("1 convertVolumeInfo: write failed for %lu with code %d\n",
2767 afs_printable_uint32_lu(vid),
2776 * Convert a RO-volume into a RW-volume
2778 * This function allows to recover very fast from the loss of a partition
2779 * from RO-copies if all RO-Copies exist on another partition.
2780 * Then these RO-volumes can be made to the new RW-volumes.
2781 * Backup of RW-volumes then consists in "vos release".
2783 * We must make sure in this partition exists only the RO-volume which
2784 * is typical for remote replicas.
2786 * Then the linktable is already ok,
2787 * the vnode files need to be renamed
2788 * the volinfo file needs to be replaced by another one with
2789 * slightly different contents and new name.
2790 * The volume header file of the RO-volume in the /vicep<x> directory
2791 * is destroyed by this call. A new header file for the RW-volume must
2792 * be created after return from this routine.
2796 namei_ConvertROtoRWvolume(char *pname, afs_uint32 volumeId)
2799 #ifdef FSSYNC_BUILD_CLIENT
2801 char dir_name[512], oldpath[512], newpath[512];
2816 struct DiskPartition64 *partP;
2817 struct ViceInodeInfo info;
2818 struct VolumeDiskHeader h;
2819 # ifdef AFS_DEMAND_ATTACH_FS
2821 # endif /* AFS_DEMAND_ATTACH_FS */
2823 for (partP = DiskPartitionList; partP && strcmp(partP->name, pname);
2824 partP = partP->next);
2826 Log("1 namei_ConvertROtoRWvolume: Couldn't find DiskPartition for %s\n", pname);
2831 # ifdef AFS_DEMAND_ATTACH_FS
2832 locktype = VVolLockType(V_VOLUPD, 1);
2833 code = VLockVolumeByIdNB(volumeId, partP, locktype);
2839 # endif /* AFS_DEMAND_ATTACH_FS */
2841 if (VReadVolumeDiskHeader(volumeId, partP, &h)) {
2842 Log("1 namei_ConvertROtoRWvolume: Couldn't read header for RO-volume %lu.\n",
2843 afs_printable_uint32_lu(volumeId));
2848 FSYNC_VolOp(volumeId, pname, FSYNC_VOL_BREAKCBKS, 0, NULL);
2850 ino = namei_MakeSpecIno(h.parent, VI_LINKTABLE);
2851 IH_INIT(ih, partP->device, h.parent, ino);
2853 namei_HandleToName(&n, ih);
2854 strlcpy(dir_name, n.n_path, sizeof(dir_name));
2855 p = strrchr(dir_name, OS_DIRSEPC);
2857 dirp = opendir(dir_name);
2859 Log("1 namei_ConvertROtoRWvolume: Could not opendir(%s)\n", dir_name);
2864 while ((dp = readdir(dirp))) {
2865 /* struct ViceInodeInfo info; */
2866 #ifndef AFS_NT40_ENV
2867 if (*dp->d_name == '.')
2870 if (DecodeInode(dir_name, dp->d_name, &info, ih->ih_vid) < 0) {
2871 Log("1 namei_ConvertROtoRWvolume: DecodeInode failed for %s" OS_DIRSEP "%s\n",
2872 dir_name, dp->d_name);
2877 if (info.u.param[1] != -1) {
2878 Log("1 namei_ConvertROtoRWvolume: found other than volume special file %s" OS_DIRSEP "%s\n", dir_name, dp->d_name);
2883 if (info.u.param[0] != volumeId) {
2884 if (info.u.param[0] == ih->ih_vid) {
2885 if (info.u.param[2] == VI_LINKTABLE) { /* link table */
2890 Log("1 namei_ConvertROtoRWvolume: found special file %s" OS_DIRSEP "%s"
2891 " for volume %lu\n", dir_name, dp->d_name,
2892 afs_printable_uint32_lu(info.u.param[0]));
2897 if (info.u.param[2] == VI_VOLINFO) { /* volume info file */
2898 strlcpy(infoName, dp->d_name, sizeof(infoName));
2900 } else if (info.u.param[2] == VI_SMALLINDEX) { /* small vnodes file */
2901 strlcpy(smallName, dp->d_name, sizeof(smallName));
2903 } else if (info.u.param[2] == VI_LARGEINDEX) { /* large vnodes file */
2904 strlcpy(largeName, dp->d_name, sizeof(largeName));
2908 Log("1 namei_ConvertROtoRWvolume: unknown type %d of special file found : %s" OS_DIRSEP "%s\n", info.u.param[2], dir_name, dp->d_name);
2915 if (!infoSeen || !smallSeen || !largeSeen || !linkSeen) {
2916 Log("1 namei_ConvertROtoRWvolume: not all special files found in %s\n", dir_name);
2922 * If we come here then there was only a RO-volume and we can safely
2926 memset(&t_ih, 0, sizeof(t_ih));
2927 t_ih.ih_dev = ih->ih_dev;
2928 t_ih.ih_vid = ih->ih_vid;
2930 (void)afs_snprintf(oldpath, sizeof oldpath, "%s" OS_DIRSEP "%s", dir_name,
2932 fd = afs_open(oldpath, O_RDWR, 0);
2934 Log("1 namei_ConvertROtoRWvolume: could not open RO info file: %s\n",
2939 t_ih.ih_ino = namei_MakeSpecIno(ih->ih_vid, VI_VOLINFO);
2940 namei_HandleToName(&n, &t_ih);
2941 fd2 = afs_open(n.n_path, O_CREAT | O_EXCL | O_TRUNC | O_RDWR, 0);
2943 Log("1 namei_ConvertROtoRWvolume: could not create RW info file: %s\n", n.n_path);
2948 code = convertVolumeInfo(fd, fd2, ih->ih_vid);
2952 OS_UNLINK(n.n_path);
2956 SetOGM(fd2, ih->ih_vid, 1);
2959 t_ih.ih_ino = namei_MakeSpecIno(ih->ih_vid, VI_SMALLINDEX);
2960 namei_HandleToName(&n, &t_ih);
2961 (void)afs_snprintf(newpath, sizeof newpath, "%s" OS_DIRSEP "%s", dir_name,
2963 fd = afs_open(newpath, O_RDWR, 0);
2965 Log("1 namei_ConvertROtoRWvolume: could not open SmallIndex file: %s\n", newpath);
2969 SetOGM(fd, ih->ih_vid, 2);
2972 MoveFileEx(n.n_path, newpath, MOVEFILE_WRITE_THROUGH);
2974 link(newpath, n.n_path);
2978 t_ih.ih_ino = namei_MakeSpecIno(ih->ih_vid, VI_LARGEINDEX);
2979 namei_HandleToName(&n, &t_ih);
2980 (void)afs_snprintf(newpath, sizeof newpath, "%s" OS_DIRSEP "%s", dir_name,
2982 fd = afs_open(newpath, O_RDWR, 0);
2984 Log("1 namei_ConvertROtoRWvolume: could not open LargeIndex file: %s\n", newpath);
2988 SetOGM(fd, ih->ih_vid, 3);
2991 MoveFileEx(n.n_path, newpath, MOVEFILE_WRITE_THROUGH);
2993 link(newpath, n.n_path);
3000 h.volumeInfo_hi = h.id;
3001 h.smallVnodeIndex_hi = h.id;
3002 h.largeVnodeIndex_hi = h.id;
3003 h.linkTable_hi = h.id;
3005 if (VCreateVolumeDiskHeader(&h, partP)) {
3006 Log("1 namei_ConvertROtoRWvolume: Couldn't write header for RW-volume %lu\n",
3007 afs_printable_uint32_lu(h.id));
3012 if (VDestroyVolumeDiskHeader(partP, volumeId, h.parent)) {
3013 Log("1 namei_ConvertROtoRWvolume: Couldn't unlink header for RO-volume %lu\n",
3014 afs_printable_uint32_lu(volumeId));
3017 FSYNC_VolOp(volumeId, pname, FSYNC_VOL_DONE, 0, NULL);
3018 FSYNC_VolOp(h.id, pname, FSYNC_VOL_ON, 0, NULL);
3021 # ifdef AFS_DEMAND_ATTACH_FS
3023 VUnlockVolumeById(volumeId, partP);
3025 # endif /* AFS_DEMAND_ATTACH_FS */
3033 * returns a static string used to print either 32 or 64 bit inode numbers.
3036 PrintInode(char *s, Inode ino)
3038 static afs_ino_str_t result;
3042 (void)afs_snprintf(s, sizeof(afs_ino_str_t), "%" AFS_UINT64_FMT, (afs_uintmax_t) ino);
3049 /* Routines to facilitate removing zero link count files. */
3050 #define MAX_ZLC_NAMES 32
3051 #define MAX_ZLC_NAMELEN 16
3052 typedef struct zlcList_s {
3053 struct zlcList_s *zlc_next;
3055 char zlc_names[MAX_ZLC_NAMES][MAX_ZLC_NAMELEN];
3058 static zlcList_t *zlcAnchor = NULL;
3059 static zlcList_t *zlcCur = NULL;
3062 AddToZLCDeleteList(char dir, char *name)
3064 osi_Assert(strlen(name) <= MAX_ZLC_NAMELEN - 3);
3066 if (!zlcCur || zlcCur->zlc_n >= MAX_ZLC_NAMES) {
3067 if (zlcCur && zlcCur->zlc_next)
3068 zlcCur = zlcCur->zlc_next;
3070 zlcList_t *tmp = (zlcList_t *) malloc(sizeof(zlcList_t));
3076 zlcCur->zlc_next = tmp;
3080 zlcCur->zlc_next = NULL;
3085 (void)sprintf(zlcCur->zlc_names[zlcCur->zlc_n], "%c" OS_DIRSEP "%s", dir, name);
3087 (void)sprintf(zlcCur->zlc_names[zlcCur->zlc_n], "%s", name);
3093 DeleteZLCFiles(char *path)
3099 for (z = zlcAnchor; z; z = z->zlc_next) {
3100 for (i = 0; i < z->zlc_n; i++) {
3102 (void)sprintf(fname, "%s" OS_DIRSEP "%s", path, z->zlc_names[i]);
3104 (void)sprintf(fname, "%s", z->zlc_names[i]);
3105 if (namei_unlink(fname) < 0) {
3106 Log("ZLC: Can't unlink %s, dos error = %d\n", fname,
3110 z->zlc_n = 0; /* Can reuse space. */
3123 tnext = i->zlc_next;
3127 zlcCur = zlcAnchor = NULL;
3131 #endif /* AFS_NAMEI_ENV */