diff options
Diffstat (limited to 'lib/bkisofs/bkAdd.c')
-rw-r--r-- | lib/bkisofs/bkAdd.c | 451 |
1 files changed, 451 insertions, 0 deletions
diff --git a/lib/bkisofs/bkAdd.c b/lib/bkisofs/bkAdd.c new file mode 100644 index 0000000..06b13d0 --- /dev/null +++ b/lib/bkisofs/bkAdd.c @@ -0,0 +1,451 @@ +/******************************* LICENCE ************************************** +* Any code in this file may be redistributed or modified under the terms of +* the GNU General Public Licence as published by the Free Software +* Foundation; version 2 of the licence. +****************************** END LICENCE ***********************************/ + +/****************************************************************************** +* Author: +* Andrew Smith, http://littlesvr.ca/misc/contactandrew.php +* +* Contributors: +* +******************************************************************************/ + +#include <dirent.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <stdlib.h> +#include <string.h> +#include <stdio.h> + +#include "bk.h" +#include "bkPath.h" +#include "bkAdd.h" +#include "bkError.h" +#include "bkGet.h" +#include "bkMangle.h" +#include "bkLink.h" +#include "bkMisc.h" +#include "bkSet.h" +#include "bkIoWrappers.h" + +int add(VolInfo* volInfo, const char* srcPathAndName, BkDir* destDir, + const char* nameToUse) +{ + int rc; + char lastName[NCHARS_FILE_ID_MAX_STORE]; + BkFileBase* oldHead; /* of the children list */ + BkStatStruct statStruct; + + if(volInfo->stopOperation) + return BKERROR_OPER_CANCELED_BY_USER; + + maybeUpdateProgress(volInfo); + + if(nameToUse == NULL) + { + rc = getLastNameFromPath(srcPathAndName, lastName); + if(rc <= 0) + return rc; + } + else + { + if(strlen(nameToUse) > NCHARS_FILE_ID_MAX_STORE - 1) + return BKERROR_MAX_NAME_LENGTH_EXCEEDED; + strcpy(lastName, nameToUse); + } + + if(strcmp(lastName, ".") == 0 || strcmp(lastName, "..") == 0) + return BKERROR_NAME_INVALID; + + if( !nameIsValid(lastName) ) + return BKERROR_NAME_INVALID_CHAR; + + oldHead = destDir->children; + + /* windows doesn't have symbolic links */ + if(volInfo->followSymLinks) + rc = bkStat(srcPathAndName, &statStruct); + else + rc = lstat(srcPathAndName, &statStruct); + if(rc == -1) + return BKERROR_STAT_FAILED; + + if( IS_DIR(statStruct.st_mode) ) + { + BkDir* newDir; + + newDir = malloc(sizeof(BkDir)); + if(newDir == NULL) + return BKERROR_OUT_OF_MEMORY; + + memset(newDir, 0, sizeof(BkDir)); + + strcpy(BK_BASE_PTR(newDir)->name, lastName); + + BK_BASE_PTR(newDir)->posixFileMode = statStruct.st_mode; + + BK_BASE_PTR(newDir)->next = oldHead; + + newDir->children = NULL; + + /* ADD dir contents */ + rc = addDirContents(volInfo, srcPathAndName, newDir); + if(rc < 0) + { + free(newDir); + return rc; + } + /* END ADD dir contents */ + + destDir->children = BK_BASE_PTR(newDir); + } + else if( IS_REG_FILE(statStruct.st_mode) ) + { + BkFile* newFile; + + if(statStruct.st_size > 0xFFFFFFFF) + /* size won't fit in a 32bit variable on the iso */ + return BKERROR_ADD_FILE_TOO_BIG; + + newFile = malloc(sizeof(BkFile)); + if(newFile == NULL) + return BKERROR_OUT_OF_MEMORY; + + memset(newFile, 0, sizeof(BkFile)); + + strcpy(BK_BASE_PTR(newFile)->name, lastName); + + BK_BASE_PTR(newFile)->posixFileMode = statStruct.st_mode; + + BK_BASE_PTR(newFile)->next = oldHead; + + newFile->size = statStruct.st_size; + + newFile->onImage = false; + + newFile->position = 0; + + newFile->pathAndName = malloc(strlen(srcPathAndName) + 1); + strcpy(newFile->pathAndName, srcPathAndName); + + if( volInfo->scanForDuplicateFiles) + { + BkHardLink* newLink; + + rc = findInHardLinkTable(volInfo, 0, newFile->pathAndName, + statStruct.st_size, false, &newLink); + if(rc < 0) + { + free(newFile); + return rc; + } + + if(newLink == NULL) + /* not found */ + { + rc = addToHardLinkTable(volInfo, 0, newFile->pathAndName, + statStruct.st_size, false, &newLink); + if(rc < 0) + { + free(newFile); + return rc; + } + } + + newFile->location = newLink; + } + + destDir->children = BK_BASE_PTR(newFile); + } + else if( IS_SYMLINK(statStruct.st_mode) ) + { + BkSymLink* newSymLink; + ssize_t numChars; + + newSymLink = malloc(sizeof(BkSymLink)); + if(newSymLink == NULL) + return BKERROR_OUT_OF_MEMORY; + + memset(newSymLink, 0, sizeof(BkSymLink)); + + strcpy(BK_BASE_PTR(newSymLink)->name, lastName); + + BK_BASE_PTR(newSymLink)->posixFileMode = statStruct.st_mode; + + BK_BASE_PTR(newSymLink)->next = oldHead; + + numChars = readlink(srcPathAndName, newSymLink->target, + NCHARS_SYMLINK_TARGET_MAX - 1); + if(numChars == -1) + { + free(newSymLink); + return BKERROR_OPEN_READ_FAILED; + } + newSymLink->target[numChars] = '\0'; + + destDir->children = BK_BASE_PTR(newSymLink); + } + else + return BKERROR_NO_SPECIAL_FILES; + + return 1; +} + +int addDirContents(VolInfo* volInfo, const char* srcPath, BkDir* destDir) +{ + int rc; + int srcPathLen; + char* newSrcPathAndName; + + /* vars to read contents of a dir on fs */ + DIR* srcDir; + struct dirent* dirEnt; + + srcPathLen = strlen(srcPath); + + /* including the new name and the possibly needed trailing '/' */ + newSrcPathAndName = malloc(srcPathLen + NCHARS_FILE_ID_MAX_STORE + 2); + if(newSrcPathAndName == NULL) + return BKERROR_OUT_OF_MEMORY; + + strcpy(newSrcPathAndName, srcPath); + + if(srcPath[srcPathLen - 1] != '/') + { + strcat(newSrcPathAndName, "/"); + srcPathLen++; + } + + srcDir = opendir(srcPath); + if(srcDir == NULL) + { + free(newSrcPathAndName); + return BKERROR_OPENDIR_FAILED; + } + + /* it may be possible but in any case very unlikely that readdir() will fail + * if it does, it returns NULL (same as end of dir) */ + while( (dirEnt = readdir(srcDir)) != NULL ) + { + if( strcmp(dirEnt->d_name, ".") == 0 || strcmp(dirEnt->d_name, "..") == 0 ) + /* ignore "." and ".." */ + continue; + + if(strlen(dirEnt->d_name) > NCHARS_FILE_ID_MAX_STORE - 1) + { + closedir(srcDir); + free(newSrcPathAndName); + + return BKERROR_MAX_NAME_LENGTH_EXCEEDED; + } + + /* append file/dir name */ + strcpy(newSrcPathAndName + srcPathLen, dirEnt->d_name); + + rc = add(volInfo, newSrcPathAndName, destDir, NULL); + if(rc <= 0 && rc != BKWARNING_OPER_PARTLY_FAILED) + { + bool goOn; + + if(volInfo->warningCbk != NULL && !volInfo->stopOperation) + /* perhaps the user wants to ignore this failure */ + { + snprintf(volInfo->warningMessage, BK_WARNING_MAX_LEN, + "Failed to add item '%s': '%s'", + dirEnt->d_name, + bk_get_error_string(rc)); + goOn = volInfo->warningCbk(volInfo->warningMessage); + rc = BKWARNING_OPER_PARTLY_FAILED; + } + else + goOn = false; + + if(goOn) + continue; + else + { + volInfo->stopOperation = true; + closedir(srcDir); + free(newSrcPathAndName); + return rc; + } + } + } + + free(newSrcPathAndName); + + rc = closedir(srcDir); + if(rc != 0) + /* exotic error */ + return BKERROR_EXOTIC; + + return 1; +} + +int bk_add(VolInfo* volInfo, const char* srcPathAndName, + const char* destPathStr, void(*progressFunction)(VolInfo*)) +{ + return bk_add_as(volInfo, srcPathAndName, destPathStr, NULL, + progressFunction); +} + +int bk_add_as(VolInfo* volInfo, const char* srcPathAndName, + const char* destPathStr, const char* nameToUse, + void(*progressFunction)(VolInfo*)) +{ + int rc; + NewPath destPath; + char lastName[NCHARS_FILE_ID_MAX_STORE]; + + /* vars to find the dir in the tree */ + BkDir* destDirInTree; + bool dirFound; + + volInfo->progressFunction = progressFunction; + + rc = makeNewPathFromString(destPathStr, &destPath); + if(rc <= 0) + { + freePathContents(&destPath); + return rc; + } + + rc = getLastNameFromPath(srcPathAndName, lastName); + if(rc <= 0) + { + freePathContents(&destPath); + return rc; + } + + dirFound = findDirByNewPath(&destPath, &(volInfo->dirTree), &destDirInTree); + if(!dirFound) + { + freePathContents(&destPath); + return BKERROR_DIR_NOT_FOUND_ON_IMAGE; + } + + freePathContents(&destPath); + + if(itemIsInDir(lastName, destDirInTree)) + return BKERROR_DUPLICATE_ADD; + + volInfo->stopOperation = false; + + rc = add(volInfo, srcPathAndName, destDirInTree, nameToUse); + if(rc <= 0) + return rc; + + return 1; +} + +/******************************************************************************* +* bk_add_boot_record() +* Source boot file must be exactly the right size if floppy emulation requested. +* */ +int bk_add_boot_record(VolInfo* volInfo, const char* srcPathAndName, + int bootMediaType) +{ + BkStatStruct statStruct; + int rc; + + if(bootMediaType != BOOT_MEDIA_NO_EMULATION && + bootMediaType != BOOT_MEDIA_1_2_FLOPPY && + bootMediaType != BOOT_MEDIA_1_44_FLOPPY && + bootMediaType != BOOT_MEDIA_2_88_FLOPPY) + { + return BKERROR_ADD_UNKNOWN_BOOT_MEDIA; + } + + rc = bkStat(srcPathAndName, &statStruct); + if(rc == -1) + return BKERROR_STAT_FAILED; + + if(statStruct.st_size > 0xFFFFFFFF) + /* size won't fit in a 32bit variable on the iso */ + return BKERROR_ADD_FILE_TOO_BIG; + + if( (bootMediaType == BOOT_MEDIA_1_2_FLOPPY && + statStruct.st_size != 1228800) || + (bootMediaType == BOOT_MEDIA_1_44_FLOPPY && + statStruct.st_size != 1474560) || + (bootMediaType == BOOT_MEDIA_2_88_FLOPPY && + statStruct.st_size != 2949120) ) + { + return BKERROR_ADD_BOOT_RECORD_WRONG_SIZE; + } + + volInfo->bootMediaType = bootMediaType; + + volInfo->bootRecordSize = statStruct.st_size; + + volInfo->bootRecordIsOnImage = false; + + /* make copy of the source path and name */ + if(volInfo->bootRecordPathAndName != NULL) + free(volInfo->bootRecordPathAndName); + volInfo->bootRecordPathAndName = malloc(strlen(srcPathAndName) + 1); + if(volInfo->bootRecordPathAndName == NULL) + { + volInfo->bootMediaType = BOOT_MEDIA_NONE; + return BKERROR_OUT_OF_MEMORY; + } + strcpy(volInfo->bootRecordPathAndName, srcPathAndName); + + /* this is the wrong function to use if you want a visible one */ + volInfo->bootRecordIsVisible = false; + + return 1; +} + +/******************************************************************************* +* bk_create_dir() +* +* */ +int bk_create_dir(VolInfo* volInfo, const char* destPathStr, + const char* newDirName) +{ + size_t nameLen; + BkDir* destDir; + int rc; + BkFileBase* oldHead; + BkDir* newDir; + + nameLen = strlen(newDirName); + if(nameLen > NCHARS_FILE_ID_MAX_STORE - 1) + return BKERROR_MAX_NAME_LENGTH_EXCEEDED; + if(nameLen == 0) + return BKERROR_BLANK_NAME; + + if(strcmp(newDirName, ".") == 0 || strcmp(newDirName, "..") == 0) + return BKERROR_NAME_INVALID; + + if( !nameIsValid(newDirName) ) + return BKERROR_NAME_INVALID_CHAR; + + rc = getDirFromString(&(volInfo->dirTree), destPathStr, &destDir); + if(rc <= 0) + return rc; + + if(itemIsInDir(newDirName, destDir)) + return BKERROR_DUPLICATE_CREATE_DIR; + + oldHead = destDir->children; + + newDir = malloc(sizeof(BkDir)); + if(newDir == NULL) + return BKERROR_OUT_OF_MEMORY; + + strcpy(BK_BASE_PTR(newDir)->name, newDirName); + + BK_BASE_PTR(newDir)->posixFileMode = volInfo->posixDirDefaults; + + BK_BASE_PTR(newDir)->next = oldHead; + + newDir->children = NULL; + + destDir->children = BK_BASE_PTR(newDir); + + return 1; +} |