Exemple #1
0
Volume *
AttachVolume(struct DiskPartition64 * dp, char *volname,
	     struct VolumeHeader * header)
{
    Volume *vp;
    afs_int32 ec = 0;

    vp = (Volume *) calloc(1, sizeof(Volume));
    vp->specialStatus = 0;
    vp->device = dp->device;
    vp->partition = dp;
    IH_INIT(vp->vnodeIndex[vLarge].handle, dp->device, header->parent,
	    header->largeVnodeIndex);
    IH_INIT(vp->vnodeIndex[vSmall].handle, dp->device, header->parent,
	    header->smallVnodeIndex);
    IH_INIT(vp->diskDataHandle, dp->device, header->parent,
	    header->volumeInfo);
    IH_INIT(V_linkHandle(vp), dp->device, header->parent, header->linkTable);
    vp->cacheCheck = 0;		/* XXXX */
    vp->shuttingDown = 0;
    vp->goingOffline = 0;
    vp->nUsers = 1;
    vp->header = (struct volHeader *)calloc(1, sizeof(*vp->header));
    ec = ReadHdr1(V_diskDataHandle(vp), (char *)&V_disk(vp),
		  sizeof(V_disk(vp)), VOLUMEINFOMAGIC, VOLUMEINFOVERSION);
    if (!ec) {
	struct IndexFileHeader iHead;
	ec = ReadHdr1(vp->vnodeIndex[vSmall].handle, (char *)&iHead,
		      sizeof(iHead), SMALLINDEXMAGIC, SMALLINDEXVERSION);
    }
    if (!ec) {
	struct IndexFileHeader iHead;
	ec = ReadHdr1(vp->vnodeIndex[vLarge].handle, (char *)&iHead,
		      sizeof(iHead), LARGEINDEXMAGIC, LARGEINDEXVERSION);
    }
#ifdef AFS_NAMEI_ENV
    if (!ec) {
	struct versionStamp stamp;
	ec = ReadHdr1(V_linkHandle(vp), (char *)&stamp, sizeof(stamp),
		      LINKTABLEMAGIC, LINKTABLEVERSION);
    }
#endif
    if (ec)
	return (Volume *) 0;
    return vp;
}
Exemple #2
0
IHandle_t *
GetLinkHandle(char *part, int volid)
{
    int dev;
    Inode ino;
    IHandle_t *lh;

    dev = volutil_GetPartitionID(part);
    ino = namei_MakeSpecIno(volid, VI_LINKTABLE);

    IH_INIT(lh, dev, volid, ino);
    return lh;
}
Exemple #3
0
/* SetSalvageDirHandle:
 * Create a handle to a directory entry and reference it (IH_INIT).
 * The handle needs to be dereferenced with the FidZap() routine.
 */
void
SetSalvageDirHandle(DirHandle * dir, afs_int32 volume, Device device,
		    Inode inode)
{
    static int SalvageCacheCheck = 1;
    memset(dir, 0, sizeof(DirHandle));

    dir->dirh_device = device;
    dir->dirh_volume = volume;
    dir->dirh_inode = inode;
    IH_INIT(dir->dirh_handle, device, volume, inode);
    /* Always re-read for a new dirhandle */
    dir->dirh_cacheCheck = SalvageCacheCheck++;
}
Exemple #4
0
static void
RemoveInodes(Device dev, VolumeId vid)
{
    register int i;
    IHandle_t *handle;

    /* This relies on the fact that IDEC only needs the device and NT only
     * needs the dev and vid to decrement volume special files.
     */
    IH_INIT(handle, dev, vid, -1);
    for (i = 0; i < nFILES; i++) {
	Inode inode = *stuff[i].inode;
	if (VALID_INO(inode))
	    IH_DEC(handle, inode, vid);
    }
    IH_RELEASE(handle);
}
Exemple #5
0
static void
RemoveInodes(struct afs_inode_info *stuff, Device dev, VolumeId parent,
             VolumeId vid)
{
    int i;
    IHandle_t *handle;

    /* This relies on the fact that IDEC only needs the device and NT only
     * needs the dev and vid to decrement volume special files.
     */
    IH_INIT(handle, dev, parent, -1);
    for (i = 0; i < MAXINODETYPE; i++) {
	Inode inode = *stuff[i].inode;
	if (VALID_INO(inode)) {
	    if (stuff[i].inodeType == VI_LINKTABLE) {
		IH_DEC(handle, inode, parent);
	    } else {
		IH_DEC(handle, inode, vid);
	    }
	}
    }
    IH_RELEASE(handle);
}
Exemple #6
0
void
HandleVolume(struct DiskPartition64 *dp, char *name)
{
    struct VolumeHeader header;
    struct VolumeDiskHeader diskHeader;
    struct afs_stat status, stat;
    int fd;
    Volume *vp;
    IHandle_t *ih;
    char headerName[1024];

    if (online) {
	printf("volinfo: -online not supported\n");
	exit(1);
    } else {
	afs_int32 n;

	(void)afs_snprintf(headerName, sizeof headerName, "%s/%s",
			   VPartitionPath(dp), name);
	if ((fd = afs_open(headerName, O_RDONLY)) == -1
	    || afs_fstat(fd, &status) == -1) {
	    printf("Volinfo: Cannot read volume header %s\n", name);
	    close(fd);
	    exit(1);
	}
	n = read(fd, &diskHeader, sizeof(diskHeader));

	if (n != sizeof(diskHeader)
	    || diskHeader.stamp.magic != VOLUMEHEADERMAGIC) {
	    printf("Volinfo: Error reading volume header %s\n", name);
	    exit(1);
	}
	if (diskHeader.stamp.version != VOLUMEHEADERVERSION) {
	    printf
		("Volinfo: Volume %s, version number is incorrect; volume needs salvage\n",
		 name);
	    exit(1);
	}
	DiskToVolumeHeader(&header, &diskHeader);

	if (dheader) {
	    FdHandle_t *fdP;
	    afs_sfsize_t size = 0;
	    afs_sfsize_t code;

	    if (afs_fstat(fd, &stat) == -1) {
		perror("stat");
		exit(1);
	    }
	    if (!dsizeOnly && !saveinodes) {
		size = stat.st_size;
		printf("Volume header (size = %d):\n", (int)size);
		printf("\tstamp\t= 0x%x\n", header.stamp.version);
		printf("\tVolId\t= %u\n", header.id);
	    }

	    IH_INIT(ih, dp->device, header.parent, header.volumeInfo);
	    fdP = IH_OPEN(ih);
	    if (fdP == NULL) {
		perror("opening volume info");
		exit(1);
	    }
	    code = FDH_SIZE(fdP);
	    if (code == -1) {
		perror("fstat");
		exit(1);
	    }
	    FDH_REALLYCLOSE(fdP);
	    IH_RELEASE(ih);
	    size += code;
	    if (!dsizeOnly && !saveinodes) {
		printf("\tparent\t= %u\n", header.parent);
		printf("\tInfo inode\t= %s (size = %d)\n",
		       PrintInode(NULL, header.volumeInfo), (int)code);
	    }

	    IH_INIT(ih, dp->device, header.parent, header.smallVnodeIndex);
	    fdP = IH_OPEN(ih);
	    if (fdP == NULL) {
		perror("opening small vnode index");
		exit(1);
	    }
	    code = FDH_SIZE(fdP);
	    if (code == -1) {
		perror("fstat");
		exit(1);
	    }
	    FDH_REALLYCLOSE(fdP);
	    IH_RELEASE(ih);
	    size += code;
	    if (!dsizeOnly && !saveinodes) {
		printf("\tSmall inode\t= %s (size = %d)\n",
		       PrintInode(NULL, header.smallVnodeIndex), (int)code);
	    }

	    IH_INIT(ih, dp->device, header.parent, header.largeVnodeIndex);
	    fdP = IH_OPEN(ih);
	    if (fdP == NULL) {
		perror("opening large vnode index");
		exit(1);
	    }
	    code = FDH_SIZE(fdP);
	    if (code == -1) {
		perror("fstat");
		exit(1);
	    }
	    FDH_REALLYCLOSE(fdP);
	    IH_RELEASE(ih);
	    size += code;
	    if (!dsizeOnly && !saveinodes) {
		printf("\tLarge inode\t= %s (size = %d)\n",
		       PrintInode(NULL, header.largeVnodeIndex), (int)code);
#ifndef AFS_NT40_ENV
		printf("Total aux volume size = %d\n\n", (int)size);
#endif
	    }
#ifdef AFS_NAMEI_ENV
	    IH_INIT(ih, dp->device, header.parent, header.linkTable);
	    fdP = IH_OPEN(ih);
	    if (fdP == NULL) {
		perror("opening link table index");
		exit(1);
	    }
	    code = FDH_SIZE(fdP);
	    if (code == -1) {
		perror("fstat");
		exit(1);
	    }
	    FDH_REALLYCLOSE(fdP);
	    IH_RELEASE(ih);
	    size += code;
	    if (!dsizeOnly && !saveinodes) {
		printf("\tLink inode\t= %s (size = %d)\n",
		       PrintInode(NULL, header.linkTable), (int)code);
		printf("Total aux volume size = %d\n\n", (int)size);
	    }
#endif
	    Vauxsize = size;
	    Vauxsize_k = size / 1024;
	}
	close(fd);
	vp = AttachVolume(dp, name, &header);
	if (!vp) {
	    printf("Volinfo: Error attaching volume header %s\n", name);
	    return;
	}
    }
    PrintHeader(vp);
    if (DumpVnodes) {
	if (!dsizeOnly && !saveinodes)
	    printf("\nLarge vnodes (directories)\n");
	PrintVnodes(vp, vLarge);
	if (!dsizeOnly && !saveinodes) {
	    printf("\nSmall vnodes(files, symbolic links)\n");
	    fflush(stdout);
	}
	if (saveinodes)
	    printf("Saving all volume files to current directory ...\n");
	PrintVnodes(vp, vSmall);
    }
    if (dsizeOnly) {
	totvolsize = Vauxsize_k + Vvnodesize_k;
	if (saveinodes)
	    printf
		("Volume-Id\t  Volsize  Auxsize Inodesize  AVolsize SizeDiff                (VolName)\n");
	printf("%u\t%9d%9d%10d%10d%9d\t%24s\n", V_id(vp), Vdiskused,
	       Vauxsize_k, Vvnodesize_k, totvolsize, totvolsize - Vdiskused,
	       V_name(vp));
    }
    free(vp->header);
    free(vp);
}
Exemple #7
0
static int
DumpVnode(int dumpfd, struct VnodeDiskObject *v, int volid, int vnodeNumber,
	  int dumpEverything, struct Volume *vp)
{
    int code = 0;
    IHandle_t *ihP;
    FdHandle_t *fdP;

    if (verbose)
	fprintf(stderr, "dumping vnode %d\n", vnodeNumber);

    if (!v || v->type == vNull)
	return code;
    if (!code)
	code = DumpDouble(dumpfd, D_VNODE, vnodeNumber, v->uniquifier);
    if (!dumpEverything)
	return code;
    if (!code)
	code = DumpByte(dumpfd, 't', (byte) v->type);
    if (!code)
	code = DumpShort(dumpfd, 'l', v->linkCount);	/* May not need this */
    if (!code)
	code = DumpInt32(dumpfd, 'v', v->dataVersion);
    if (!code)
	code = DumpInt32(dumpfd, 'm', v->unixModifyTime);
    if (!code)
	code = DumpInt32(dumpfd, 'a', v->author);
    if (!code)
	code = DumpInt32(dumpfd, 'o', v->owner);
    if (!code && v->group)
	code = DumpInt32(dumpfd, 'g', v->group);	/* default group is 0 */
    if (!code)
	code = DumpShort(dumpfd, 'b', v->modeBits);
    if (!code)
	code = DumpInt32(dumpfd, 'p', v->parent);
    if (!code)
	code = DumpInt32(dumpfd, 's', v->serverModifyTime);
    if (v->type == vDirectory) {
	acl_HtonACL(VVnodeDiskACL(v));
	if (!code)
	    code =
		DumpByteString(dumpfd, 'A', (byte *) VVnodeDiskACL(v),
			       VAclDiskSize(v));
    }

    if (VNDISK_GET_INO(v)) {
	IH_INIT(ihP, V_device(vp), V_parentId(vp), VNDISK_GET_INO(v));
	fdP = IH_OPEN(ihP);
	if (fdP == NULL) {
	    fprintf(stderr,
		    "Unable to open inode %s for vnode %u (volume %i); not dumped, error %d\n",
		    PrintInode(NULL, VNDISK_GET_INO(v)), vnodeNumber, volid,
		    errno);
	}
	else
	{
		if (verbose)
		    fprintf(stderr, "about to dump inode %s for vnode %u\n",
			    PrintInode(NULL, VNDISK_GET_INO(v)), vnodeNumber);
		code = DumpFile(dumpfd, vnodeNumber, fdP, v);
		FDH_CLOSE(fdP);
	}
	IH_RELEASE(ihP);
    }

    if (verbose)
	fprintf(stderr, "done dumping vnode %d\n", vnodeNumber);
    return code;
}
Exemple #8
0
Volume *
VCreateVolume_r(Error * ec, char *partname, VolumeId volumeId, VolumeId parentId)
{				/* Should be the same as volumeId if there is
				 * no parent */
    VolumeDiskData vol;
    int i, rc;
    char headerName[VMAXPATHLEN], volumePath[VMAXPATHLEN];
    Device device;
    struct DiskPartition64 *partition;
    struct VolumeDiskHeader diskHeader;
    IHandle_t *handle;
    FdHandle_t *fdP;
    Inode nearInode AFS_UNUSED = 0;
    char *part, *name;
    struct stat st;
    struct VolumeHeader tempHeader;
    struct afs_inode_info stuff[MAXINODETYPE];
    afs_ino_str_t stmp;
# ifdef AFS_DEMAND_ATTACH_FS
    int locktype = 0;
# endif /* AFS_DEMAND_ATTACH_FS */

    init_inode_info(&tempHeader, stuff);

    *ec = 0;
    memset(&vol, 0, sizeof(vol));
    vol.id = volumeId;
    vol.parentId = parentId;
    vol.copyDate = time(0);	/* The only date which really means when this
				 * @i(instance) of this volume was created.
				 * Creation date does not mean this */

    /* Initialize handle for error case below. */
    handle = NULL;

    /* Verify that the parition is valid before writing to it. */
    if (!(partition = VGetPartition_r(partname, 0))) {
	Log("VCreateVolume: partition %s is not in service.\n", partname);
	*ec = VNOVOL;
	return NULL;
    }
#if	defined(NEARINODE_HINT)
    nearInodeHash(volumeId, nearInode);
    nearInode %= partition->f_files;
#endif
    VGetVolumePath(ec, vol.id, &part, &name);
    if (*ec == VNOVOL || !strcmp(partition->name, part)) {
	/* this case is ok */
    } else {
	/* return EXDEV if it's a clone to an alternate partition
	 * otherwise assume it's a move */
	if (vol.parentId != vol.id) {
	    *ec = EXDEV;
	    return NULL;
	}
    }
    *ec = 0;

# ifdef AFS_DEMAND_ATTACH_FS
    /* volume doesn't exist yet, but we must lock it to try to prevent something
     * else from reading it when we're e.g. half way through creating it (or
     * something tries to create the same volume at the same time) */
    locktype = VVolLockType(V_VOLUPD, 1);
    rc = VLockVolumeByIdNB(volumeId, partition, locktype);
    if (rc) {
	Log("VCreateVolume: vol %lu already locked by someone else\n",
	    afs_printable_uint32_lu(volumeId));
	*ec = VNOVOL;
	return NULL;
    }
# else /* AFS_DEMAND_ATTACH_FS */
    VLockPartition_r(partname);
# endif /* !AFS_DEMAND_ATTACH_FS */

    memset(&tempHeader, 0, sizeof(tempHeader));
    tempHeader.stamp.magic = VOLUMEHEADERMAGIC;
    tempHeader.stamp.version = VOLUMEHEADERVERSION;
    tempHeader.id = vol.id;
    tempHeader.parent = vol.parentId;
    vol.stamp.magic = VOLUMEINFOMAGIC;
    vol.stamp.version = VOLUMEINFOVERSION;
    vol.destroyMe = DESTROY_ME;
    snprintf(headerName, sizeof headerName, VFORMAT,
	     afs_printable_VolumeId_lu(vol.id));
    snprintf(volumePath, sizeof volumePath, "%s" OS_DIRSEP "%s",
	     VPartitionPath(partition), headerName);
    rc = stat(volumePath, &st);
    if (rc == 0 || errno != ENOENT) {
	if (rc == 0) {
	    Log("VCreateVolume: Header file %s already exists!\n",
		volumePath);
	    *ec = VVOLEXISTS;
	} else {
	    Log("VCreateVolume: Error %d trying to stat header file %s\n",
	        errno, volumePath);
	    *ec = VNOVOL;
	}
	goto bad_noheader;
    }
    device = partition->device;

    for (i = 0; i < MAXINODETYPE; i++) {
	struct afs_inode_info *p = &stuff[i];
	if (p->obsolete)
	    continue;
#ifdef AFS_NAMEI_ENV
	*(p->inode) =
	    IH_CREATE(NULL, device, VPartitionPath(partition), nearInode,
		      (p->inodeType == VI_LINKTABLE) ? vol.parentId : vol.id,
		      INODESPECIAL, p->inodeType, vol.parentId);
	if (!(VALID_INO(*(p->inode)))) {
	    if (errno == EEXIST && (p->inodeType == VI_LINKTABLE)) {
		/* Increment the reference count instead. */
		IHandle_t *lh;
		int code;

		*(p->inode) = namei_MakeSpecIno(vol.parentId, VI_LINKTABLE);
		IH_INIT(lh, device, parentId, *(p->inode));
		fdP = IH_OPEN(lh);
		if (fdP == NULL) {
		    IH_RELEASE(lh);
		    goto bad;
		}
		code = IH_INC(lh, *(p->inode), parentId);
		FDH_REALLYCLOSE(fdP);
		IH_RELEASE(lh);
		if (code < 0)
		    goto bad;
		continue;
	    }
	}
#else
	*(p->inode) =
	    IH_CREATE(NULL, device, VPartitionPath(partition), nearInode,
		      vol.id, INODESPECIAL, p->inodeType, vol.parentId);
#endif

	if (!VALID_INO(*(p->inode))) {
	    Log("VCreateVolume:  Problem creating %s file associated with volume header %s\n", p->description, volumePath);
	  bad:
	    if (handle)
		IH_RELEASE(handle);
	    RemoveInodes(stuff, device, vol.parentId, vol.id);
	    if (!*ec) {
		*ec = VNOVOL;
	    }
	    VDestroyVolumeDiskHeader(partition, volumeId, parentId);
	  bad_noheader:
# ifdef AFS_DEMAND_ATTACH_FS
	    if (locktype) {
		VUnlockVolumeById(volumeId, partition);
	    }
# endif /* AFS_DEMAND_ATTACH_FS */
	    return NULL;
	}
	IH_INIT(handle, device, vol.parentId, *(p->inode));
	fdP = IH_OPEN(handle);
	if (fdP == NULL) {
	    Log("VCreateVolume:  Problem iopen inode %s (err=%d)\n",
		PrintInode(stmp, *(p->inode)), errno);
	    goto bad;
	}
	if (FDH_PWRITE(fdP, (char *)&p->stamp, sizeof(p->stamp), 0) !=
	    sizeof(p->stamp)) {
	    Log("VCreateVolume:  Problem writing to inode %s (err=%d)\n",
		PrintInode(stmp, *(p->inode)), errno);
	    FDH_REALLYCLOSE(fdP);
	    goto bad;
	}
	FDH_REALLYCLOSE(fdP);
	IH_RELEASE(handle);
	nearInode = *(p->inode);
    }

    IH_INIT(handle, device, vol.parentId, tempHeader.volumeInfo);
    fdP = IH_OPEN(handle);
    if (fdP == NULL) {
	Log("VCreateVolume:  Problem iopen inode %s (err=%d)\n",
	    PrintInode(stmp, tempHeader.volumeInfo), errno);
	goto bad;
    }
    if (FDH_PWRITE(fdP, (char *)&vol, sizeof(vol), 0) != sizeof(vol)) {
	Log("VCreateVolume:  Problem writing to  inode %s (err=%d)\n",
	    PrintInode(stmp, tempHeader.volumeInfo), errno);
	FDH_REALLYCLOSE(fdP);
	goto bad;
    }
    FDH_CLOSE(fdP);
    IH_RELEASE(handle);

    VolumeHeaderToDisk(&diskHeader, &tempHeader);
    rc = VCreateVolumeDiskHeader(&diskHeader, partition);
    if (rc) {
	Log("VCreateVolume: Error %d trying to write volume header for "
	    "volume %" AFS_VOLID_FMT " on partition %s; volume not created\n", rc,
	    afs_printable_VolumeId_lu(vol.id), VPartitionPath(partition));
	if (rc == EEXIST) {
	    *ec = VVOLEXISTS;
	}
	goto bad;
    }

# ifdef AFS_DEMAND_ATTACH_FS
    if (locktype) {
	VUnlockVolumeById(volumeId, partition);
    }
# endif /* AFS_DEMAND_ATTACH_FS */
    return (VAttachVolumeByName_r(ec, partname, headerName, V_SECRETLY));
}
Exemple #9
0
/* function called with partition name and volid ID, and which removes all
 * inodes marked with the specified volume ID.  If the volume is a read-only
 * clone, we'll only remove the header inodes, since they're the only inodes
 * marked with that volume ID.  If you want to reclaim all the data, you should
 * nuke the read-write volume ID.
 *
 * Note also that nuking a read-write volume effectively nukes all RO volumes
 * cloned from that RW volume ID, too, since everything except for their
 * indices will be gone.
 */
