int File_copyTo( const IFile* self, const IPath* targetPath, int force ) { bool status = 0; char* target = NULL; IFile* target_file = NULL; IDirectory* target_dir = new_Directory_path( targetPath ); if ( Directory_exists( target_dir ) ) { target = CharString_cat3( Path_getCommon( targetPath ), "/", Path_getBasename( self->path ) ); } else { target = CharString_copy( Path_getCommon( targetPath ) ); } target_file = new_File( target ); if ( !File_exists( target_file ) || force ) { if ( File_open( target_file, "w" ) ) { byte buffer[256]; int read; while ( (read = File_read( self, buffer, 256 )) ) { File_write( target_file, buffer, read ); status = 1; } if ( !status ) { fprintf( stdout, "File.c::copyTo: could not copy data\n" ); } } File_close( target_file ); } free_Directory( target_dir ); free_File( target_file ); free_CharString( target ); return status; }
Errors Misc_executeCommand(const char *commandTemplate, const TextMacro macros[], uint macroCount, ExecuteIOFunction stdoutExecuteIOFunction, ExecuteIOFunction stderrExecuteIOFunction, void *executeIOUserData ) { Errors error; String commandLine; StringTokenizer stringTokenizer; String token; String command; StringList argumentList; const char *path; String fileName; bool foundFlag; char const **arguments; int pipeStdin[2],pipeStdout[2],pipeStderr[2]; int pid; StringNode *stringNode; uint n,z; int status; bool sleepFlag; String stdoutLine,stderrLine; int exitcode; int terminateSignal; error = ERROR_NONE; if (commandTemplate != NULL) { commandLine = String_new(); command = File_newFileName(); StringList_init(&argumentList); // expand command line Misc_expandMacros(commandLine,commandTemplate,macros,macroCount); printInfo(3,"Execute command '%s'...",String_cString(commandLine)); // parse command String_initTokenizer(&stringTokenizer,commandLine,STRING_BEGIN,STRING_WHITE_SPACES,STRING_QUOTES,FALSE); if (!String_getNextToken(&stringTokenizer,&token,NULL)) { String_doneTokenizer(&stringTokenizer); StringList_done(&argumentList); String_delete(command); String_delete(commandLine); return ERRORX_(PARSE_COMMAND,0,String_cString(commandLine)); } File_setFileName(command,token); // parse arguments while (String_getNextToken(&stringTokenizer,&token,NULL)) { StringList_append(&argumentList,token); } String_doneTokenizer(&stringTokenizer); // find command in PATH path = getenv("PATH"); if (path != NULL) { fileName = File_newFileName(); foundFlag = FALSE; String_initTokenizerCString(&stringTokenizer,path,":","",FALSE); while (String_getNextToken(&stringTokenizer,&token,NULL) && !foundFlag) { File_setFileName(fileName,token); File_appendFileName(fileName,command); if (File_exists(fileName)) { File_setFileName(command,fileName); foundFlag = TRUE; } } String_doneTokenizer(&stringTokenizer); File_deleteFileName(fileName); } #if 0 fprintf(stderr,"%s,%d: command %s\n",__FILE__,__LINE__,String_cString(command)); stringNode = argumentList.head; while (stringNode != NULL) { fprintf(stderr,"%s,%d: argument %s\n",__FILE__,__LINE__,String_cString(stringNode->string)); stringNode = stringNode->next; } #endif /* 0 */ #if defined(HAVE_PIPE) && defined(HAVE_FORK) && defined(HAVE_WAITPID) #if 1 // create i/o pipes if (pipe(pipeStdin) != 0) { error = ERRORX_(IO_REDIRECT_FAIL,errno,String_cString(commandLine)); StringList_done(&argumentList); String_delete(command); String_delete(commandLine); return error; } if (pipe(pipeStdout) != 0) { error = ERRORX_(IO_REDIRECT_FAIL,errno,String_cString(commandLine)); close(pipeStdin[0]); close(pipeStdin[1]); StringList_done(&argumentList); String_delete(command); String_delete(commandLine); return error; } if (pipe(pipeStderr) != 0) { error = ERRORX_(IO_REDIRECT_FAIL,errno,String_cString(commandLine)); close(pipeStdout[0]); close(pipeStdout[1]); close(pipeStdin[0]); close(pipeStdin[1]); StringList_done(&argumentList); String_delete(command); String_delete(commandLine); return error; } // do fork to start separated process pid = fork(); if (pid == 0) { // close stdin, stdout, and stderr and reassign them to the pipes close(STDERR_FILENO); close(STDOUT_FILENO); close(STDIN_FILENO); // redirect stdin/stdout/stderr to pipe dup2(pipeStdin[0],STDIN_FILENO); dup2(pipeStdout[1],STDOUT_FILENO); dup2(pipeStderr[1],STDERR_FILENO); /* close unused pipe handles (the pipes are duplicated by fork(), thus there are two open ends of the pipes) */ close(pipeStderr[0]); close(pipeStdout[0]); close(pipeStdin[1]); // execute of external program n = 1+StringList_count(&argumentList)+1; arguments = (char const**)malloc(n*sizeof(char*)); if (arguments == NULL) { HALT_INSUFFICIENT_MEMORY(); } z = 0; arguments[z] = String_cString(command); z++; stringNode = argumentList.head; while (stringNode != NULL) { assert(z < n); arguments[z] = String_cString(stringNode->string); z++; stringNode = stringNode->next; } assert(z < n); arguments[z] = NULL; z++; execvp(String_cString(command),(char**)arguments); // in case exec() fail, return a default exitcode HALT_INTERNAL_ERROR("execvp() returned"); } else if (pid < 0) { error = ERRORX_(EXEC_FAIL,errno,String_cString(commandLine)); printInfo(3,"FAIL!\n"); close(pipeStderr[0]); close(pipeStderr[1]); close(pipeStdout[0]); close(pipeStdout[1]); close(pipeStdin[0]); close(pipeStdin[1]); StringList_done(&argumentList); String_delete(command); String_delete(commandLine); return error; } // close unused pipe handles (the pipe is duplicated by fork(), thus there are two open ends of the pipe) close(pipeStderr[1]); close(pipeStdout[1]); close(pipeStdin[0]); #else /* 0 */ error = ERROR_NONE; #endif /* 0 */ // wait until process terminate and read stdout/stderr stdoutLine = String_new(); stderrLine = String_new(); status = 0; while ((waitpid(pid,&status,WNOHANG) == 0) || (!WIFEXITED(status) && !WIFSIGNALED(status))) { sleepFlag = TRUE; if (readProcessIO(pipeStdout[0],stdoutLine)) { if (stdoutExecuteIOFunction != NULL) stdoutExecuteIOFunction(executeIOUserData,stdoutLine); String_clear(stdoutLine); sleepFlag = FALSE; } if (readProcessIO(pipeStderr[0],stderrLine)) { if (stderrExecuteIOFunction != NULL) stderrExecuteIOFunction(executeIOUserData,stderrLine); String_clear(stderrLine); sleepFlag = FALSE; } if (sleepFlag) { Misc_udelay(500LL*1000LL); } } while (readProcessIO(pipeStdout[0],stdoutLine)) { if (stdoutExecuteIOFunction != NULL) stdoutExecuteIOFunction(executeIOUserData,stdoutLine); String_clear(stdoutLine); } while (readProcessIO(pipeStderr[0],stderrLine)) { if (stderrExecuteIOFunction != NULL) stderrExecuteIOFunction(executeIOUserData,stderrLine); String_clear(stderrLine); } String_delete(stderrLine); String_delete(stdoutLine); // close i/o close(pipeStderr[0]); close(pipeStdout[0]); close(pipeStdin[1]); // check exit code exitcode = -1; if (WIFEXITED(status)) { exitcode = WEXITSTATUS(status); printInfo(3,"ok (exitcode %d)\n",exitcode); if (exitcode != 0) { error = ERRORX_(EXEC_FAIL,exitcode,String_cString(commandLine)); StringList_done(&argumentList); String_delete(command); String_delete(commandLine); return error; } } else if (WIFSIGNALED(status)) { terminateSignal = WTERMSIG(status); error = ERRORX_(EXEC_FAIL,terminateSignal,String_cString(commandLine)); printInfo(3,"FAIL (signal %d)\n",terminateSignal); StringList_done(&argumentList); String_delete(command); String_delete(commandLine); return error; } else { printInfo(3,"ok (unknown exit)\n"); } #elif defined(WIN32) #if 0 HANDLE hOutputReadTmp,hOutputRead,hOutputWrite; HANDLE hInputWriteTmp,hInputRead,hInputWrite; HANDLE hErrorWrite; HANDLE hThread; DWORD ThreadId; SECURITY_ATTRIBUTES sa; // Set up the security attributes struct. sa.nLength= sizeof(SECURITY_ATTRIBUTES); sa.lpSecurityDescriptor = NULL; sa.bInheritHandle = TRUE; // Create the child output pipe. if (!CreatePipe(&hOutputReadTmp,&hOutputWrite,&sa,0)) DisplayError("CreatePipe"); // Create a duplicate of the output write handle for the std error // write handle. This is necessary in case the child application // closes one of its std output handles. if (!DuplicateHandle(GetCurrentProcess(),hOutputWrite, GetCurrentProcess(),&hErrorWrite,0, TRUE,DUPLICATE_SAME_ACCESS)) DisplayError("DuplicateHandle"); // Create the child input pipe. if (!CreatePipe(&hInputRead,&hInputWriteTmp,&sa,0)) DisplayError("CreatePipe"); // Create new output read handle and the input write handles. Set // the Properties to FALSE. Otherwise, the child inherits the // properties and, as a result, non-closeable handles to the pipes // are created. if (!DuplicateHandle(GetCurrentProcess(),hOutputReadTmp, GetCurrentProcess(), &hOutputRead, // Address of new handle. 0,FALSE, // Make it uninheritable. DUPLICATE_SAME_ACCESS)) DisplayError("DupliateHandle"); if (!DuplicateHandle(GetCurrentProcess(),hInputWriteTmp, GetCurrentProcess(), &hInputWrite, // Address of new handle. 0,FALSE, // Make it uninheritable. DUPLICATE_SAME_ACCESS)) DisplayError("DupliateHandle"); // Close inheritable copies of the handles you do not want to be // inherited. if (!CloseHandle(hOutputReadTmp)) DisplayError("CloseHandle"); if (!CloseHandle(hInputWriteTmp)) DisplayError("CloseHandle"); // Get std input handle so you can close it and force the ReadFile to // fail when you want the input thread to exit. if ( (hStdIn = GetStdHandle(STD_INPUT_HANDLE)) == INVALID_HANDLE_VALUE ) DisplayError("GetStdHandle"); PrepAndLaunchRedirectedChild(hOutputWrite,hInputRead,hErrorWrite); // Close pipe handles (do not continue to modify the parent). // You need to make sure that no handles to the write end of the // output pipe are maintained in this process or else the pipe will // not close when the child process exits and the ReadFile will hang. if (!CloseHandle(hOutputWrite)) DisplayError("CloseHandle"); if (!CloseHandle(hInputRead )) DisplayError("CloseHandle"); if (!CloseHandle(hErrorWrite)) DisplayError("CloseHandle"); // Launch the thread that gets the input and sends it to the child. hThread = CreateThread(NULL,0,GetAndSendInputThread, (LPVOID)hInputWrite,0,&ThreadId); if (hThread == NULL) DisplayError("CreateThread"); // Read the child's output. ReadAndHandleOutput(hOutputRead); // Redirection is complete // Force the read on the input to return by closing the stdin handle. if (!CloseHandle(hStdIn)) DisplayError("CloseHandle"); // Tell the thread to exit and wait for thread to die. bRunThread = FALSE; if (WaitForSingleObject(hThread,INFINITE) == WAIT_FAILED) DisplayError("WaitForSingleObject"); if (!CloseHandle(hOutputRead)) DisplayError("CloseHandle"); if (!CloseHandle(hInputWrite)) DisplayError("CloseHandle"); #endif #else /* not defined(HAVE_PIPE) && defined(HAVE_FORK) && defined(HAVE_WAITPID) || WIN32 */ #error pipe()/fork()/waitpid() not available nor Win32 system! #endif /* defined(HAVE_PIPE) && defined(HAVE_FORK) && defined(HAVE_WAITPID) || WIN32 */ // free resources StringList_done(&argumentList); String_delete(command); String_delete(commandLine); } return error; }
// Determine which directory should store the user's configuration. // // For most Unix and Windows platforms: // If a config file already exists in program_dir, it will return it in priority // (Useful for development, and possibly for upgrading from DOS version) // If the standard directory doesn't exist yet, this function will attempt // to create it ($(HOME)/.grafx2, or %APPDATA%\GrafX2) // If it cannot be created, this function will return the executable's // own directory. // IN: The directory containing the executable // OUT: Write into config_dir. Trailing / or \ is kept. void Set_config_directory(const char * program_dir, char * config_dir) { // AmigaOS4 #if defined(__amigaos4__) || defined(__AROS__) strcpy(config_dir,"PROGDIR:"); // GP2X #elif defined(__GP2X__) || defined(__WIZ__) || defined(__CAANOO__) // On the GP2X, the program is installed to the sdcard, and we don't want to mess with the system tree which is // on an internal flash chip. So, keep these settings locals. strcpy(config_dir,program_dir); #elif defined(__MINT__) strcpy(config_dir,program_dir); #else char filename[MAX_PATH_CHARACTERS]; // In priority: check root directory strcpy(config_dir, program_dir); // On all the remaining targets except OSX, the executable is in ./bin #if !defined(__macosx__) strcat(config_dir, "../"); #endif strcpy(filename, config_dir); strcat(filename, CONFIG_FILENAME); if (!File_exists(filename)) { char *config_parent_dir; #if defined(__WIN32__) // "%APPDATA%\GrafX2" const char* Config_SubDir = "GrafX2"; config_parent_dir = getenv("APPDATA"); #elif defined(__BEOS__) || defined(__HAIKU__) // "~/.grafx2", the BeOS way const char* Config_SubDir = ".grafx2"; config_parent_dir = getenv("$HOME"); #elif defined(__macosx__) // "~/Library/Preferences/com.googlecode.grafx2" const char* Config_SubDir = "Library/Preferences/com.googlecode.grafx2"; config_parent_dir = getenv("HOME"); #elif defined(__MINT__) const char* Config_SubDir = ""; printf("GFX2.CFG not found in %s\n",filename); strcpy(config_parent_dir, config_dir); #else // "~/.grafx2" const char* Config_SubDir = ".grafx2"; config_parent_dir = getenv("HOME"); #endif if (config_parent_dir && config_parent_dir[0]!='\0') { int size = strlen(config_parent_dir); strcpy(config_dir, config_parent_dir); if (config_parent_dir[size-1] != '\\' && config_parent_dir[size-1] != '/') { strcat(config_dir,PATH_SEPARATOR); } strcat(config_dir,Config_SubDir); if (Directory_exists(config_dir)) { // Répertoire trouvé, ok strcat(config_dir,PATH_SEPARATOR); } else { // Tentative de création if (!Create_ConfigDirectory(config_dir)) { // Réussi strcat(config_dir,PATH_SEPARATOR); } else { // Echec: on se rabat sur le repertoire de l'executable. strcpy(config_dir,program_dir); #if defined(__macosx__) strcat(config_dir, "../"); #endif } } } } #endif }
Errors Command_compare(StringList *archiveFileNameList, EntryList *includeEntryList, PatternList *excludePatternList, JobOptions *jobOptions, ArchiveGetCryptPasswordFunction archiveGetCryptPasswordFunction, void *archiveGetCryptPasswordUserData ) { byte *archiveBuffer,*buffer; FragmentList fragmentList; String archiveFileName; Errors failError; Errors error; ArchiveInfo archiveInfo; ArchiveFileInfo archiveFileInfo; ArchiveEntryTypes archiveEntryType; FragmentNode *fragmentNode; assert(archiveFileNameList != NULL); assert(includeEntryList != NULL); assert(excludePatternList != NULL); assert(jobOptions != NULL); /* allocate resources */ archiveBuffer = (byte*)malloc(BUFFER_SIZE); if (archiveBuffer == NULL) { HALT_INSUFFICIENT_MEMORY(); } buffer = malloc(BUFFER_SIZE); if (buffer == NULL) { free(archiveBuffer); HALT_INSUFFICIENT_MEMORY(); } FragmentList_init(&fragmentList); archiveFileName = String_new(); failError = ERROR_NONE; while ( !StringList_empty(archiveFileNameList) && (failError == ERROR_NONE) ) { StringList_getFirst(archiveFileNameList,archiveFileName); printInfo(1,"Comparing archive '%s':\n",String_cString(archiveFileName)); /* open archive */ error = Archive_open(&archiveInfo, archiveFileName, jobOptions, archiveGetCryptPasswordFunction, archiveGetCryptPasswordUserData ); if (error != ERROR_NONE) { printError("Cannot open archive file '%s' (error: %s)!\n", String_cString(archiveFileName), Errors_getText(error) ); if (failError == ERROR_NONE) failError = error; continue; } /* read files */ while ( !Archive_eof(&archiveInfo) && (failError == ERROR_NONE) ) { /* get next archive entry type */ error = Archive_getNextArchiveEntryType(&archiveInfo, &archiveFileInfo, &archiveEntryType ); if (error != ERROR_NONE) { printError("Cannot not read next entry in archive '%s' (error: %s)!\n", String_cString(archiveFileName), Errors_getText(error) ); if (failError == ERROR_NONE) failError = error; break; } switch (archiveEntryType) { case ARCHIVE_ENTRY_TYPE_FILE: { String fileName; FileInfo fileInfo; uint64 fragmentOffset,fragmentSize; FragmentNode *fragmentNode; // FileInfo localFileInfo; FileHandle fileHandle; bool equalFlag; uint64 length; ulong n; ulong diffIndex; /* read file */ fileName = String_new(); error = Archive_readFileEntry(&archiveInfo, &archiveFileInfo, NULL, NULL, NULL, fileName, &fileInfo, &fragmentOffset, &fragmentSize ); if (error != ERROR_NONE) { printError("Cannot not read 'file' content of archive '%s' (error: %s)!\n", String_cString(archiveFileName), Errors_getText(error) ); String_delete(fileName); if (failError == ERROR_NONE) failError = error; break; } if ( (List_empty(includeEntryList) || EntryList_match(includeEntryList,fileName,PATTERN_MATCH_MODE_EXACT)) && !PatternList_match(excludePatternList,fileName,PATTERN_MATCH_MODE_EXACT) ) { printInfo(2," Compare file '%s'...",String_cString(fileName)); /* check file */ if (!File_exists(fileName)) { printInfo(2,"FAIL!\n"); printError("File '%s' not found!\n",String_cString(fileName)); Archive_closeEntry(&archiveFileInfo); String_delete(fileName); if (jobOptions->stopOnErrorFlag) { failError = ERROR_FILE_NOT_FOUND; } break; } if (File_getType(fileName) != FILE_TYPE_FILE) { printInfo(2,"FAIL!\n"); printError("'%s' is not a file!\n",String_cString(fileName)); Archive_closeEntry(&archiveFileInfo); String_delete(fileName); if (jobOptions->stopOnErrorFlag) { failError = ERROR_WRONG_FILE_TYPE; } break; } /* get file fragment list */ fragmentNode = FragmentList_find(&fragmentList,fileName); if (fragmentNode == NULL) { fragmentNode = FragmentList_add(&fragmentList,fileName,fileInfo.size); } //FragmentList_print(fragmentNode,String_cString(fileName)); /* open file */ error = File_open(&fileHandle,fileName,FILE_OPENMODE_READ); if (error != ERROR_NONE) { printInfo(2,"FAIL!\n"); printError("Cannot open file '%s' (error: %s)\n", String_cString(fileName), Errors_getText(error) ); Archive_closeEntry(&archiveFileInfo); String_delete(fileName); if (jobOptions->stopOnErrorFlag) { failError = error; } continue; } /* check file size */ if (fileInfo.size != File_getSize(&fileHandle)) { printInfo(2,"FAIL!\n"); printError("'%s' differ in size: expected %lld bytes, found %lld bytes\n", String_cString(fileName), fileInfo.size, File_getSize(&fileHandle) ); File_close(&fileHandle); Archive_closeEntry(&archiveFileInfo); String_delete(fileName); if (jobOptions->stopOnErrorFlag) { failError = ERROR_FILES_DIFFER; } continue; } /* check file content */ error = File_seek(&fileHandle,fragmentOffset); if (error != ERROR_NONE) { printInfo(2,"FAIL!\n"); printError("Cannot read file '%s' (error: %s)\n", String_cString(fileName), Errors_getText(error) ); File_close(&fileHandle); Archive_closeEntry(&archiveFileInfo); String_delete(fileName); if (jobOptions->stopOnErrorFlag) { failError = error; } continue; } length = 0; equalFlag = TRUE; diffIndex = 0; while ((length < fragmentSize) && equalFlag) { n = MIN(fragmentSize-length,BUFFER_SIZE); /* read archive, file */ error = Archive_readData(&archiveFileInfo,archiveBuffer,n); if (error != ERROR_NONE) { printInfo(2,"FAIL!\n"); printError("Cannot not read content of archive '%s' (error: %s)!\n", String_cString(archiveFileName), Errors_getText(error) ); if (failError == ERROR_NONE) failError = error; break; } error = File_read(&fileHandle,buffer,n,NULL); if (error != ERROR_NONE) { printInfo(2,"FAIL!\n"); printError("Cannot read file '%s' (error: %s)\n", String_cString(fileName), Errors_getText(error) ); if (jobOptions->stopOnErrorFlag) { failError = error; } break; } /* compare */ diffIndex = compare(archiveBuffer,buffer,n); equalFlag = (diffIndex >= n); if (!equalFlag) { printInfo(2,"FAIL!\n"); printError("'%s' differ at offset %llu\n", String_cString(fileName), fragmentOffset+length+(uint64)diffIndex ); if (jobOptions->stopOnErrorFlag) { failError = ERROR_FILES_DIFFER; } break; } length += n; } File_close(&fileHandle); if (failError != ERROR_NONE) { Archive_closeEntry(&archiveFileInfo); String_delete(fileName); continue; } #if 0 /* get local file info */ /* check file time, permissions, file owner/group */ #endif /* 0 */ printInfo(2,"ok\n"); /* add fragment to file fragment list */ FragmentList_addEntry(fragmentNode,fragmentOffset,fragmentSize); /* discard fragment list if file is complete */ if (FragmentList_checkEntryComplete(fragmentNode)) { FragmentList_remove(&fragmentList,fragmentNode); } /* free resources */ } else { /* skip */ printInfo(3," Compare '%s'...skipped\n",String_cString(fileName)); } /* close archive file, free resources */ Archive_closeEntry(&archiveFileInfo); String_delete(fileName); } break; case ARCHIVE_ENTRY_TYPE_IMAGE: { String imageName; DeviceInfo deviceInfo; uint64 blockOffset,blockCount; FragmentNode *fragmentNode; DeviceHandle deviceHandle; bool equalFlag; uint64 block; ulong bufferBlockCount; ulong diffIndex; /* read image */ imageName = String_new(); error = Archive_readImageEntry(&archiveInfo, &archiveFileInfo, NULL, NULL, NULL, imageName, &deviceInfo, &blockOffset, &blockCount ); if (error != ERROR_NONE) { printError("Cannot not read 'image' content of archive '%s' (error: %s)!\n", String_cString(archiveFileName), Errors_getText(error) ); String_delete(imageName); if (failError == ERROR_NONE) failError = error; break; } if ( (List_empty(includeEntryList) || EntryList_match(includeEntryList,imageName,PATTERN_MATCH_MODE_EXACT)) && !PatternList_match(excludePatternList,imageName,PATTERN_MATCH_MODE_EXACT) ) { printInfo(2," Compare image '%s'...",String_cString(imageName)); /* check if device exists */ if (!File_exists(imageName)) { printInfo(2,"FAIL!\n"); printError("Device '%s' not found!\n",String_cString(imageName)); Archive_closeEntry(&archiveFileInfo); String_delete(imageName); if (jobOptions->stopOnErrorFlag) { failError = ERROR_FILE_NOT_FOUND; } break; } /* get image fragment list */ fragmentNode = FragmentList_find(&fragmentList,imageName); if (fragmentNode == NULL) { fragmentNode = FragmentList_add(&fragmentList,imageName,deviceInfo.size); } /* open device */ error = Device_open(&deviceHandle,imageName,DEVICE_OPENMODE_READ); if (error != ERROR_NONE) { printInfo(2,"FAIL!\n"); printError("Cannot open file '%s' (error: %s)\n", String_cString(imageName), Errors_getText(error) ); Archive_closeEntry(&archiveFileInfo); String_delete(imageName); if (jobOptions->stopOnErrorFlag) { failError = error; } continue; } /* check image size */ if (deviceInfo.size != Device_getSize(&deviceHandle)) { printInfo(2,"FAIL!\n"); printError("'%s' differ in size: expected %lld bytes, found %lld bytes\n", String_cString(imageName), deviceInfo.size, Device_getSize(&deviceHandle) ); Device_close(&deviceHandle); Archive_closeEntry(&archiveFileInfo); String_delete(imageName); if (jobOptions->stopOnErrorFlag) { failError = ERROR_FILES_DIFFER; } continue; } /* check image content */ error = Device_seek(&deviceHandle,blockOffset*(uint64)deviceInfo.blockSize); if (error != ERROR_NONE) { printInfo(2,"FAIL!\n"); printError("Cannot read file '%s' (error: %s)\n", String_cString(imageName), Errors_getText(error) ); Device_close(&deviceHandle); Archive_closeEntry(&archiveFileInfo); String_delete(imageName); if (jobOptions->stopOnErrorFlag) { failError = error; } continue; } block = 0LL; equalFlag = TRUE; diffIndex = 0; while ((block < blockCount) && equalFlag) { assert(deviceInfo.blockSize > 0); bufferBlockCount = MIN(blockCount-block,BUFFER_SIZE/deviceInfo.blockSize); /* read archive, file */ error = Archive_readData(&archiveFileInfo,archiveBuffer,bufferBlockCount*deviceInfo.blockSize); if (error != ERROR_NONE) { printInfo(2,"FAIL!\n"); printError("Cannot not read content of archive '%s' (error: %s)!\n", String_cString(archiveFileName), Errors_getText(error) ); if (failError == ERROR_NONE) failError = error; break; } error = Device_read(&deviceHandle,buffer,bufferBlockCount*deviceInfo.blockSize,NULL); if (error != ERROR_NONE) { printInfo(2,"FAIL!\n"); printError("Cannot read file '%s' (error: %s)\n", String_cString(imageName), Errors_getText(error) ); if (jobOptions->stopOnErrorFlag) { failError = error; } break; } /* compare */ diffIndex = compare(archiveBuffer,buffer,bufferBlockCount*deviceInfo.blockSize); equalFlag = (diffIndex >= bufferBlockCount*deviceInfo.blockSize); if (!equalFlag) { printInfo(2,"FAIL!\n"); printError("'%s' differ at offset %llu\n", String_cString(imageName), blockOffset*(uint64)deviceInfo.blockSize+block*(uint64)deviceInfo.blockSize+(uint64)diffIndex ); if (jobOptions->stopOnErrorFlag) { failError = ERROR_FILES_DIFFER; } break; } block += (uint64)bufferBlockCount; } Device_close(&deviceHandle); if (failError != ERROR_NONE) { Archive_closeEntry(&archiveFileInfo); String_delete(imageName); continue; } #if 0 /* get local file info */ /* check file time, permissions, file owner/group */ #endif /* 0 */ printInfo(2,"ok\n"); /* add fragment to file fragment list */ FragmentList_addEntry(fragmentNode,blockOffset*(uint64)deviceInfo.blockSize,blockCount*(uint64)deviceInfo.blockSize); /* discard fragment list if file is complete */ if (FragmentList_checkEntryComplete(fragmentNode)) { FragmentList_remove(&fragmentList,fragmentNode); } /* free resources */ } else { /* skip */ printInfo(3," Compare '%s'...skipped\n",String_cString(imageName)); } /* close archive file, free resources */ Archive_closeEntry(&archiveFileInfo); String_delete(imageName); } break; case ARCHIVE_ENTRY_TYPE_DIRECTORY: { String directoryName; FileInfo fileInfo; // String localFileName; // FileInfo localFileInfo; /* read directory */ directoryName = String_new(); error = Archive_readDirectoryEntry(&archiveInfo, &archiveFileInfo, NULL, NULL, directoryName, &fileInfo ); if (error != ERROR_NONE) { printError("Cannot not read 'directory' content of archive '%s' (error: %s)!\n", String_cString(archiveFileName), Errors_getText(error) ); String_delete(directoryName); if (failError == ERROR_NONE) failError = error; break; } if ( (List_empty(includeEntryList) || EntryList_match(includeEntryList,directoryName,PATTERN_MATCH_MODE_EXACT)) && !PatternList_match(excludePatternList,directoryName,PATTERN_MATCH_MODE_EXACT) ) { printInfo(2," Compare directory '%s'...",String_cString(directoryName)); /* check directory */ if (!File_exists(directoryName)) { printInfo(2,"FAIL!\n"); printError("Directory '%s' does not exists!\n",String_cString(directoryName)); Archive_closeEntry(&archiveFileInfo); String_delete(directoryName); if (jobOptions->stopOnErrorFlag) { failError = ERROR_FILE_NOT_FOUND; } break; } if (File_getType(directoryName) != FILE_TYPE_DIRECTORY) { printInfo(2,"FAIL!\n"); printError("'%s' is not a directory!\n", String_cString(directoryName) ); Archive_closeEntry(&archiveFileInfo); String_delete(directoryName); if (jobOptions->stopOnErrorFlag) { failError = ERROR_WRONG_FILE_TYPE; } break; } #if 0 /* get local file info */ error = File_getFileInfo(directoryName,&localFileInfo); if (error != ERROR_NONE) { printError("Cannot not read local directory '%s' (error: %s)!\n", String_cString(directoryName), Errors_getText(error) ); Archive_closeEntry(&archiveFileInfo); String_delete(directoryName); if (failError == ERROR_NONE) failError = error; break; } /* check file time, permissions, file owner/group */ #endif /* 0 */ printInfo(2,"ok\n"); /* free resources */ } else { /* skip */ printInfo(3," Compare '%s'...skipped\n",String_cString(directoryName)); } /* close archive file */ Archive_closeEntry(&archiveFileInfo); String_delete(directoryName); } break; case ARCHIVE_ENTRY_TYPE_LINK: { String linkName; String fileName; FileInfo fileInfo; String localFileName; // FileInfo localFileInfo; /* read link */ linkName = String_new(); fileName = String_new(); error = Archive_readLinkEntry(&archiveInfo, &archiveFileInfo, NULL, NULL, linkName, fileName, &fileInfo ); if (error != ERROR_NONE) { printError("Cannot not read 'link' content of archive '%s' (error: %s)!\n", String_cString(archiveFileName), Errors_getText(error) ); String_delete(fileName); String_delete(linkName); if (failError == ERROR_NONE) failError = error; break; } if ( (List_empty(includeEntryList) || EntryList_match(includeEntryList,linkName,PATTERN_MATCH_MODE_EXACT)) && !PatternList_match(excludePatternList,linkName,PATTERN_MATCH_MODE_EXACT) ) { printInfo(2," Compare link '%s'...",String_cString(linkName)); /* check link */ if (!File_exists(linkName)) { printInfo(2,"FAIL!\n"); printError("Link '%s' -> '%s' does not exists!\n", String_cString(linkName), String_cString(fileName) ); Archive_closeEntry(&archiveFileInfo); String_delete(fileName); String_delete(linkName); if (jobOptions->stopOnErrorFlag) { failError = ERROR_FILE_NOT_FOUND; } break; } if (File_getType(linkName) != FILE_TYPE_LINK) { printInfo(2,"FAIL!\n"); printError("'%s' is not a link!\n", String_cString(linkName) ); Archive_closeEntry(&archiveFileInfo); String_delete(fileName); String_delete(linkName); if (jobOptions->stopOnErrorFlag) { failError = ERROR_WRONG_FILE_TYPE; } break; } /* check link content */ localFileName = String_new(); error = File_readLink(linkName,localFileName); if (error != ERROR_NONE) { printError("Cannot not read local file '%s' (error: %s)!\n", String_cString(linkName), Errors_getText(error) ); String_delete(localFileName); Archive_closeEntry(&archiveFileInfo); String_delete(fileName); String_delete(linkName); if (jobOptions->stopOnErrorFlag) { failError = error; } break; } if (!String_equals(fileName,localFileName)) { printInfo(2,"FAIL!\n"); printError("Link '%s' does not contain file '%s'!\n", String_cString(linkName), String_cString(fileName) ); String_delete(localFileName); Archive_closeEntry(&archiveFileInfo); String_delete(fileName); String_delete(linkName); if (jobOptions->stopOnErrorFlag) { failError = ERROR_FILES_DIFFER; } break; } String_delete(localFileName); #if 0 /* get local file info */ error = File_getFileInfo(linkName,&localFileInfo); if (error != ERROR_NONE) { printError("Cannot not read local file '%s' (error: %s)!\n", String_cString(linkName), Errors_getText(error) ); Archive_closeEntry(&archiveFileInfo); String_delete(fileName); String_delete(linkName); if (failError == ERROR_NONE) failError = error; break; } /* check file time, permissions, file owner/group */ #endif /* 0 */ printInfo(2,"ok\n"); /* free resources */ } else { /* skip */ printInfo(3," Compare '%s'...skipped\n",String_cString(linkName)); } /* close archive file */ Archive_closeEntry(&archiveFileInfo); String_delete(fileName); String_delete(linkName); } break; case ARCHIVE_ENTRY_TYPE_SPECIAL: { String fileName; FileInfo fileInfo; FileInfo localFileInfo; /* read special */ fileName = String_new(); error = Archive_readSpecialEntry(&archiveInfo, &archiveFileInfo, NULL, NULL, fileName, &fileInfo ); if (error != ERROR_NONE) { printError("Cannot not read 'special' content of archive '%s' (error: %s)!\n", String_cString(archiveFileName), Errors_getText(error) ); String_delete(fileName); if (failError == ERROR_NONE) failError = error; break; } if ( (List_empty(includeEntryList) || EntryList_match(includeEntryList,fileName,PATTERN_MATCH_MODE_EXACT)) && !PatternList_match(excludePatternList,fileName,PATTERN_MATCH_MODE_EXACT) ) { printInfo(2," Compare special device '%s'...",String_cString(fileName)); /* check special device */ if (!File_exists(fileName)) { printInfo(2,"FAIL!\n"); printError("Special device '%s' does not exists!\n", String_cString(fileName) ); Archive_closeEntry(&archiveFileInfo); String_delete(fileName); if (jobOptions->stopOnErrorFlag) { failError = ERROR_FILE_NOT_FOUND; } break; } if (File_getType(fileName) != FILE_TYPE_SPECIAL) { printInfo(2,"FAIL!\n"); printError("'%s' is not a special device!\n", String_cString(fileName) ); Archive_closeEntry(&archiveFileInfo); String_delete(fileName); if (jobOptions->stopOnErrorFlag) { failError = ERROR_WRONG_FILE_TYPE; } break; } /* check special settings */ error = File_getFileInfo(fileName,&localFileInfo); if (error != ERROR_NONE) { printError("Cannot not read local file '%s' (error: %s)!\n", String_cString(fileName), Errors_getText(error) ); Archive_closeEntry(&archiveFileInfo); String_delete(fileName); if (jobOptions->stopOnErrorFlag) { failError = error; } break; } if (fileInfo.specialType != localFileInfo.specialType) { printError("Different types of special device '%s'!\n", String_cString(fileName) ); Archive_closeEntry(&archiveFileInfo); String_delete(fileName); if (jobOptions->stopOnErrorFlag) { failError = error; } break; } if ( (fileInfo.specialType == FILE_SPECIAL_TYPE_CHARACTER_DEVICE) || (fileInfo.specialType == FILE_SPECIAL_TYPE_BLOCK_DEVICE) ) { if (fileInfo.major != localFileInfo.major) { printError("Different major numbers of special device '%s'!\n", String_cString(fileName) ); Archive_closeEntry(&archiveFileInfo); String_delete(fileName); if (jobOptions->stopOnErrorFlag) { failError = error; } break; } if (fileInfo.minor != localFileInfo.minor) { printError("Different minor numbers of special device '%s'!\n", String_cString(fileName) ); Archive_closeEntry(&archiveFileInfo); String_delete(fileName); if (jobOptions->stopOnErrorFlag) { failError = error; } break; } } #if 0 /* check file time, permissions, file owner/group */ #endif /* 0 */ printInfo(2,"ok\n"); /* free resources */ } else { /* skip */ printInfo(3," Compare '%s'...skipped\n",String_cString(fileName)); } /* close archive file */ Archive_closeEntry(&archiveFileInfo); String_delete(fileName); } break; default: #ifndef NDEBUG HALT_INTERNAL_ERROR_UNHANDLED_SWITCH_CASE(); #endif /* NDEBUG */ break; /* not reached */ } } /* close archive */ Archive_close(&archiveInfo); } /* check fragment lists */ for (fragmentNode = fragmentList.head; fragmentNode != NULL; fragmentNode = fragmentNode->next) { if (!FragmentList_checkEntryComplete(fragmentNode)) { printInfo(0,"Warning: incomplete entry '%s'\n",String_cString(fragmentNode->name)); if (failError == ERROR_NONE) failError = ERROR_FILE_INCOMPLETE; } } /* free resources */ String_delete(archiveFileName); FragmentList_done(&fragmentList); free(buffer); free(archiveBuffer); return failError; }
Errors File_open(FileHandle *fileHandle, const String fileName, FileOpenModes fileOpenMode ) { off_t n; Errors error; String pathName; assert(fileHandle != NULL); assert(fileName != NULL); switch (fileOpenMode) { case FILE_OPENMODE_CREATE: /* create file */ fileHandle->file = fopen(String_cString(fileName),"wb"); if (fileHandle->file == NULL) { return ERRORX(CREATE_FILE,errno,String_cString(fileName)); } fileHandle->name = String_duplicate(fileName);; fileHandle->index = 0LL; fileHandle->size = 0LL; break; case FILE_OPENMODE_READ: /* open file for reading */ fileHandle->file = fopen(String_cString(fileName),"rb"); if (fileHandle->file == NULL) { return ERRORX(OPEN_FILE,errno,String_cString(fileName)); } /* get file size */ if (fseeko(fileHandle->file,(off_t)0,SEEK_END) == -1) { error = ERRORX(IO_ERROR,errno,String_cString(fileName)); fclose(fileHandle->file); return error; } n = ftello(fileHandle->file); if (n == (off_t)-1) { error = ERRORX(IO_ERROR,errno,String_cString(fileName)); fclose(fileHandle->file); return error; } if (fseeko(fileHandle->file,(off_t)0,SEEK_SET) == -1) { error = ERRORX(IO_ERROR,errno,String_cString(fileName)); fclose(fileHandle->file); return error; } fileHandle->name = String_duplicate(fileName);; fileHandle->index = 0LL; fileHandle->size = (uint64)n; break; case FILE_OPENMODE_WRITE: /* create directory if needed */ pathName = File_getFilePathName(File_newFileName(),fileName); if (!File_exists(pathName)) { error = File_makeDirectory(pathName, FILE_DEFAULT_USER_ID, FILE_DEFAULT_GROUP_ID, FILE_DEFAULT_PERMISSION ); if (error != ERROR_NONE) { return error; } } File_deleteFileName(pathName); /* open existing file for writing */ fileHandle->file = fopen(String_cString(fileName),"r+b"); if (fileHandle->file == NULL) { if (errno == ENOENT) { fileHandle->file = fopen(String_cString(fileName),"wb"); if (fileHandle->file == NULL) { return ERRORX(OPEN_FILE,errno,String_cString(fileName)); } } else { return ERRORX(OPEN_FILE,errno,String_cString(fileName)); } } fileHandle->name = String_duplicate(fileName);; fileHandle->index = 0LL; fileHandle->size = 0LL; break; case FILE_OPENMODE_APPEND: /* create directory if needed */ pathName = File_getFilePathName(File_newFileName(),fileName); if (!File_exists(pathName)) { error = File_makeDirectory(pathName, FILE_DEFAULT_USER_ID, FILE_DEFAULT_GROUP_ID, FILE_DEFAULT_PERMISSION ); if (error != ERROR_NONE) { return error; } } File_deleteFileName(pathName); /* open existing file for writing */ fileHandle->file = fopen(String_cString(fileName),"ab"); if (fileHandle->file == NULL) { return ERRORX(OPEN_FILE,errno,String_cString(fileName)); } /* get file size */ n = ftello(fileHandle->file); if (n == (off_t)-1) { error = ERRORX(IO_ERROR,errno,String_cString(fileName)); fclose(fileHandle->file); return error; } fileHandle->name = String_duplicate(fileName);; fileHandle->index = (uint64)n; fileHandle->size = (uint64)n; break; #ifndef NDEBUG default: HALT_INTERNAL_ERROR_UNHANDLED_SWITCH_CASE(); break; /* not reached */ #endif /* NDEBUG */ } return ERROR_NONE; }
Errors File_makeDirectory(const String pathName, uint32 userId, uint32 groupId, uint32 permission ) { mode_t currentCreationMask; StringTokenizer pathNameTokenizer; String directoryName; uid_t uid; gid_t gid; Errors error; String name; assert(pathName != NULL); /* get current umask */ currentCreationMask = umask(0); umask(currentCreationMask); /* create directory including parent directories */ directoryName = File_newFileName(); File_initSplitFileName(&pathNameTokenizer,pathName); if (File_getNextSplitFileName(&pathNameTokenizer,&name)) { if (String_length(name) > 0) { File_setFileName(directoryName,name); } else { File_setFileNameChar(directoryName,FILES_PATHNAME_SEPARATOR_CHAR); } } if (!File_exists(directoryName)) { if (mkdir(String_cString(directoryName),0777 & ~currentCreationMask) != 0) { error = ERRORX(IO_ERROR,errno,String_cString(directoryName)); File_doneSplitFileName(&pathNameTokenizer); File_deleteFileName(directoryName); return error; } if ( (userId != FILE_DEFAULT_USER_ID) || (groupId != FILE_DEFAULT_GROUP_ID) ) { uid = (userId != FILE_DEFAULT_USER_ID ) ? (uid_t)userId : -1; gid = (groupId != FILE_DEFAULT_GROUP_ID) ? (gid_t)groupId : -1; if (chown(String_cString(directoryName),uid,gid) != 0) { error = ERRORX(IO_ERROR,errno,String_cString(directoryName)); File_doneSplitFileName(&pathNameTokenizer); File_deleteFileName(directoryName); return error; } } if (permission != FILE_DEFAULT_PERMISSION) { if (chmod(String_cString(directoryName),(permission|S_IXUSR|S_IXGRP|S_IXOTH) & ~currentCreationMask) != 0) { error = ERROR(IO_ERROR,errno); File_doneSplitFileName(&pathNameTokenizer); File_deleteFileName(directoryName); return error; } } } while (File_getNextSplitFileName(&pathNameTokenizer,&name)) { if (String_length(name) > 0) { File_appendFileName(directoryName,name); if (!File_exists(directoryName)) { if (mkdir(String_cString(directoryName),0777 & ~currentCreationMask) != 0) { error = ERRORX(IO_ERROR,errno,String_cString(directoryName)); File_doneSplitFileName(&pathNameTokenizer); File_deleteFileName(directoryName); return error; } if ( (userId != FILE_DEFAULT_USER_ID) || (groupId != FILE_DEFAULT_GROUP_ID) ) { uid = (userId != FILE_DEFAULT_USER_ID ) ? (uid_t)userId : -1; gid = (groupId != FILE_DEFAULT_GROUP_ID) ? (gid_t)groupId : -1; if (chown(String_cString(directoryName),uid,gid) != 0) { error = ERRORX(IO_ERROR,errno,String_cString(directoryName)); File_doneSplitFileName(&pathNameTokenizer); File_deleteFileName(directoryName); return error; } } if (permission != FILE_DEFAULT_PERMISSION) { if (chmod(String_cString(directoryName),(permission|S_IXUSR|S_IXGRP|S_IXOTH) & ~currentCreationMask) != 0) { error = ERRORX(IO_ERROR,errno,String_cString(directoryName)); File_doneSplitFileName(&pathNameTokenizer); File_deleteFileName(directoryName); return error; } } } } } File_doneSplitFileName(&pathNameTokenizer); File_deleteFileName(directoryName); return ERROR_NONE; }
Errors Command_restore(StringList *archiveFileNameList, PatternList *includePatternList, PatternList *excludePatternList, JobOptions *jobOptions, ArchiveGetCryptPasswordFunction archiveGetCryptPasswordFunction, void *archiveGetCryptPasswordUserData, RestoreStatusInfoFunction restoreStatusInfoFunction, void *restoreStatusInfoUserData, bool *pauseFlag, bool *requestedAbortFlag ) { RestoreInfo restoreInfo; byte *buffer; FileFragmentList fileFragmentList; String archiveFileName; Errors error; ArchiveInfo archiveInfo; ArchiveFileInfo archiveFileInfo; FileTypes fileType; FileFragmentNode *fileFragmentNode; assert(archiveFileNameList != NULL); assert(includePatternList != NULL); assert(excludePatternList != NULL); assert(jobOptions != NULL); /* initialize variables */ restoreInfo.includePatternList = includePatternList; restoreInfo.excludePatternList = excludePatternList; restoreInfo.jobOptions = jobOptions; restoreInfo.pauseFlag = pauseFlag; restoreInfo.requestedAbortFlag = requestedAbortFlag; restoreInfo.error = ERROR_NONE; restoreInfo.statusInfoFunction = restoreStatusInfoFunction; restoreInfo.statusInfoUserData = restoreStatusInfoUserData; restoreInfo.statusInfo.doneFiles = 0L; restoreInfo.statusInfo.doneBytes = 0LL; restoreInfo.statusInfo.skippedFiles = 0L; restoreInfo.statusInfo.skippedBytes = 0LL; restoreInfo.statusInfo.errorFiles = 0L; restoreInfo.statusInfo.errorBytes = 0LL; restoreInfo.statusInfo.fileName = String_new(); restoreInfo.statusInfo.fileDoneBytes = 0LL; restoreInfo.statusInfo.fileTotalBytes = 0LL; restoreInfo.statusInfo.storageName = String_new(); restoreInfo.statusInfo.storageDoneBytes = 0LL; restoreInfo.statusInfo.storageTotalBytes = 0LL; /* allocate resources */ buffer = malloc(BUFFER_SIZE); if (buffer == NULL) { HALT_INSUFFICIENT_MEMORY(); } FileFragmentList_init(&fileFragmentList); archiveFileName = String_new(); while ( ((restoreInfo.requestedAbortFlag == NULL) || !(*restoreInfo.requestedAbortFlag)) && !StringList_empty(archiveFileNameList) && (restoreInfo.error == ERROR_NONE) ) { /* pause */ while ((restoreInfo.pauseFlag != NULL) && (*restoreInfo.pauseFlag)) { Misc_udelay(500*1000); } StringList_getFirst(archiveFileNameList,archiveFileName); printInfo(0,"Restore archive '%s':\n",String_cString(archiveFileName)); /* open archive */ error = Archive_open(&archiveInfo, archiveFileName, jobOptions, archiveGetCryptPasswordFunction, archiveGetCryptPasswordUserData ); if (error != ERROR_NONE) { printError("Cannot open archive file '%s' (error: %s)!\n", String_cString(archiveFileName), Errors_getText(error) ); if (restoreInfo.error == ERROR_NONE) restoreInfo.error = error; continue; } String_set(restoreInfo.statusInfo.storageName,archiveFileName); updateStatusInfo(&restoreInfo); /* read files */ while ( ((restoreInfo.requestedAbortFlag == NULL) || !(*restoreInfo.requestedAbortFlag)) && !Archive_eof(&archiveInfo) && (restoreInfo.error == ERROR_NONE) ) { /* pause */ while ((restoreInfo.pauseFlag != NULL) && (*restoreInfo.pauseFlag)) { Misc_udelay(500*1000); } /* get next file type */ error = Archive_getNextFileType(&archiveInfo, &archiveFileInfo, &fileType ); if (error != ERROR_NONE) { printError("Cannot not read next entry in archive '%s' (error: %s)!\n", String_cString(archiveFileName), Errors_getText(error) ); if (restoreInfo.error == ERROR_NONE) restoreInfo.error = error; break; } switch (fileType) { case FILE_TYPE_FILE: { String fileName; FileInfo fileInfo; uint64 fragmentOffset,fragmentSize; FileFragmentNode *fileFragmentNode; String destinationFileName; String directoryName; // FileInfo localFileInfo; FileHandle fileHandle; uint64 length; ulong n; /* read file */ fileName = String_new(); error = Archive_readFileEntry(&archiveInfo, &archiveFileInfo, NULL, NULL, NULL, fileName, &fileInfo, &fragmentOffset, &fragmentSize ); if (error != ERROR_NONE) { printError("Cannot not read 'file' content of archive '%s' (error: %s)!\n", String_cString(archiveFileName), Errors_getText(error) ); String_delete(fileName); if (restoreInfo.error == ERROR_NONE) restoreInfo.error = error; continue; } if ( (List_empty(includePatternList) || PatternList_match(includePatternList,fileName,PATTERN_MATCH_MODE_EXACT)) && !PatternList_match(excludePatternList,fileName,PATTERN_MATCH_MODE_EXACT) ) { String_set(restoreInfo.statusInfo.fileName,fileName); restoreInfo.statusInfo.fileDoneBytes = 0LL; restoreInfo.statusInfo.fileTotalBytes = fragmentSize; updateStatusInfo(&restoreInfo); /* get destination filename */ destinationFileName = getDestinationFileName(String_new(), fileName, jobOptions->directory, jobOptions->directoryStripCount ); /* check if file fragment exists */ fileFragmentNode = FileFragmentList_findFile(&fileFragmentList,fileName); if (fileFragmentNode != NULL) { if (!jobOptions->overwriteFilesFlag && FileFragmentList_checkExists(fileFragmentNode,fragmentOffset,fragmentSize)) { printInfo(1," Restore file '%s'...skipped (file part %ll..%ll exists)\n", String_cString(destinationFileName), fragmentOffset, (fragmentSize > 0)?fragmentOffset+fragmentSize-1:fragmentOffset ); String_delete(destinationFileName); Archive_closeEntry(&archiveFileInfo); String_delete(fileName); continue; } } else { if (!jobOptions->overwriteFilesFlag && File_exists(destinationFileName)) { printInfo(1," Restore file '%s'...skipped (file exists)\n",String_cString(destinationFileName)); String_delete(destinationFileName); Archive_closeEntry(&archiveFileInfo); String_delete(fileName); continue; } fileFragmentNode = FileFragmentList_addFile(&fileFragmentList,fileName,fileInfo.size); } printInfo(2," Restore file '%s'...",String_cString(destinationFileName)); /* create directory if not existing */ directoryName = File_getFilePathName(String_new(),destinationFileName); if (!File_exists(directoryName)) { /* create directory */ error = File_makeDirectory(directoryName, FILE_DEFAULT_USER_ID, FILE_DEFAULT_GROUP_ID, fileInfo.permission ); if (error != ERROR_NONE) { printInfo(2,"FAIL!\n"); printError("Cannot create directory '%s' (error: %s)\n", String_cString(directoryName), Errors_getText(error) ); String_delete(directoryName); String_delete(destinationFileName); Archive_closeEntry(&archiveFileInfo); String_delete(fileName); if (restoreInfo.error == ERROR_NONE) restoreInfo.error = error; continue; } /* set owner ship */ error = File_setOwner(directoryName, (jobOptions->owner.userId != FILE_DEFAULT_USER_ID )?jobOptions->owner.userId:fileInfo.userId, (jobOptions->owner.groupId != FILE_DEFAULT_GROUP_ID)?jobOptions->owner.groupId:fileInfo.groupId ); if (error != ERROR_NONE) { if (jobOptions->stopOnErrorFlag) { printInfo(2,"FAIL!\n"); printError("Cannot set owner ship of directory '%s' (error: %s)\n", String_cString(directoryName), Errors_getText(error) ); String_delete(directoryName); String_delete(destinationFileName); Archive_closeEntry(&archiveFileInfo); String_delete(fileName); if (restoreInfo.error == ERROR_NONE) restoreInfo.error = error; continue; } else { printWarning("Cannot set owner ship of directory '%s' (error: %s)\n", String_cString(directoryName), Errors_getText(error) ); } } } String_delete(directoryName); /* write file data */ //if (fileFragmentNode == NULL) File_delete(destinationFileName,TRUE); error = File_open(&fileHandle,destinationFileName,FILE_OPENMODE_WRITE); if (error != ERROR_NONE) { printInfo(2,"FAIL!\n"); printError("Cannot create/write to file '%s' (error: %s)\n", String_cString(destinationFileName), Errors_getText(error) ); String_delete(destinationFileName); Archive_closeEntry(&archiveFileInfo); String_delete(fileName); if (jobOptions->stopOnErrorFlag) { restoreInfo.error = error; } continue; } error = File_seek(&fileHandle,fragmentOffset); if (error != ERROR_NONE) { printInfo(2,"FAIL!\n"); printError("Cannot write file '%s' (error: %s)\n", String_cString(destinationFileName), Errors_getText(error) ); File_close(&fileHandle); String_delete(destinationFileName); Archive_closeEntry(&archiveFileInfo); String_delete(fileName); if (jobOptions->stopOnErrorFlag) { restoreInfo.error = error; } continue; } length = 0; while ( ((restoreInfo.requestedAbortFlag == NULL) || !(*restoreInfo.requestedAbortFlag)) && (length < fragmentSize) ) { /* pause */ while ((restoreInfo.pauseFlag != NULL) && (*restoreInfo.pauseFlag)) { Misc_udelay(500*1000); } n = MIN(fragmentSize-length,BUFFER_SIZE); error = Archive_readFileData(&archiveFileInfo,buffer,n); if (error != ERROR_NONE) { printInfo(2,"FAIL!\n"); printError("Cannot not read content of archive '%s' (error: %s)!\n", String_cString(archiveFileName), Errors_getText(error) ); if (restoreInfo.error == ERROR_NONE) restoreInfo.error = error; break; } error = File_write(&fileHandle,buffer,n); if (error != ERROR_NONE) { printInfo(2,"FAIL!\n"); printError("Cannot write file '%s' (error: %s)\n", String_cString(destinationFileName), Errors_getText(error) ); if (jobOptions->stopOnErrorFlag) { restoreInfo.error = error; } break; } restoreInfo.statusInfo.fileDoneBytes += n; updateStatusInfo(&restoreInfo); length += n; } if (File_getSize(&fileHandle) > fileInfo.size) { File_truncate(&fileHandle,fileInfo.size); } File_close(&fileHandle); if ((restoreInfo.requestedAbortFlag != NULL) && (*restoreInfo.requestedAbortFlag)) { printInfo(2,"ABORTED\n"); String_delete(destinationFileName); Archive_closeEntry(&archiveFileInfo); String_delete(fileName); continue; } #if 0 if (restoreInfo.error != ERROR_NONE) { String_delete(destinationFileName); Archive_closeEntry(&archiveFileInfo); String_delete(fileName); continue; } #endif /* 0 */ /* set file time, file owner/group */ if (jobOptions->owner.userId != FILE_DEFAULT_USER_ID ) fileInfo.userId = jobOptions->owner.userId; if (jobOptions->owner.groupId != FILE_DEFAULT_GROUP_ID) fileInfo.groupId = jobOptions->owner.groupId; error = File_setFileInfo(destinationFileName,&fileInfo); if (error != ERROR_NONE) { if (jobOptions->stopOnErrorFlag) { printInfo(2,"FAIL!\n"); printError("Cannot set file info of '%s' (error: %s)\n", String_cString(destinationFileName), Errors_getText(error) ); String_delete(destinationFileName); Archive_closeEntry(&archiveFileInfo); String_delete(fileName); restoreInfo.error = error; continue; } else { printWarning("Cannot set file info of '%s' (error: %s)\n", String_cString(destinationFileName), Errors_getText(error) ); } } /* add fragment to file fragment list */ FileFragmentList_add(fileFragmentNode,fragmentOffset,fragmentSize); //FileFragmentList_print(fileFragmentNode,String_cString(fileName)); /* discard fragment list if file is complete */ if (FileFragmentList_checkComplete(fileFragmentNode)) { FileFragmentList_removeFile(&fileFragmentList,fileFragmentNode); } /* free resources */ String_delete(destinationFileName); printInfo(2,"ok\n"); } else { /* skip */ printInfo(3," Restore '%s'...skipped\n",String_cString(fileName)); } /* close archive file, free resources */ Archive_closeEntry(&archiveFileInfo); String_delete(fileName); } break; case FILE_TYPE_DIRECTORY: { String directoryName; FileInfo fileInfo; String destinationFileName; // FileInfo localFileInfo; /* read directory */ directoryName = String_new(); error = Archive_readDirectoryEntry(&archiveInfo, &archiveFileInfo, NULL, NULL, directoryName, &fileInfo ); if (error != ERROR_NONE) { printError("Cannot not read 'directory' content of archive '%s' (error: %s)!\n", String_cString(archiveFileName), Errors_getText(error) ); String_delete(directoryName); if (restoreInfo.error == ERROR_NONE) restoreInfo.error = error; break; } if ( (List_empty(includePatternList) || PatternList_match(includePatternList,directoryName,PATTERN_MATCH_MODE_EXACT)) && !PatternList_match(excludePatternList,directoryName,PATTERN_MATCH_MODE_EXACT) ) { String_set(restoreInfo.statusInfo.fileName,directoryName); restoreInfo.statusInfo.fileDoneBytes = 0LL; restoreInfo.statusInfo.fileTotalBytes = 00L; updateStatusInfo(&restoreInfo); /* get destination filename */ destinationFileName = getDestinationFileName(String_new(), directoryName, jobOptions->directory, jobOptions->directoryStripCount ); /* check if directory already exists */ if (!jobOptions->overwriteFilesFlag && File_exists(destinationFileName)) { printInfo(1, " Restore directory '%s'...skipped (file exists)\n", String_cString(destinationFileName) ); String_delete(destinationFileName); Archive_closeEntry(&archiveFileInfo); String_delete(directoryName); continue; } printInfo(2," Restore directory '%s'...",String_cString(destinationFileName)); /* create directory */ error = File_makeDirectory(destinationFileName, FILE_DEFAULT_USER_ID, FILE_DEFAULT_GROUP_ID, fileInfo.permission ); if (error != ERROR_NONE) { printInfo(2,"FAIL!\n"); printError("Cannot create directory '%s' (error: %s)\n", String_cString(destinationFileName), Errors_getText(error) ); String_delete(destinationFileName); Archive_closeEntry(&archiveFileInfo); String_delete(directoryName); if (jobOptions->stopOnErrorFlag) { restoreInfo.error = error; } continue; } /* set file time, file owner/group */ if (jobOptions->owner.userId != FILE_DEFAULT_USER_ID ) fileInfo.userId = jobOptions->owner.userId; if (jobOptions->owner.groupId != FILE_DEFAULT_GROUP_ID) fileInfo.groupId = jobOptions->owner.groupId; error = File_setFileInfo(destinationFileName,&fileInfo); if (error != ERROR_NONE) { if (jobOptions->stopOnErrorFlag) { printInfo(2,"FAIL!\n"); printError("Cannot set directory info of '%s' (error: %s)\n", String_cString(destinationFileName), Errors_getText(error) ); String_delete(destinationFileName); Archive_closeEntry(&archiveFileInfo); String_delete(directoryName); if (jobOptions->stopOnErrorFlag) { restoreInfo.error = error; } continue; } else { printWarning("Cannot set directory info of '%s' (error: %s)\n", String_cString(destinationFileName), Errors_getText(error) ); } } /* free resources */ String_delete(destinationFileName); printInfo(2,"ok\n"); } else { /* skip */ printInfo(3," Restore '%s'...skipped\n",String_cString(directoryName)); } /* close archive file */ Archive_closeEntry(&archiveFileInfo); String_delete(directoryName); } break; case FILE_TYPE_LINK: { String linkName; String fileName; FileInfo fileInfo; String destinationFileName; // FileInfo localFileInfo; /* read link */ linkName = String_new(); fileName = String_new(); error = Archive_readLinkEntry(&archiveInfo, &archiveFileInfo, NULL, NULL, linkName, fileName, &fileInfo ); if (error != ERROR_NONE) { printError("Cannot not read 'link' content of archive '%s' (error: %s)!\n", String_cString(archiveFileName), Errors_getText(error) ); String_delete(fileName); String_delete(linkName); if (restoreInfo.error == ERROR_NONE) restoreInfo.error = error; break; } if ( (List_empty(includePatternList) || PatternList_match(includePatternList,linkName,PATTERN_MATCH_MODE_EXACT)) && !PatternList_match(excludePatternList,linkName,PATTERN_MATCH_MODE_EXACT) ) { String_set(restoreInfo.statusInfo.fileName,linkName); restoreInfo.statusInfo.fileDoneBytes = 0LL; restoreInfo.statusInfo.fileTotalBytes = 00L; updateStatusInfo(&restoreInfo); /* get destination filename */ destinationFileName = getDestinationFileName(String_new(), linkName, jobOptions->directory, jobOptions->directoryStripCount ); /* create link */ if (!jobOptions->overwriteFilesFlag && File_exists(destinationFileName)) { printInfo(1, " Restore link '%s'...skipped (file exists)\n", String_cString(destinationFileName) ); String_delete(destinationFileName); Archive_closeEntry(&archiveFileInfo); String_delete(fileName); String_delete(linkName); if (jobOptions->stopOnErrorFlag) { restoreInfo.error = ERROR_FILE_EXITS; } continue; } printInfo(2," Restore link '%s'...",String_cString(destinationFileName)); error = File_makeLink(destinationFileName,fileName); if (error != ERROR_NONE) { printInfo(2,"FAIL!\n"); printError("Cannot create link '%s' -> '%s' (error: %s)\n", String_cString(destinationFileName), String_cString(fileName), Errors_getText(error) ); String_delete(destinationFileName); Archive_closeEntry(&archiveFileInfo); String_delete(fileName); String_delete(linkName); if (jobOptions->stopOnErrorFlag) { restoreInfo.error = error; } continue; } /* set file time, file owner/group */ if (jobOptions->owner.userId != FILE_DEFAULT_USER_ID ) fileInfo.userId = jobOptions->owner.userId; if (jobOptions->owner.groupId != FILE_DEFAULT_GROUP_ID) fileInfo.groupId = jobOptions->owner.groupId; error = File_setFileInfo(destinationFileName,&fileInfo); if (error != ERROR_NONE) { if (jobOptions->stopOnErrorFlag) { printInfo(2,"FAIL!\n"); printError("Cannot set file info of '%s' (error: %s)\n", String_cString(destinationFileName), Errors_getText(error) ); String_delete(destinationFileName); Archive_closeEntry(&archiveFileInfo); String_delete(fileName); String_delete(linkName); if (jobOptions->stopOnErrorFlag) { restoreInfo.error = error; } continue; } else { printWarning("Cannot set file info of '%s' (error: %s)\n", String_cString(destinationFileName), Errors_getText(error) ); } } /* free resources */ String_delete(destinationFileName); printInfo(2,"ok\n"); } else { /* skip */ printInfo(3," Restore '%s'...skipped\n",String_cString(linkName)); } /* close archive file */ Archive_closeEntry(&archiveFileInfo); String_delete(fileName); String_delete(linkName); } break; case FILE_TYPE_SPECIAL: { String fileName; FileInfo fileInfo; String destinationFileName; // FileInfo localFileInfo; /* read special device */ fileName = String_new(); error = Archive_readSpecialEntry(&archiveInfo, &archiveFileInfo, NULL, NULL, fileName, &fileInfo ); if (error != ERROR_NONE) { printError("Cannot not read 'special' content of archive '%s' (error: %s)!\n", String_cString(archiveFileName), Errors_getText(error) ); String_delete(fileName); if (restoreInfo.error == ERROR_NONE) restoreInfo.error = error; break; } if ( (List_empty(includePatternList) || PatternList_match(includePatternList,fileName,PATTERN_MATCH_MODE_EXACT)) && !PatternList_match(excludePatternList,fileName,PATTERN_MATCH_MODE_EXACT) ) { String_set(restoreInfo.statusInfo.fileName,fileName); restoreInfo.statusInfo.fileDoneBytes = 0LL; restoreInfo.statusInfo.fileTotalBytes = 00L; updateStatusInfo(&restoreInfo); /* get destination filename */ destinationFileName = getDestinationFileName(String_new(), fileName, jobOptions->directory, jobOptions->directoryStripCount ); /* create special device */ if (!jobOptions->overwriteFilesFlag && File_exists(destinationFileName)) { printInfo(1, " Restore special device '%s'...skipped (file exists)\n", String_cString(destinationFileName) ); String_delete(destinationFileName); Archive_closeEntry(&archiveFileInfo); String_delete(fileName); if (jobOptions->stopOnErrorFlag) { restoreInfo.error = ERROR_FILE_EXITS; } continue; } printInfo(2," Restore special device '%s'...",String_cString(destinationFileName)); error = File_makeSpecial(destinationFileName, fileInfo.specialType, fileInfo.major, fileInfo.minor ); if (error != ERROR_NONE) { printInfo(2,"FAIL!\n"); printError("Cannot create special device '%s' (error: %s)\n", String_cString(fileName), Errors_getText(error) ); String_delete(destinationFileName); Archive_closeEntry(&archiveFileInfo); String_delete(fileName); if (jobOptions->stopOnErrorFlag) { restoreInfo.error = error; } continue; } /* set file time, file owner/group */ if (jobOptions->owner.userId != FILE_DEFAULT_USER_ID ) fileInfo.userId = jobOptions->owner.userId; if (jobOptions->owner.groupId != FILE_DEFAULT_GROUP_ID) fileInfo.groupId = jobOptions->owner.groupId; error = File_setFileInfo(destinationFileName,&fileInfo); if (error != ERROR_NONE) { if (jobOptions->stopOnErrorFlag) { printInfo(2,"FAIL!\n"); printError("Cannot set file info of '%s' (error: %s)\n", String_cString(destinationFileName), Errors_getText(error) ); String_delete(destinationFileName); Archive_closeEntry(&archiveFileInfo); String_delete(fileName); if (jobOptions->stopOnErrorFlag) { restoreInfo.error = error; } continue; } else { printWarning("Cannot set file info of '%s' (error: %s)\n", String_cString(destinationFileName), Errors_getText(error) ); } } /* free resources */ String_delete(destinationFileName); printInfo(2,"ok\n"); } else { /* skip */ printInfo(3," Restore '%s'...skipped\n",String_cString(fileName)); } /* close archive file */ Archive_closeEntry(&archiveFileInfo); String_delete(fileName); } break; default: #ifndef NDEBUG HALT_INTERNAL_ERROR_UNHANDLED_SWITCH_CASE(); #endif /* NDEBUG */ break; /* not reached */ } } /* close archive */ Archive_close(&archiveInfo); } /* check fragment lists */ if ((restoreInfo.requestedAbortFlag == NULL) || !(*restoreInfo.requestedAbortFlag)) { for (fileFragmentNode = fileFragmentList.head; fileFragmentNode != NULL; fileFragmentNode = fileFragmentNode->next) { if (!FileFragmentList_checkComplete(fileFragmentNode)) { printInfo(0,"Warning: incomplete file '%s'\n",String_cString(fileFragmentNode->fileName)); if (restoreInfo.error == ERROR_NONE) restoreInfo.error = ERROR_FILE_INCOMPLETE; } } } /* free resources */ String_delete(archiveFileName); FileFragmentList_done(&fileFragmentList); free(buffer); String_delete(restoreInfo.statusInfo.fileName); String_delete(restoreInfo.statusInfo.storageName); if ((restoreInfo.requestedAbortFlag == NULL) || !(*restoreInfo.requestedAbortFlag)) { return restoreInfo.error; } else { return ERROR_ABORTED; } }