/* Filename: restore.c * Author: Mark R. Rinfret * Date: 08/02/87 * Description: Restore processing module for MRBackup * * History: (most recent change first) * * 09/19/87 -MRR- Added NewHomeDir() which creates subdirectories as * necessary when the initial backup path specifies a * subdirectory. */ #include "MRBackup.h" #ifdef DEBUG extern char debugmsg[]; #endif static char fullbackpath[256], fullhomepath[256]; static unsigned home_is_device; /* true => home is "DH:" */ /* Create a new directory on the home device. * Called with: * name: directory pathname * Returns: * false => success * true => failure */ int NewHomeDir(name) char *name; { char c; struct Lock *dirlock; int dirleng; int errnum; char dirname[256]; int nameindx = 0, nameleng; *dirname = '\0'; dirleng = 0; nameleng = strlen(name); /* Parse the pathname, one directory node at a time, creating * directories as needed. */ while (nameindx < nameleng) { if (nameindx) /* 2nd - nth pass? */ dirname[dirleng++] = '/'; /* directory separator */ while ((c = name[nameindx++]) && c != '/') dirname[dirleng++] = c; dirname[dirleng] = '\0'; /* terminate with null */ if (dirlock = Lock(dirname,SHARED_LOCK)) /* subdir exists? */ UnLock(dirlock); else { /* create subdirectory */ if ((dirlock = CreateDir(dirname))== NULL){ if ((errnum = IoErr())== ERROR_DIRECTORY_NOT_EMPTY){ sprintf(conmsg, "Directory %s already exists!\n",dirname); TypeAndSpeak(conmsg); } else { sprintf(conmsg, "ERROR %d: Unable to create directory %s\n", errnum,dirname); TypeAndSpeak(conmsg); return errnum; } } else UnLock(dirlock); } } /* endwhile */ return 0; } /* Restore files from floppy disk. */ int Restore() { int status = 0; Speak("And away we go!"); if (!IsDir(backpath)) { TypeAndSpeak("Backup path must be a device or directory name!\n"); return ERR_ABORT; } BreakPath(backpath, srcvol, srcpath); home_is_device = (homepath[strlen(homepath)-1] == ':'); status = RestoreFile(srcpath); if (status == 0) { TypeAndSpeak("Your restoration project is completed, sire.\n"); } else { sprintf(conmsg,"Restore terminated with status %d.\n",status); TypeAndSpeak(conmsg); TypeAndSpeak( "Perhaps you should check things out and try it again.\n"); } return status; } /* Restore all the files in a directory. * Called with: * lock: lock on the directory * fib: pointer to file info block * path: directory pathname (without volume) * Returns: * status (0 => success) */ int RestoreDir(lock, fib, path) struct Lock *lock; struct FileInfoBlock *fib; char *path; { struct Lock *dirlock = NULL, *filelock = NULL; char newpath[256]; int status = 0; strcpy(temp, homepath); if (*path) { if (!home_is_device) strcat(temp, "/"); strcat(temp, path); } #ifdef DEBUG sprintf(debugmsg,"Checking for directory %s\n",temp); DebugWrite(debugmsg); #endif if (!(dirlock = Lock(temp, SHARED_LOCK))) { if ((status = IoErr()) == ERROR_OBJECT_NOT_FOUND) { #ifdef DEBUG sprintf(debugmsg,"Creating directory %s\n",temp); DebugWrite(debugmsg); #endif if (status = NewHomeDir(temp)) return status; } else { sprintf(conmsg,"RestoreDir cannot lock %s: %d\n",temp, status); TypeAndSpeak(conmsg); return status; } } if (dirlock) UnLock(dirlock); while (ExNext(lock,fib)) { strcpy(newpath, path); if (*newpath) strcat(newpath, "/"); strcat(newpath, fib->fib_FileName); if (status = RestoreFile(newpath)) { /* filter out "permissable:" errors */ if (status == ERROR_OBJECT_IN_USE || status == ERROR_WRITE_PROTECTED) status = 0; else break; } } done: return status; } /* Restore one or more files according to the calling pathname. * The path argument does not contain the backup volume name. */ int RestoreFile(path) char *path; { struct FileInfoBlock *fib = NULL, *fib2 = NULL; UBYTE exists = FALSE, ignore = FALSE; struct Lock *lock = NULL; USHORT namelength; UBYTE savechar; int status = 0; if (status = CheckStop()) return status; if (!(fib = (struct FileInfoBlock *) AllocMem((long) sizeof (struct FileInfoBlock), MEMF_PUBLIC | MEMF_CHIP))) { TypeAndSpeak("RestoreFile could not allocate FIB!\n"); return ERROR_NO_FREE_STORE; } sprintf(fullbackpath, "%s:%s",srcvol,path); strcpy(fullhomepath, homepath); if (*path) { if (!home_is_device) strcat(fullhomepath, "/"); strcat(fullhomepath, path); } #ifdef DEBUG sprintf(conmsg,"fullbackpath = %s\n",fullbackpath); DebugWrite(conmsg); sprintf(conmsg,"fullhomepath = %s\n",fullhomepath); DebugWrite(conmsg); #endif if (!(lock = Lock(fullbackpath, SHARED_LOCK))) { status = IoErr(); sprintf(conmsg, "RestoreFile: can't lock %s: %d\n", fullbackpath, status); TypeAndSpeak(conmsg); goto done; } if (!Examine(lock, fib)) { status = IoErr(); sprintf(conmsg, "RestoreFile can't examine %s: %d\n", fullbackpath, status); TypeAndSpeak(conmsg); goto done; } if (fib->fib_DirEntryType > 0) { /* path is a directory */ status = RestoreDir(lock, fib, path); UnLock(lock); lock = NULL; } else { UnLock(lock); lock = NULL; /*#define NOCOPY*/ #ifndef NOCOPY /* If this file exists, then check its modification date. If * it's newer than the backup, don't replace it. */ if ((lock = Lock(fullhomepath, SHARED_LOCK))) { if (!(fib2 = (struct FileInfoBlock *) AllocMem((long) sizeof (struct FileInfoBlock), MEMF_PUBLIC | MEMF_CHIP))) { TypeAndSpeak("RestoreFile could not allocate FIB!\n"); status = ERROR_NO_FREE_STORE; goto done; } Examine(lock, fib2); UnLock(lock); lock = NULL; if (CompareDS(&fib2->fib_Date, &fib->fib_Date) >= 0) ignore = TRUE; } if (ignore) { sprintf(conmsg,"Skipping %s. Current version is newer.\n", path); TypeAndSpeak(conmsg); } else { if (!do_compress || !IsCompressed(fullhomepath)) { copyfile: sprintf(conmsg,"Copying %s\n", fullbackpath); WriteConsole(conmsg); status = CopyFile(fullbackpath, fullhomepath); } else { /* truncate the destination pathname (remove ".z") */ namelength = strlen(fullhomepath); fullhomepath[namelength-2] = '\0'; sprintf(conmsg, "Decompressing %s\n", fullbackpath); WriteConsole(conmsg); if (status = decompress(fullbackpath, fullhomepath)) { sprintf(conmsg, "Decompression of %s failed; status is %d.\n", fullbackpath, status); TypeAndSpeak(conmsg); TypeAndSpeak("I will try to copy the file, instead.\n"); /* restore ".z" to name */ fullhomepath[namelength-2] = '.'; goto copyfile; } CopyFileDate(fullbackpath, fullhomepath); } } #endif } done: if (lock) UnLock(lock); if (fib) FreeMem(fib, (long) sizeof(struct FileInfoBlock)); if (fib2) FreeMem(fib2, (long) sizeof(struct FileInfoBlock)); return status; }