int
nuke(char *aname, afs_int32 avolid)
{
    /* first process the partition containing this junk */
    struct afs_stat_st tstat;
    struct ilist *ti, *ni, *li=NULL;
    afs_int32 code;
    int i, forceSal;
    char wpath[100];
    char *lastDevComp;
    struct DiskPartition64 *dp;
#ifdef AFS_NAMEI_ENV
    char *path;

    namei_t ufs_name;
#endif /* AFS_NAMEI_ENV */
#ifndef AFS_NAMEI_ENV
    char devName[64];
#endif /* !AFS_NAMEI_ENV */
    IHandle_t *fileH;
    struct ilist *allInodes = 0;

    if (avolid == 0)
	return EINVAL;
    code = afs_stat(aname, &tstat);
    if (code || (dp = VGetPartition(aname, 0)) == NULL) {
	printf("volnuke: partition %s does not exist.\n", aname);
	if (!code) {
	    code = EINVAL;
	}
	return code;
    }
    /* get the device name for the partition */
#if defined(AFS_NAMEI_ENV) && !defined(AFS_NT40_ENV)
    lastDevComp = aname;
#else
#ifdef AFS_NT40_ENV
    lastDevComp = &aname[strlen(aname) - 1];
    *lastDevComp = toupper(*lastDevComp);
#else
    {
	char *tfile = vol_DevName(tstat.st_dev, wpath);
	if (!tfile) {
	    printf("volnuke: can't find %s's device.\n", aname);
	    return 1;
	}
	strcpy(devName, tfile);	/* save this from the static buffer */
    }
    /* aim lastDevComp at the 'foo' of '/dev/foo' */
    lastDevComp = strrchr(devName, OS_DIRSEPC);
    /* either points at slash, or there is no slash; adjust appropriately */
    if (lastDevComp)
	lastDevComp++;
    else
	lastDevComp = devName;
#endif /* AFS_NT40_ENV */
#endif /* AFS_NAMEI_ENV && !AFS_NT40_ENV */

    ObtainWriteLock(&localLock);
    /* OK, we have the mounted on place, aname, the device name (in devName).
     * all we need to do to call ListViceInodes is find the inodes for the
     * volume we're nuking.
     */
    code =
	ListViceInodes(lastDevComp, aname, INVALID_FD, NukeProc, avolid, &forceSal,
		       0, wpath, &allInodes);
    if (code == 0) {
	/* actually do the idecs now */
	for (ti = allInodes; ti; ti = ti->next) {
	    for (i = 0; i < ti->freePtr; i++) {
#ifndef AFS_PTHREAD_ENV
		IOMGR_Poll();	/* keep RPC running */
#endif /* !AFS_PTHREAD_ENV */
		/* idec this inode into oblivion */
#ifdef AFS_NAMEI_ENV
#ifdef AFS_NT40_ENV
		IH_INIT(fileH, (int)(*lastDevComp - 'A'), avolid,
			ti->inode[i]);
#else
		IH_INIT(fileH, (int)volutil_GetPartitionID(aname), avolid,
			ti->inode[i]);
#endif /* AFS_NT40_ENV */
		namei_HandleToName(&ufs_name, fileH);
		path = ufs_name.n_path;
		IH_RELEASE(fileH);
		if (OS_UNLINK(path) < 0) {
		    Log("Nuke: Failed to remove %s\n", path);
		}
#else /* AFS_NAMEI_ENV */
		IH_INIT(fileH, (int)tstat.st_dev, avolid, ti->inode[i]);
		{
		    int j;
		    for (j = 0; j < ti->count[i]; j++) {
			code = IH_DEC(fileH, ti->inode[i], avolid);
		    }
		}
		IH_RELEASE(fileH);
#endif /* AFS_NAMEI_ENV */
	    }
	    ni = ti->next;
	    if (li) free(li);
	    li = ti;
	}
	if (li) free(li);
	code = 0;		/* we really don't care about it except for debugging */
	allInodes = NULL;

	/* at this point, we should try to remove the volume header file itself.
	 * the volume header file is the file named VNNNNN.vol in the UFS file
	 * system, and is a normal file.  As such, it is not stamped with the
	 * volume's ID in its inode, and has to be removed explicitly.
	 */
	code = VDestroyVolumeDiskHeader(dp, avolid, 0);
    } else {
	/* just free things */
	for (ti = allInodes; ti; ti = ni) {
	    ni = ti->next;
	    if (li) free(li);
	    li = ti;
	}
	if (li) free(li);
	allInodes = NULL;
    }
    ReleaseWriteLock(&localLock);
    return code;
}