/* * Copyright 2000, International Business Machines Corporation and others. * All Rights Reserved. * * This software has been released under the terms of the IBM Public * License. For details, see the LICENSE file in the top-level source * directory or online at http://www.openafs.org/dl/license10.html */ /* * Read a vos dump and recreate the tree. * * restorevol [-file ] * [-dir ] * [-extension ] * [-mountpoint ] * [-umask ] * * 1. The dump file will be restored within the current or that specified with -dir. * 2. Within this dir, a subdir is created. It's name is the RW volume name * that was dumped. An extension can be appended to this directory name * with -extension. * 3. All mountpoints will appear as symbolic links to the volume. The * pathname to the volume will be either that in -mountpoint, or -dir. * Symbolic links remain untouched. * 4. You can change your umask during the restore with -umask. Otherwise, it * uses your current umask. Mode bits for directories are 0777 (then * AND'ed with the umask). Mode bits for files are the owner mode bits * duplicated accross group and user (then AND'ed with the umask). * 5. For restores of full dumps, if a directory says it has a file and * the file is not found, then a symbolic link "AFSFile-<#>" will * appear in that restored tree. Restores of incremental dumps remove * all these files at the end (expensive because it is a tree search). * 6. If a file or directory was found in the dump but found not to be * connected to the hierarchical tree, then the file or directory * will be connected at the root of the tree as "__ORPHANEDIR__.<#>" * or "__ORPHANFILE__.<#>". * 7. ACLs are not restored. * */ #include #include #include #include #include #include #include #include #include #include #include #include "volint.h" #include "dump.h" char rootdir[MAXPATHLEN]; char mntroot[MAXPATHLEN]; #define ADIR "AFSDir-" #define AFILE "AFSFile-" #define ODIR "__ORPHANEDIR__." #define OFILE "__ORPHANFILE__." int inc_dump = 0; FILE *dumpfile; afs_int32 readvalue(int size) { afs_int32 value, s; int code; char *ptr; value = 0; ptr = (char *)&value; s = sizeof(value) - size; if (s < 0) { fprintf(stderr, "Too much data for afs_int32\n"); return 0; } code = fread(&ptr[s], 1, size, dumpfile); if (code != size) fprintf(stderr, "Code = %d; Errno = %d\n", code, errno); return (value); } char readchar(void) { char value; int code; value = '\0'; code = fread(&value, 1, 1, dumpfile); if (code != 1) fprintf(stderr, "Code = %d; Errno = %d\n", code, errno); return (value); } #define BUFSIZE 16384 char buf[BUFSIZE]; void readdata(char *buffer, afs_sfsize_t size) { int code; afs_int32 s; if (!buffer) { while (size > 0) { s = (afs_int32) ((size > BUFSIZE) ? BUFSIZE : size); code = fread(buf, 1, s, dumpfile); if (code != s) fprintf(stderr, "Code = %d; Errno = %d\n", code, errno); size -= s; } } else { code = fread(buffer, 1, size, dumpfile); if (code != size) { if (code < 0) fprintf(stderr, "Code = %d; Errno = %d\n", code, errno); else fprintf(stderr, "Read %d bytes out of %" AFS_INT64_FMT "\n", code, (afs_uintmax_t)size); } if ((code >= 0) && (code < BUFSIZE)) buffer[size] = 0; /* Add null char at end */ } } afs_int32 ReadDumpHeader(struct DumpHeader *dh) { int i, done; char tag, c; afs_int32 magic AFS_UNUSED; /* memset(&dh, 0, sizeof(dh)); */ magic = ntohl(readvalue(4)); dh->version = ntohl(readvalue(4)); done = 0; while (!done) { tag = readchar(); switch (tag) { case 'v': dh->volumeId = ntohl(readvalue(4)); break; case 'n': for (i = 0, c = 'a'; c != '\0'; i++) { dh->volumeName[i] = c = readchar(); } dh->volumeName[i] = c; break; case 't': dh->nDumpTimes = ntohl(readvalue(2)) >> 1; if (dh->nDumpTimes > MAXDUMPTIMES) { fprintf(stderr, "Too many dump times in header (%d > %d)\n", dh->nDumpTimes, MAXDUMPTIMES); dh->nDumpTimes = MAXDUMPTIMES; } for (i = 0; i < dh->nDumpTimes; i++) { dh->dumpTimes[i].from = ntohl(readvalue(4)); dh->dumpTimes[i].to = ntohl(readvalue(4)); } break; default: done = 1; break; } } return ((afs_int32) tag); } struct volumeHeader { afs_int32 volumeId; char volumeName[100]; afs_int32 volType; afs_int32 uniquifier; afs_int32 parentVol; afs_int32 cloneId; afs_int32 maxQuota; afs_int32 minQuota; afs_int32 diskUsed; afs_int32 fileCount; afs_int32 accountNumber; afs_int32 owner; afs_int32 creationDate; afs_int32 accessDate; afs_int32 updateDate; afs_int32 expirationDate; afs_int32 backupDate; afs_int32 dayUseDate; afs_int32 dayUse; afs_int32 weekCount; afs_int32 weekUse[100]; /* weekCount of these */ char motd[1024]; int inService; int blessed; char message[1024]; afs_int32 volUpdateCounter; }; afs_int32 ReadVolumeHeader(afs_int32 count) { struct volumeHeader vh; int i, done; char tag, c; /* memset(&vh, 0, sizeof(vh)); */ done = 0; while (!done) { tag = readchar(); switch (tag) { case 'i': vh.volumeId = ntohl(readvalue(4)); break; case 'v': (void)ntohl(readvalue(4)); /* version stamp - ignore */ break; case 'n': for (i = 0, c = 'a'; c != '\0'; i++) { vh.volumeName[i] = c = readchar(); } vh.volumeName[i] = c; break; case 's': vh.inService = ntohl(readvalue(1)); break; case 'b': vh.blessed = ntohl(readvalue(1)); break; case 'u': vh.uniquifier = ntohl(readvalue(4)); break; case 't': vh.volType = ntohl(readvalue(1)); break; case 'p': vh.parentVol = ntohl(readvalue(4)); break; case 'c': vh.cloneId = ntohl(readvalue(4)); break; case 'q': vh.maxQuota = ntohl(readvalue(4)); break; case 'm': vh.minQuota = ntohl(readvalue(4)); break; case 'd': vh.diskUsed = ntohl(readvalue(4)); break; case 'f': vh.fileCount = ntohl(readvalue(4)); break; case 'a': vh.accountNumber = ntohl(readvalue(4)); break; case 'o': vh.owner = ntohl(readvalue(4)); break; case 'C': vh.creationDate = ntohl(readvalue(4)); break; case 'A': vh.accessDate = ntohl(readvalue(4)); break; case 'U': vh.updateDate = ntohl(readvalue(4)); break; case 'E': vh.expirationDate = ntohl(readvalue(4)); break; case 'B': vh.backupDate = ntohl(readvalue(4)); break; case 'O': for (i = 0, c = 'a'; c != '\0'; i++) { vh.message[i] = c = readchar(); } vh.volumeName[i] = c; break; case 'W': vh.weekCount = ntohl(readvalue(2)); for (i = 0; i < vh.weekCount; i++) { vh.weekUse[i] = ntohl(readvalue(4)); } break; case 'M': for (i = 0, c = 'a'; c != '\0'; i++) { vh.motd[i] = c = readchar(); } break; case 'D': vh.dayUseDate = ntohl(readvalue(4)); break; case 'Z': vh.dayUse = ntohl(readvalue(4)); break; case 'V': readvalue(4); /*volUpCounter*/ break; default: done = 1; break; } } return ((afs_int32) tag); } struct vNode { afs_int32 vnode; afs_int32 uniquifier; afs_int32 type; afs_int32 linkCount; afs_int32 dataVersion; afs_int32 unixModTime; afs_int32 servModTime; afs_int32 author; afs_int32 owner; afs_int32 group; afs_int32 modebits; afs_int32 parent; char acl[192]; afs_sfsize_t dataSize; }; #define MAXNAMELEN 256 static int ReadVNode(afs_int32 count, afs_int32 *return_tag) { struct vNode vn; int code, i, done; char tag; char *dirname = NULL, *lname = NULL, *slinkname = NULL; char linkname[MAXNAMELEN+1]; char *parentdir = NULL, *vflink = NULL; char *filename = NULL; char fname[MAXNAMELEN+1]; int len; afs_int32 vnode; afs_int32 mode = 0; afs_uint32 hi, lo; /* memset(&vn, 0, sizeof(vn)); */ vn.dataSize = 0; vn.vnode = 0; vn.parent = 0; vn.type = 0; vn.vnode = ntohl(readvalue(4)); vn.uniquifier = ntohl(readvalue(4)); done = 0; while (!done) { tag = readchar(); switch (tag) { case 't': vn.type = ntohl(readvalue(1)); break; case 'l': vn.linkCount = ntohl(readvalue(2)); break; case 'v': vn.dataVersion = ntohl(readvalue(4)); break; case 'm': vn.unixModTime = ntohl(readvalue(4)); break; case 's': vn.servModTime = ntohl(readvalue(4)); break; case 'a': vn.author = ntohl(readvalue(4)); break; case 'o': vn.owner = ntohl(readvalue(4)); break; case 'g': vn.group = ntohl(readvalue(4)); break; case 'b': vn.modebits = ntohl(readvalue(2)); break; case 'p': vn.parent = ntohl(readvalue(4)); break; case 'A': readdata(vn.acl, 192); /* Skip ACL data */ break; case 'h': hi = ntohl(readvalue(4)); lo = ntohl(readvalue(4)); FillInt64(vn.dataSize, hi, lo); goto common_vnode; case 'f': vn.dataSize = ntohl(readvalue(4)); common_vnode: /* parentdir is the name of this dir's vnode-file-link * or this file's parent vnode-file-link. * "./AFSDir-<#>". It's a symbolic link to its real dir. * The parent dir and symbolic link to it must exist. */ vnode = ((vn.type == 2) ? vn.vnode : vn.parent); if (vnode == 1) { free(parentdir); parentdir = strdup(rootdir); if (!parentdir) { code = ENOMEM; goto common_exit; } } else { free(parentdir); if (asprintf(&parentdir, "%s" OS_DIRSEP "%s%d", rootdir, ADIR, vnode) < 0) { parentdir = NULL; code = ENOMEM; goto common_exit; } len = readlink(parentdir, linkname, MAXNAMELEN); if (len < 0) { /* parentdir does not exist. So create an orphan dir. * and then link the parentdir to the orphaned dir. */ if (asprintf(&lname, "%s" OS_DIRSEP "%s%d", rootdir, ODIR, vnode) < 0) { lname = NULL; code = ENOMEM; goto common_exit; } code = mkdir(lname, 0777); if ((code < 0) && (errno != EEXIST)) { fprintf(stderr, "Error creating directory %s code=%d;%d\n", lname, code, errno); } free(lname); /* Link the parentdir to it - now parentdir exists */ if (asprintf(&lname, "%s%d/", ODIR, vnode) < 0) { lname = NULL; code = ENOMEM; goto common_exit; } code = symlink(lname, parentdir); if (code) { fprintf(stderr, "Error creating symlink %s -> %s code=%d;%d\n", parentdir, lname, code, errno); } free(lname); lname = NULL; } } if (vn.type == 2) { /*ITSADIR*/ /* We read the directory entries. If the entry is a * directory, the subdir is created and the root dir * will contain a link to it. If its a file, we only * create a symlink in the dir to the file name. */ char *buffer; unsigned short j; afs_int32 this_vn; char *this_name; struct DirEntry { char flag; char length; unsigned short next; struct MKFid { afs_int32 vnode; afs_int32 vunique; } fid; char name[20]; }; struct Pageheader { unsigned short pgcount; unsigned short tag; char freecount; char freebitmap[8]; char padding[19]; }; struct DirHeader { struct Pageheader header; char alloMap[128]; unsigned short hashTable[128]; }; struct Page0 { struct DirHeader header; struct DirEntry entry[1]; } *page0; buffer = NULL; buffer = calloc(1, vn.dataSize); if (!buffer) { code = ENOMEM; goto common_exit; } readdata(buffer, vn.dataSize); page0 = (struct Page0 *)buffer; /* Step through each bucket in the hash table, i, * and follow each element in the hash chain, j. * This gives us each entry of the dir. */ for (i = 0; i < 128; i++) { for (j = ntohs(page0->header.hashTable[i]); j; j = ntohs(page0->entry[j].next)) { j -= 13; this_vn = ntohl(page0->entry[j].fid.vnode); this_name = page0->entry[j].name; if ((strcmp(this_name, ".") == 0) || (strcmp(this_name, "..") == 0)) continue; /* Skip these */ /* For a directory entry, create it. Then create the * link (from the rootdir) to this directory. */ if (this_vn & 1) { /*ADIRENTRY*/ /* dirname is the directory to create. * vflink is what will link to it. */ if (asprintf(&dirname, "%s" OS_DIRSEP "%s", parentdir, this_name) < 0) { free(buffer); code = ENOMEM; goto common_exit; } if (asprintf(&vflink, "%s" OS_DIRSEP "%s%d", rootdir, ADIR, this_vn) < 0) { free(buffer); free(dirname); code = ENOMEM; goto common_exit; } /* The link and directory may already exist */ len = readlink(vflink, linkname, MAXNAMELEN); if (len < 0) { /* Doesn't already exist - so create the directory. * umask will pare the mode bits down. */ code = mkdir(dirname, 0777); if ((code < 0) && (errno != EEXIST)) { fprintf(stderr, "Error creating directory %s code=%d;%d\n", dirname, code, errno); } } else { /* Does already exist - so move the directory. * It was created originally as orphaned. */ linkname[len - 1] = '\0'; /* remove '/' at end */ if (asprintf(&lname, "%s" OS_DIRSEP "%s", rootdir, linkname) < 0) { free(buffer); free(dirname); free(vflink); lname = NULL; code = ENOMEM; goto common_exit; } code = rename(lname, dirname); if (code) { fprintf(stderr, "Error renaming %s to %s code=%d;%d\n", lname, dirname, code, errno); } free(lname); lname = NULL; } free(dirname); dirname = NULL; /* Now create/update the link to the new/moved directory */ if (vn.vnode == 1) { if (asprintf(&dirname, "%s/", this_name) < 0) { free(buffer); free(vflink); code = ENOMEM; goto common_exit; } } else { if (asprintf(&dirname, "%s%d/%s/", ADIR, vn.vnode, this_name) < 0) { free(buffer); free(vflink); code = ENOMEM; goto common_exit; } } unlink(vflink); code = symlink(dirname, vflink); if (code) { fprintf(stderr, "Error creating symlink %s -> %s code=%d;%d\n", vflink, dirname, code, errno); } free(dirname); free(vflink); dirname = NULL; vflink = NULL; } /*ADIRENTRY*/ /* For a file entry, we remember the name of the file * by creating a link within the directory. Restoring * the file will later remove the link. */ else { /*AFILEENTRY*/ if (asprintf(&vflink, "%s" OS_DIRSEP "%s%d", parentdir, AFILE, this_vn) < 0) { free(buffer); code = ENOMEM; goto common_exit; } code = symlink(this_name, vflink); if ((code < 0) && (errno != EEXIST)) { fprintf(stderr, "Error creating symlink %s -> %s code=%d;%d\n", vflink, page0->entry[j].name, code, errno); } free(vflink); vflink = NULL; } /*AFILEENTRY*/} } free(buffer); buffer = NULL; } /*ITSADIR*/ else if (vn.type == 1) { /*ITSAFILE*/ /* A file vnode. So create it into the desired directory. A * link should exist in the directory naming the file. */ int fid; int lfile; afs_sfsize_t size, s; ssize_t count; /* Check if its vnode-file-link exists. If not, * then the file will be an orphaned file. */ lfile = 1; if (asprintf(&filename, "%s" OS_DIRSEP "%s%d", parentdir, AFILE, vn.vnode) < 0) { code = ENOMEM; goto common_exit; } len = readlink(filename, fname, MAXNAMELEN); if (len < 0) { free(filename); if (asprintf(&filename, "%s" OS_DIRSEP "%s%d", rootdir, OFILE, vn.vnode) < 0) { code = ENOMEM; goto common_exit; } lfile = 0; /* no longer a linked file; a direct path */ } /* Create a mode for the file. Use the owner bits and * duplicate them across group and other. The umask * will remove what we don't want. */ mode = (vn.modebits >> 6) & 0x7; mode |= (mode << 6) | (mode << 3); /* Write the file out */ fid = open(filename, (O_CREAT | O_WRONLY | O_TRUNC), mode); if (fid < 0) { fprintf(stderr, "Open %s: Errno = %d\n", filename, errno); goto open_fail; } size = vn.dataSize; while (size > 0) { s = (afs_int32) ((size > BUFSIZE) ? BUFSIZE : size); code = fread(buf, 1, s, dumpfile); if (code != s) { if (code < 0) fprintf(stderr, "Code = %d; Errno = %d\n", code, errno); else { fprintf(stderr, "Read %llu bytes out of %llu\n", (afs_uintmax_t) (vn.dataSize - size), (afs_uintmax_t) vn.dataSize); } break; } if (code > 0) { count = write(fid, buf, code); if (count < 0) { fprintf(stderr, "Count = %ld, Errno = %d\n", (long)count, errno); break; } else if (count != code) { fprintf(stderr, "Wrote %llu bytes out of %llu\n", (afs_uintmax_t) count, (afs_uintmax_t) code); break; } size -= code; } } close(fid); if (size != 0) { fprintf(stderr, " File %s (%s) is incomplete\n", filename, fname); } open_fail: /* Remove the link to the file */ if (lfile) { unlink(filename); } free(filename); filename = NULL; } /*ITSAFILE*/ else if (vn.type == 3) { /*ITSASYMLINK*/ /* A symlink vnode. So read it into the desired directory. This could * also be a mount point. If the volume is being restored to AFS, this * will become a mountpoint. If not, it becomes a symlink to no-where. */ afs_int32 s; /* Check if its vnode-file-link exists and create pathname * of the symbolic link. If it doesn't exist, * then the link will be an orphaned link. */ if (asprintf(&slinkname, "%s" OS_DIRSEP "%s%d", parentdir, AFILE, vn.vnode) < 0) { code = ENOMEM; goto common_exit; } len = readlink(slinkname, fname, MAXNAMELEN); if (len < 0) { if (asprintf(&filename, "%s" OS_DIRSEP "%s%d", rootdir, OFILE, vn.vnode) < 0) { free(slinkname); code = ENOMEM; goto common_exit; } } else { fname[len] = '\0'; if (asprintf(&filename, "%s" OS_DIRSEP "%s", parentdir, fname) < 0) { free(slinkname); code = ENOMEM; goto common_exit; } } /* Read the link in, delete it, and then create it */ readdata(buf, vn.dataSize); /* If a mountpoint, change its link path to mountroot */ s = strlen(buf); if (((buf[0] == '%') || (buf[0] == '#')) && (buf[s - 1] == '.')) { /* This is a symbolic link */ buf[s - 1] = 0; /* Remove prefix '.' */ lname = strdup(&buf[1]); /* Remove postfix '#' or '%' */ if (!lname) { free(filename); free(slinkname); code = ENOMEM; goto common_exit; } if (strlcpy(buf, mntroot, BUFSIZE) >= BUFSIZE) { free(filename); free(slinkname); code = EMSGSIZE; goto common_exit; } if (strlcat(buf, lname, BUFSIZE) >= BUFSIZE) { free(filename); free(slinkname); code = EMSGSIZE; goto common_exit; } free(lname); lname = NULL; } unlink(filename); code = symlink(buf, filename); if (code) { fprintf(stderr, "Error creating symlink %s -> %s code=%d;%d\n", filename, buf, code, errno); } /* Remove the symbolic link */ unlink(slinkname); free(slinkname); free(filename); slinkname = NULL; filename = NULL; } /*ITSASYMLINK*/ else { fprintf(stderr, "Unknown Vnode block\n"); } break; default: done = 1; break; } } if (vn.type == 0) inc_dump = 1; *return_tag = (afs_int32)tag; code = 0; common_exit: free(parentdir); free(lname); return code; } static int WorkerBee(struct cmd_syndesc *as, void *arock) { int code = 0, len; afs_int32 type, count, vcount; DIR *dirP, *dirQ; struct dirent *dirE, *dirF; char *name = NULL; char *thisdir, *t; struct DumpHeader dh; /* Defined in dump.h */ thisdir = calloc(1, MAXPATHLEN+4); if (!thisdir) goto mem_error_exit; if (as->parms[0].items) { /* -file */ dumpfile = fopen(as->parms[0].items->data, "r"); if (!dumpfile) { fprintf(stderr, "Cannot open '%s'. Code = %d\n", as->parms[0].items->data, errno); goto cleanup; } } else { dumpfile = (FILE *) stdin; /* use stdin */ } /* Read the dump header. From it we get the volume name */ type = ntohl(readvalue(1)); if (type != 1) { fprintf(stderr, "Expected DumpHeader\n"); code = -1; goto cleanup; } type = ReadDumpHeader(&dh); /* Get the root directory we restore to */ if (as->parms[1].items) { /* -dir */ if (strlcpy(rootdir, as->parms[1].items->data, sizeof(rootdir)) >= sizeof(rootdir)) goto str_error_exit; } else { strcpy(rootdir, "."); } if (strlcat(rootdir, "/", sizeof(rootdir)) >= sizeof(rootdir)) goto str_error_exit; /* Append the RW volume name to the root directory */ if (strlcat(rootdir, dh.volumeName, sizeof(rootdir)) >= sizeof(rootdir)) goto str_error_exit; len = strlen(rootdir); if (strcmp(".backup", rootdir + len - 7) == 0) { rootdir[len - 7] = 0; } else if (strcmp(".readonly", rootdir + len - 9) == 0) { rootdir[len - 9] = 0; } /* Append the extension we asked for */ if (as->parms[2].items) { if (strlcat(rootdir, as->parms[2].items->data, sizeof(rootdir)) >= sizeof(rootdir)) /* -extension */ goto str_error_exit; } /* The mountpoint root is either specifid in -mountpoint * or -dir or the current working dir. */ if ((as->parms[3].items) || (as->parms[1].items)) { /* -mountpoint or -dir */ t = (char *)getcwd(thisdir, MAXPATHLEN); /* remember current dir */ if (!t) { fprintf(stderr, "Cannot get pathname of current working directory: %s\n", thisdir); code = -1; goto cleanup; } /* Change to the mount point dir */ code = chdir((as->parms[3].items ? as->parms[3].items->data : as-> parms[1].items->data)); if (code) { fprintf(stderr, "Mount point directory not found: Error = %d\n", errno); goto cleanup; } t = (char *)getcwd(mntroot, MAXPATHLEN); /* get its full pathname */ if (!t) { fprintf(stderr, "Cannot determine pathname of mount point root directory: %s\n", mntroot); code = -1; goto cleanup; } if (strlcat(mntroot, "/", sizeof(mntroot)) >= sizeof(mntroot)) /* append '/' to end of it */ goto str_error_exit; code = chdir(thisdir); /* return to original working dir */ if (code) { fprintf(stderr, "Cannot find working directory: Error = %d\n", errno); goto cleanup; } } else { /* use current directory */ t = (char *)getcwd(mntroot, MAXPATHLEN); /* get full pathname of current dir */ if (!t) { fprintf(stderr, "Cannot determine pathname of current working directory: %s\n", mntroot); code = -1; goto cleanup; } } if (strlcat(mntroot, "/", sizeof(mntroot)) >= sizeof(mntroot)) /* append '/' to end of it */ goto str_error_exit; /* Set the umask for the restore */ if (as->parms[4].items) { /* -umask */ afs_int32 mask; mask = strtol(as->parms[4].items->data, 0, 8); fprintf(stderr, "Umask set to 0%03o\n", mask); umask(mask); } fprintf(stderr, "Restoring volume dump of '%s' to directory '%s'.\n", dh.volumeName, rootdir); code = mkdir(rootdir, 0777); if ((code < 0) && (errno != EEXIST)) { fprintf(stderr, "Error creating directory %s code=%d;%d\n", rootdir, code, errno); } for (count = 1; type == 2; count++) { type = ReadVolumeHeader(count); for (vcount = 1; type == 3; vcount++) { code = ReadVNode(vcount, &type); if (code == ENOMEM) goto mem_error_exit; if (code == EMSGSIZE) goto str_error_exit; } } if (type != 4) { fprintf(stderr, "Expected End-of-Dump\n"); code = -1; goto cleanup; } cleanup: /* For incremental restores, Follow each directory link and * remove an "AFSFile" links. */ if (inc_dump) { fprintf(stderr, "An incremental dump.\n"); dirP = opendir(rootdir); while (dirP && (dirE = readdir(dirP))) { if (strncmp(dirE->d_name, ADIR, strlen(ADIR)) == 0) { if (asprintf(&name, "%s" OS_DIRSEP "%s", rootdir, dirE->d_name) < 0) goto mem_error_exit; dirQ = opendir(name); free(name); name = NULL; while (dirQ && (dirF = readdir(dirQ))) { if (strncmp(dirF->d_name, AFILE, strlen(AFILE)) == 0) { if (asprintf(&name, "%s" OS_DIRSEP "%s/%s", rootdir, dirE->d_name, dirF->d_name) < 0) goto mem_error_exit; unlink(name); free(name); name = NULL; } } if (dirQ) closedir(dirQ); } else if (strncmp(dirE->d_name, AFILE, strlen(AFILE)) == 0) { if (asprintf(&name, "%s" OS_DIRSEP "%s", rootdir, dirE->d_name) < 0) goto mem_error_exit; unlink(name); free(name); name = NULL; } } if (dirP) closedir(dirP); } /* Now go through and remove all the directory links */ dirP = opendir(rootdir); while (dirP && (dirE = readdir(dirP))) { if (strncmp(dirE->d_name, ADIR, strlen(ADIR)) == 0) { if (asprintf(&name, "%s" OS_DIRSEP "%s", rootdir, dirE->d_name) < 0) goto mem_error_exit; unlink(name); free(name); name = NULL; } } if (dirP) closedir(dirP); free(thisdir); return (code); mem_error_exit: /* Error allocating memory -- quick exit */ fprintf(stderr, "Memory allocation error!\n"); free(thisdir); return -1; str_error_exit: /* Str length error */ fprintf(stderr, "String exceeded buffer size\n"); free(thisdir); return -1; } int main(int argc, char **argv) { struct cmd_syndesc *ts; setlinebuf(stdout); ts = cmd_CreateSyntax(NULL, WorkerBee, NULL, 0, "vldb check"); cmd_AddParm(ts, "-file", CMD_SINGLE, CMD_OPTIONAL, "dump file"); cmd_AddParm(ts, "-dir", CMD_SINGLE, CMD_OPTIONAL, "restore dir"); cmd_AddParm(ts, "-extension", CMD_SINGLE, CMD_OPTIONAL, "name extension"); cmd_AddParm(ts, "-mountpoint", CMD_SINGLE, CMD_OPTIONAL, "mount point root"); cmd_AddParm(ts, "-umask", CMD_SINGLE, CMD_OPTIONAL, "mode mask"); return cmd_Dispatch(argc, argv); }