📄 simple_restore.c
字号:
/* -*- Mode: C -*- * simple_restore.c * * Description : Simple restore functions. * * Copyright (c) 1996,1997 PDC, Network Appliance. All Rights Reserved. * * $Id: simple_restore.c,v 1.9 1998/05/26 03:52:23 tim Exp $ */#if !defined(lint) && !defined(SABER)static char rcsId[] __attribute__ ((unused)) = "@(#) $Id: simple_restore.c,v 1.9 1998/05/26 03:52:23 tim Exp $";#endif#include <stdlib.h>#include <unistd.h>#include <errno.h>#include <sys/types.h>#include <sys/mman.h>#include <string.h>#include <libgen.h>#include "simple_private.h"typedef struct RestoreInfo{ SimpleParams *params; bool_t setUidGid; bool_t direct; char destDir[MAXPATHLEN+1]; u_long nFiles;} RestoreInfo;static intregularRestore(RestoreInfo* info);static intdirectRestore(RestoreInfo* info);static intcheckFile(RestoreInfo* info, char* name);static intrestoreFile(RestoreInfo* info, char* name, struct stat* fileStat);static intdiscardFile(RestoreInfo* info, char* name, struct stat* fileStat);/* * simpleRestore * Restores data dumped by the simple dump module. * Sends a file recovered request for every file in the file list. * * Parameters: * params (input) - restore parameters. * * Returns: * 0 - success. * error code. */intsimpleRestore(SimpleParams* params){ RestoreInfo info; u_long nameLen; int err; NdmpdModuleParams* modParams = params->modParams; ndmp_name* nameEnt; char* directStr; info.params = params; /* * Validate restore name list and construct the destination path. * The following functionality is *not* supported: * - restore file renaming. Restoring a file with a name different * from the name of the file on the restore tape. * - multiple restore destination root directories. * * Therefore, for each recover file name entry: * - the last X characters of dest must match name where X is the * length of name. * - the first L-X characters of each dest must match where L is * the length of dest. The destination path of all * entries must be the same. */ for (info.nFiles = 0; ; info.nFiles++) { u_long destlen; nameEnt = (*modParams->getNameFunc)(modParams->daemonCookie, info.nFiles); if (nameEnt == 0) break; destlen = strlen(nameEnt->destination_dir); if (strlen(nameEnt->original_path) > destlen) { (*modParams->logFunc)(modParams->daemonCookie, NDMP_LOG_NORMAL, 0, "Restore: ERROR: name entry %ld: name is longer than dest.\n", info.nFiles); return(EINVAL); } destlen -= strlen(nameEnt->original_path); if (destlen > MAXPATHLEN) { (*modParams->logFunc)(modParams->daemonCookie, NDMP_LOG_NORMAL, 0, "Restore: ERROR: name entry %ld: dest longer than MAXPATHLEN.\n", info.nFiles); return(EINVAL); } /* * Source and destination name must be the same * relative to the destination directory. */ if (strcmp(nameEnt->original_path, &nameEnt->destination_dir[destlen]) != 0) { (*modParams->logFunc)(modParams->daemonCookie, NDMP_LOG_NORMAL, 0, "Restore: ERROR: name entry %ld: name/dest mismatch relative to destination directory \n", info.nFiles); return(EINVAL); } if (info.nFiles == 0) { strncpy(info.destDir, nameEnt->destination_dir, destlen); info.destDir[destlen] = '\0'; } else { /* * All files must have the same destination directory. */ if (strncmp(info.destDir, nameEnt->destination_dir, strlen(info.destDir)) != 0) { (*modParams->logFunc)(modParams->daemonCookie, NDMP_LOG_NORMAL, 0, "Restore: ERROR: name entry %ld: dest does not destination directory \n", info.nFiles); return(EINVAL); } } } if (info.nFiles == 0) { (*modParams->logFunc)(modParams->daemonCookie, NDMP_LOG_NORMAL, 0, "Restore: ERROR: empty name list.\n"); return(EINVAL); } /* * Adjust destDir so that it ends with a / */ nameLen = strlen(info.destDir); if (nameLen == 0) strcpy(info.destDir, "/"); else if (info.destDir[nameLen-1] != '/') strcat(info.destDir, "/"); if (geteuid() == 0) info.setUidGid = TRUE; else info.setUidGid = FALSE; directStr = (*modParams->getEnvFunc)(modParams->daemonCookie, "DIRECT"); if (directStr) { if (directStr[0] == 't' || directStr[0] == 'T' || directStr[0] == 'y' || directStr[0] == 'Y') info.direct = TRUE; else info.direct = FALSE; } else info.direct = FALSE; if (info.direct == TRUE) err = directRestore(&info); else err = regularRestore(&info); return(err);}/* * regularRestore * Restores files by reading each file entry on tape, checking if the file * matches an entry in the name list, and restoring the file to disk if * if it matches. * * Paramters: * info (input) - restore info. * * Returns: * error code. */static intregularRestore(RestoreInfo* info){ struct stat fileStat; struct stat zeroFileStat; char *recoveredList; NdmpdModuleParams *modParams = info->params->modParams; int err; u_long nameLen; char name[MAXPATHLEN]; memset((void*)&zeroFileStat, 0, sizeof(zeroFileStat)); recoveredList = (char*)malloc(info->nFiles); if (recoveredList == 0) { (*modParams->logFunc)(modParams->daemonCookie, NDMP_LOG_NORMAL, 0, "Restore: ERROR: malloc: %s\n", strerror(errno)); return(ENOMEM); } /* Zero the list to mark no files as having been recovered yet. */ memset((void*)recoveredList, 0, info->nFiles); for (;;) { int match; /* * Read the file status data for the next file. */ if ((*modParams->readFunc)(modParams->daemonCookie, (char*)&fileStat, sizeof(fileStat)) < 0) { err = EIO; break; } modParams->stats->bytesProcessed += sizeof(fileStat); /* * Check for end of dump marked by a zeroed file status record. */ if (memcmp((void*)&fileStat, (void*)&zeroFileStat, sizeof(fileStat)) == 0) { err = 0; break; } /* * Read the length of the file name. */ if ((*modParams->readFunc)(modParams->daemonCookie, (char*)&nameLen, sizeof(nameLen)) < 0) { err = EIO; break; } modParams->stats->bytesProcessed += sizeof(nameLen); if (nameLen > sizeof(name)) { (*modParams->logFunc)(modParams->daemonCookie, NDMP_LOG_NORMAL, 0, "Restore: ERROR: read invalid file name length.\n"); err = EIO; break; } /* * Read the file name. */ if ((*modParams->readFunc)(modParams->daemonCookie, (char*)name, nameLen) < 0) { err = EIO; break; } modParams->stats->bytesProcessed += nameLen; name[nameLen] = '\0'; /* * Check if the file should be restored. */ if ((match = checkFile(info, name)) >= -1) { err = restoreFile(info, name, &fileStat); if (err < 0) { err = EIO; break; } /* * Only notify the NDMP client that a file recovery succeeded * or failed if the file exactly matches a file from the * restore list. */ if (match >= 0) { recoveredList[match] = 1; (*modParams->fileRecoveredFunc)(modParams->daemonCookie, name, (err == 0 ? EPERM : 0)); } } else { if (discardFile(info, name, &fileStat) < 0) { err = EIO; break; } } /* * Check if the restore has been aborted * or the NDMP connection broken. */ (*modParams->dispatchFunc)(modParams->daemonCookie, FALSE); if (info->params->abortFlag == TRUE) { err = EINTR; break; } } /* * Notify client of all files in recover list that were not found. */ if (err == 0) { u_long i; for (i = 0; i < info->nFiles; i++) { ndmp_name* nameEnt; nameEnt = (*modParams->getNameFunc)(modParams->daemonCookie, i); if (recoveredList[i] == 0) (*modParams->fileRecoveredFunc)(modParams->daemonCookie, nameEnt->original_path, ENOENT); } } free(recoveredList); return(err);}/* * directRestore * Restores files by seeking the tape to the offset of each file to be * restored and restoring the file. * * Paramters: * info (input) - restore info. * * Returns: * error code. */static intdirectRestore(RestoreInfo* info){ struct stat fileStat; struct stat zeroFileStat; ndmp_name *nameEnt; NdmpdModuleParams *modParams = info->params->modParams; int err; u_long nameLen; char name[MAXPATHLEN]; char* n1; char* n2; u_long i; memset((void*)&zeroFileStat, 0, sizeof(zeroFileStat)); for (i = 0; i < info->nFiles; i++) { nameEnt = (*modParams->getNameFunc)(modParams->daemonCookie, i); if (nameEnt == 0) { (*modParams->logFunc)(modParams->daemonCookie, NDMP_LOG_NORMAL, 0, "Restore: ERROR: name list error.\n"); return(EINVAL); } if ((*modParams->seekFunc)(modParams->daemonCookie, ((u_longlong_t)nameEnt->fh_info.high << 32) + nameEnt->fh_info.low, (u_longlong_t)sizeof(fileStat) + sizeof(nameLen)) < 0) { (*modParams->logFunc)(modParams->daemonCookie, NDMP_LOG_NORMAL, 0, "Restore: ERROR: seeking.\n"); return(EIO); } /* * Read the file status data for the file. */ if ((*modParams->readFunc)(modParams->daemonCookie, (char*)&fileStat, sizeof(fileStat)) < 0) { (*modParams->logFunc)(modParams->daemonCookie, NDMP_LOG_NORMAL, 0, "Restore: ERROR: reading file status.\n"); return(EIO); } modParams->stats->bytesProcessed += sizeof(fileStat); /* * Check for end of dump marked by a zeroed file status record. */ if (memcmp((void*)&fileStat, (void*)&zeroFileStat, sizeof(fileStat)) == 0) { (*modParams->logFunc)(modParams->daemonCookie, NDMP_LOG_NORMAL, 0, "Restore: ERROR: unexpected EOF.\n"); return(EIO); } /* * Read the length of the file name. */ if ((*modParams->readFunc)(modParams->daemonCookie, (char*)&nameLen, sizeof(nameLen)) < 0) { (*modParams->logFunc)(modParams->daemonCookie, NDMP_LOG_NORMAL, 0, "Restore: ERROR: reading file name length.\n"); return(EIO); } modParams->stats->bytesProcessed += sizeof(nameLen); if (nameLen > sizeof(name)) { (*modParams->logFunc)(modParams->daemonCookie, NDMP_LOG_NORMAL, 0, "Restore: ERROR: read invalid file name length.\n"); return(EIO); } /* * Read the file name. */ if ((*modParams->readFunc)(modParams->daemonCookie, (char*)name, nameLen) < 0) { return (EIO); } modParams->stats->bytesProcessed += nameLen; name[nameLen] = '\0'; /* * Verify this is the correct file. * Need to normalize the file names by removing any leading ./ or / component * and also need to handle the . directory. */ n1 = name; n2 = nameEnt->original_path;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -