📄 simple_restore.c
字号:
if (n1[0] == '.' && n1[1] == '/') n1 += 2; else if (n1[0] == '/' || (n1[0] == '.' && n1[1] == '\0')) n1++; if (n2[0] == '.' && n2[1] == '/') n2 += 2; else if (n2[0] == '/' || (n2[0] == '.' && n2[1] == '\0')) n2++; if (strcmp(n1, n2) != 0) { (*modParams->logFunc)(modParams->daemonCookie, NDMP_LOG_NORMAL, 0, "Restore: ERROR: expected file: %s; read: %s.\n", nameEnt->original_path, name); return(EIO); } err = restoreFile(info, name, &fileStat); if (err < 0) { return(EIO); } /* * Notify the NDMP client that a file recovery succeeded or * failed. */ (*modParams->fileRecoveredFunc)(modParams->daemonCookie, name, (err == 0 ? EPERM : 0)); /* * Check if the restore has been aborted * or the NDMP connection broken. */ (*modParams->dispatchFunc)(modParams->daemonCookie, FALSE); if (info->params->abortFlag == TRUE) { return(EINTR); } } return(0);}/* * checkFile * Determine if the specified file name should be restored by * comparing the name to each name in the restore list. * Look for exact match as well as if the name is a parent directory * to a file in the restore list or is contained in a directory * specified in the restore list. * * Before comparing names, names are normalized by removing any * leading / or ./. A name of .\0 is normalized to \0. * A resulting normalized name of \0 implies the backup root * directory of the dump. * * Parameters: * info (input) - restore info. * name (input) - file name to check. * * Returns: * -2 - no match. * -1 - name is a parent directory of a file in the list or * name is contained in a directory from the list. * otherwise - index into list of the exact matching name. */static intcheckFile(RestoreInfo* info, char* name){ char* ckname; u_long cknamelen; u_long namelen; u_long i; int match = -2; NdmpdModuleParams* modParams = info->params->modParams; /* * Remove leading ./ * Force . (backup root directory) to match everything. */ if (name[0] == '.' && name[1] == '/') name += 2; else if (name[0] == '.' && name[1] == '\0') name++; /* * Always restore the backup root directory. * Still need to check for an exact match. */ if (name[0] == '\0') match = -1; /* * Check against each name in the restore list until a * match is found or until the end of the list is encountered. */ for (i = 0; ; i++) { ndmp_name* nameEnt; nameEnt = (*modParams->getNameFunc)(modParams->daemonCookie, i); if (nameEnt == 0) break; ckname = nameEnt->original_path; /* Remove leading ./ or / */ if (ckname[0] == '.' && ckname[1] == '/') ckname += 2; else if (ckname[0] == '/' || (ckname[0] == '.' && ckname[1] == '\0')) ckname++; /* Root directory matches all names. */ if (ckname[0] == '\0') match = -1; cknamelen = strlen(ckname); namelen = strlen(name); if (namelen == cknamelen) { if (strcmp(name, ckname) == 0) return(i); continue; } if (namelen < cknamelen) { /* * Its only a match if name is a parent directory of ckname. */ if (ckname[namelen] != '/') continue; if (strncmp(name, ckname, namelen) != 0) continue; /* Found a match but keep looking for an exact match. */ match = -1; continue; } /* * Its only a match now if ckname is a parent directory to name. */ if (name[cknamelen] != '/') continue; if (strncmp(name, ckname, cknamelen) != 0) continue; /* Found a match but keep looking for an exact match. */ match = -1; } return(match);}/* * restoreFile * Restores the specified file. * * Parameters: * info (input) - restore info. * name (input) - name of file being restored. * fileStat (input) - file stat data. * * Returns: * -1 - error reading file dump data. * 0 - error creating file or setting attributes. * 1 - file successfully restored. */static intrestoreFile(RestoreInfo* info, char* name, struct stat* fileStat){ char path[MAXPATHLEN+1]; NdmpdModuleParams* modParams = info->params->modParams; if (strlen(name) + strlen(info->destDir) > MAXPATHLEN) { (*modParams->logFunc)(modParams->daemonCookie, NDMP_LOG_NORMAL, 0, "Restore: ERROR: MAXPATHLEN exceeded for: %s%s.\n", info->destDir, name); return(discardFile(info, name, fileStat)); } /* * Remove leading ./ * This is not really necessary but is done so that the file names * in error messages don't contain embedded /./ */ if (name[0] == '.' && name[1] == '/') name += 2; else if (name[0] == '.') name++; strcpy(path, info->destDir); strcat(path, name); /* * Don't overwrite files. * This is enforced mostly to prevent buggy code from * destroying the filesystem. * It also simplifies the code since since existing files * don't have to be dealt with. This is especially a problem if * the file exists and is of a different type than the file being restored. */ if (access(path, F_OK) == 0) { (*modParams->logFunc)(modParams->daemonCookie, NDMP_LOG_NORMAL, 0, "Restore: ERROR: file exists: %s.\n", path); return(discardFile(info, path, fileStat)); } /* * For direct access restores, the parent directories only get * created if explictly specified in the name list so create * them here if they do not already exist. */ if (info->direct && (fileStat->st_mode & S_IFMT) != S_IFDIR) { char* p = strrchr(path, '/'); if (p != 0 && p != path) { *p = '\0'; if (access(path, F_OK) != 0) { if (mkdirp(path, fileStat->st_mode&S_IAMB) < 0) { (*modParams->logFunc)(modParams->daemonCookie, NDMP_LOG_NORMAL, 0, "Restore: ERROR: creating directory: %s: %s.\n", path, strerror(errno)); *p = '/'; return(0); } } *p = '/'; } } switch (fileStat->st_mode & S_IFMT) { case S_IFDIR: { if (mkdirp(path, fileStat->st_mode&S_IAMB) < 0) { (*modParams->logFunc)(modParams->daemonCookie, NDMP_LOG_NORMAL, 0, "Restore: ERROR: creating directory: %s: %s.\n", path, strerror(errno)); return(0); } break; } case S_IFIFO: case S_IFBLK: case S_IFCHR: { if (mknod(path, fileStat->st_mode, fileStat->st_dev) < 0) { (*modParams->logFunc)(modParams->daemonCookie, NDMP_LOG_NORMAL, 0, "Restore: ERROR: creating file: %s: %s.\n", path, strerror(errno)); return(0); } break; } case S_IFREG: { int fd; caddr_t addr; if ((fd = open(path, O_RDWR|O_CREAT, fileStat->st_mode&S_IAMB)) < 0) { (*modParams->logFunc)(modParams->daemonCookie, NDMP_LOG_NORMAL, 0, "Restore: ERROR: creating file: %s: %s.\n", path, strerror(errno)); return(discardFile(info, path, fileStat)); } /* Set the file length so mmap works. */ if (ftruncate(fd, fileStat->st_size) < 0) { (*modParams->logFunc)(modParams->daemonCookie, NDMP_LOG_NORMAL, 0, "Restore: ERROR: setting file size: %s: %s.\n", name, strerror(errno)); (void)close(fd); return(discardFile(info, path, fileStat)); } if (fileStat->st_size == 0) { close(fd); break; } /* Map in the file. */ addr = mmap(0, fileStat->st_size, PROT_WRITE, MAP_SHARED, fd, 0); if (addr == MAP_FAILED) { (*modParams->logFunc)(modParams->daemonCookie, NDMP_LOG_NORMAL, 0, "Restore: ERROR: mapping file: %s: %s.\n", path, strerror(errno)); (void)close(fd); return(discardFile(info, path, fileStat)); } /* Read the file data into the file via the mapped address. */ if ((*modParams->readFunc)(modParams->daemonCookie, addr, fileStat->st_size) < 0) { (*modParams->logFunc)(modParams->daemonCookie, NDMP_LOG_NORMAL, 0, "Restore: ERROR: reading file data: %s: %s.\n", path, strerror(errno)); (void)munmap(addr, fileStat->st_size); (void)close(fd); return(-1); } modParams->stats->bytesProcessed += fileStat->st_size; (void)munmap(addr, fileStat->st_size); (void)close(fd); break; } case S_IFLNK: { char linkName[MAXPATHLEN]; /* * Read the link name. */ if ((*modParams->readFunc)(modParams->daemonCookie, (char*)linkName, fileStat->st_size) < 0) { (*modParams->logFunc)(modParams->daemonCookie, NDMP_LOG_NORMAL, 0, "Restore: ERROR: reading file data: %s: %s.\n", path, strerror(errno)); return(-1); } modParams->stats->bytesProcessed += fileStat->st_size; linkName[fileStat->st_size] = '\0'; if (symlink(linkName, path) < 0) { (*modParams->logFunc)(modParams->daemonCookie, NDMP_LOG_NORMAL, 0, "Restore: ERROR: creating symbolic link: %s: %s.\n", path, strerror(errno)); return(0); } break; } default: { (*modParams->logFunc)(modParams->daemonCookie, NDMP_LOG_NORMAL, 0, "Restore: ERROR: unsupported file type(0%o): %s.\n", fileStat->st_mode&S_IFMT, path); return(0); } } if (info->setUidGid == TRUE) { /* * Set file owner and group. */ if (chown(path, fileStat->st_uid, fileStat->st_gid) < 0) { (*modParams->logFunc)(modParams->daemonCookie, NDMP_LOG_NORMAL, 0, "Restore: ERROR: setting uid/gid: %s.\n", path); return(0); } } return(1);}/* * discardFile * Read and discard file data. * * Parameters: * info (input) - restore info. * name (input) - file name. * size (input) - file size. * * Returns: * -1 - error reading file data. * 0 - success. */static intdiscardFile(RestoreInfo* info, char* name, struct stat* fileStat){ int fd; caddr_t addr; NdmpdModuleParams* modParams = (NdmpdModuleParams*) info->params->modParams; #if 0 /* * No need to discard if direct access restore since seeking * is done before reading each file. */ if (info->direct == TRUE) return(0);#endif /* * Only regular files and symbolic link files have * data that needs to be discarded. */ if ((fileStat->st_mode & S_IFMT) != S_IFREG && (fileStat->st_mode & S_IFMT) != S_IFLNK) return(0); if (fileStat->st_size == 0) return(0); if ((fd = open("/dev/zero", O_RDWR)) < 0) { (*modParams->logFunc)(modParams->daemonCookie, NDMP_LOG_NORMAL, 0, "Restore: ERROR: opening /dev/zero: %s.\n", strerror(errno)); return(-1); } addr = mmap(0, fileStat->st_size, PROT_WRITE, MAP_PRIVATE, fd, 0); if (addr == MAP_FAILED) { (*modParams->logFunc)(modParams->daemonCookie, NDMP_LOG_NORMAL, 0, "Restore: ERROR: mapping /dev/zero: %s.\n", strerror(errno)); (void)close(fd); return(-1); } /* Read the file data. */ if ((*modParams->readFunc)(modParams->daemonCookie, addr, fileStat->st_size) < 0) { (*modParams->logFunc)(modParams->daemonCookie, NDMP_LOG_NORMAL, 0, "Restore: ERROR: reading file data: %s: %s.\n", name, strerror(errno)); (void)munmap(addr, fileStat->st_size); (void)close(fd); return(-1); } modParams->stats->bytesProcessed += fileStat->st_size; (void)munmap(addr, fileStat->st_size); (void)close(fd); return(0);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -