summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEudyptula <eitan@mosenkis.net>2009-07-21 16:02:48 -0400
committerEudyptula <eitan@mosenkis.net>2009-07-21 16:02:48 -0400
commit34b01fa4d3614698ac2b1af74a7f56b986fd97c4 (patch)
treec85a7c34256db034a676c683875a405a361bca9b /lib/bkisofs/bkWrite.c
parentFixes/hacks so backend still works with non-execution logging (diff)
downloadingenue-34b01fa4d3614698ac2b1af74a7f56b986fd97c4.tar.gz
ingenue-34b01fa4d3614698ac2b1af74a7f56b986fd97c4.tar.bz2
ingenue-34b01fa4d3614698ac2b1af74a7f56b986fd97c4.zip
Added bkisofs ISO manipulation library and wrote CLI wrapper for it
Diffstat (limited to 'lib/bkisofs/bkWrite.c')
-rw-r--r--lib/bkisofs/bkWrite.c2547
1 files changed, 2547 insertions, 0 deletions
diff --git a/lib/bkisofs/bkWrite.c b/lib/bkisofs/bkWrite.c
new file mode 100644
index 0000000..031cb30
--- /dev/null
+++ b/lib/bkisofs/bkWrite.c
@@ -0,0 +1,2547 @@
+/******************************* 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:
+*
+******************************************************************************/
+
+/******************************************************************************
+* Functions in this file write to volInfo.imageForWriting and are probably
+* unsutable for anything else.
+******************************************************************************/
+
+#include <strings.h>
+#include <string.h>
+#include <time.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+
+#include "bk.h"
+#include "bkInternal.h"
+#include "bkWrite7x.h"
+#include "bkTime.h"
+#include "bkWrite.h"
+#include "bkMangle.h"
+#include "bkError.h"
+#include "bkSort.h"
+#include "bkPath.h"
+#include "bkCache.h"
+#include "bkRead7x.h"
+#include "bkLink.h"
+#include "bkIoWrappers.h"
+
+/******************************************************************************
+* bk_write_image()
+* Writes everything from first to last byte of the iso.
+* Public function.
+* */
+int bk_write_image(const char* newImagePathAndName, VolInfo* volInfo,
+ time_t creationTime, int filenameTypes,
+ void(*progressFunction)(VolInfo*, double))
+{
+ int rc;
+ DirToWrite newTree;
+ bk_off_t svdOffset;
+ bk_off_t pRealRootDrOffset;
+ int pRootDirSize;
+ bk_off_t sRealRootDrOffset;
+ int sRootDirSize;
+ bk_off_t lPathTable9660Loc;
+ bk_off_t mPathTable9660Loc;
+ int pathTable9660Size;
+ bk_off_t lPathTableJolietLoc;
+ bk_off_t mPathTableJolietLoc;
+ int pathTableJolietSize;
+ bk_off_t bootCatalogSectorNumberOffset;
+ bk_off_t currPos;
+
+ volInfo->writeProgressFunction = progressFunction;
+ volInfo->stopOperation = false;
+
+ volInfo->estimatedIsoSize = bk_estimate_iso_size(volInfo, filenameTypes);
+ progressFunction(volInfo, 0);
+
+ BkStatStruct statStruct;
+ rc = bkStat(newImagePathAndName, &statStruct);
+ if(rc == 0 && statStruct.st_ino == volInfo->imageForReadingInode)
+ return BKERROR_SAVE_OVERWRITE;
+
+ /* because mangleDir works on dir's children i need to
+ * copy the root manually */
+ memset(&newTree, 0, sizeof(DirToWrite));
+ newTree.base.posixFileMode = volInfo->dirTree.base.posixFileMode;
+
+ printf("mangling\n");fflush(NULL);
+ /* create tree to write */
+ rc = mangleDir(&(volInfo->dirTree), &newTree, filenameTypes);
+ if(rc <= 0)
+ {
+ freeDirToWriteContents(&newTree);
+ return rc;
+ }
+
+ printf("opening '%s' for writing\n", newImagePathAndName);fflush(NULL);
+ volInfo->imageForWriting = open(newImagePathAndName,
+ O_RDWR | O_CREAT | O_TRUNC,
+ S_IRUSR | S_IWUSR);
+ if(volInfo->imageForWriting == -1)
+ {
+ freeDirToWriteContents(&newTree);
+ return BKERROR_OPEN_WRITE_FAILED;
+ }
+
+ printf("writing blank at %X\n", (int)wcSeekTell(volInfo));fflush(NULL);
+ /* system area, always zeroes */
+ rc = writeByteBlock(volInfo, 0, NBYTES_LOGICAL_BLOCK * NLS_SYSTEM_AREA);
+ if(rc <= 0)
+ {
+ freeDirToWriteContents(&newTree);
+ bkClose(volInfo->imageForWriting);
+ unlink(newImagePathAndName);
+ return rc;
+ }
+
+ /* skip pvd (1 block), write it after files */
+ wcSeekForward(volInfo, NBYTES_LOGICAL_BLOCK);
+
+ if(volInfo->bootMediaType != BOOT_MEDIA_NONE)
+ {
+ /* el torito volume descriptor */
+ rc = writeElToritoVd(volInfo, &bootCatalogSectorNumberOffset);
+ if(rc <= 0)
+ {
+ freeDirToWriteContents(&newTree);
+ bkClose(volInfo->imageForWriting);
+ unlink(newImagePathAndName);
+ return rc;
+ }
+ }
+
+ if(filenameTypes & FNTYPE_JOLIET)
+ /* skip svd (1 block), write it after pvd */
+ {
+ svdOffset = wcSeekTell(volInfo);
+ wcSeekForward(volInfo, NBYTES_LOGICAL_BLOCK);
+ }
+
+ printf("writing terminator at %X\n", (int)wcSeekTell(volInfo));fflush(NULL);
+ /* volume descriptor set terminator */
+ rc = writeVdsetTerminator(volInfo);
+ if(rc <= 0)
+ {
+ freeDirToWriteContents(&newTree);
+ bkClose(volInfo->imageForWriting);
+ unlink(newImagePathAndName);
+ return rc;
+ }
+
+ if(volInfo->bootMediaType != BOOT_MEDIA_NONE)
+ {
+ /* write boot catalog sector number */
+ currPos = wcSeekTell(volInfo);
+ wcSeekSet(volInfo, bootCatalogSectorNumberOffset);
+ rc = write731(volInfo, currPos / NBYTES_LOGICAL_BLOCK);
+ if(rc <= 0)
+ {
+ freeDirToWriteContents(&newTree);
+ bkClose(volInfo->imageForWriting);
+ unlink(newImagePathAndName);
+ return rc;
+ }
+ wcSeekSet(volInfo, currPos);
+
+ /* write el torito booting catalog */
+ rc = writeElToritoBootCatalog(volInfo, &(volInfo->bootRecordSectorNumberOffset));
+ if(rc <= 0)
+ {
+ freeDirToWriteContents(&newTree);
+ bkClose(volInfo->imageForWriting);
+ unlink(newImagePathAndName);
+ return rc;
+ }
+ }
+
+ /* MAYBE write boot record file now */
+ if(volInfo->bootMediaType != BOOT_MEDIA_NONE &&
+ !volInfo->bootRecordIsVisible)
+ {
+ int blankSize;
+ int srcFile; /* either the old image or the boot record file on
+ * the regular filesystem */
+ bool srcFileOpened;
+
+ /* set up source file pointer */
+ if(volInfo->bootRecordIsOnImage)
+ {
+ srcFile = volInfo->imageForReading;
+ bkSeekSet(volInfo->imageForReading, volInfo->bootRecordOffset, SEEK_SET);
+ srcFileOpened = false;
+ }
+ else
+ {
+ srcFile = open(volInfo->bootRecordPathAndName, O_RDONLY, 0);
+ if(srcFile == -1)
+ {
+ freeDirToWriteContents(&newTree);
+ bkClose(volInfo->imageForWriting);
+ unlink(newImagePathAndName);
+ return BKERROR_OPEN_READ_FAILED;
+ }
+ srcFileOpened = true;
+ }
+
+ /* write boot record sector number */
+ currPos = wcSeekTell(volInfo);
+ wcSeekSet(volInfo, volInfo->bootRecordSectorNumberOffset);
+
+ rc = write731(volInfo, currPos / NBYTES_LOGICAL_BLOCK);
+ if(rc <= 0)
+ {
+ freeDirToWriteContents(&newTree);
+ if(srcFileOpened)
+ bkClose(srcFile);
+ bkClose(volInfo->imageForWriting);
+ unlink(newImagePathAndName);
+ return rc;
+ }
+ wcSeekSet(volInfo, currPos);
+
+ /* file contents */
+ rc = writeByteBlockFromFile(srcFile, volInfo, volInfo->bootRecordSize);
+ if(rc < 0)
+ {
+ freeDirToWriteContents(&newTree);
+ if(srcFileOpened)
+ bkClose(srcFile);
+ bkClose(volInfo->imageForWriting);
+ unlink(newImagePathAndName);
+ return rc;
+ }
+
+ blankSize = NBYTES_LOGICAL_BLOCK -
+ volInfo->bootRecordSize % NBYTES_LOGICAL_BLOCK;
+
+ /* fill the last sector with 0s */
+ rc = writeByteBlock(volInfo, 0x00, blankSize);
+ if(rc < 0)
+ {
+ freeDirToWriteContents(&newTree);
+ if(srcFileOpened)
+ bkClose(srcFile);
+ bkClose(volInfo->imageForWriting);
+ unlink(newImagePathAndName);
+ return rc;
+ }
+
+ if(srcFileOpened)
+ bkClose(srcFile);
+ }
+ /* END MAYBE write boot record file now */
+
+ printf("sorting 9660\n");
+ sortDir(&newTree, FNTYPE_9660);
+
+ pRealRootDrOffset = wcSeekTell(volInfo);
+
+ printf("writing primary directory tree at %X\n", (int)wcSeekTell(volInfo));fflush(NULL);
+ /* 9660 and maybe rockridge dir tree */
+ rc = writeDir(volInfo, &newTree, 0, 0, 0, creationTime,
+ filenameTypes & (FNTYPE_9660 | FNTYPE_ROCKRIDGE), true);
+ if(rc <= 0)
+ {
+ freeDirToWriteContents(&newTree);
+ bkClose(volInfo->imageForWriting);
+ unlink(newImagePathAndName);
+ return rc;
+ }
+
+ pRootDirSize = rc;
+
+ /* joliet dir tree */
+ if(filenameTypes & FNTYPE_JOLIET)
+ {
+ printf("sorting joliet\n");
+ sortDir(&newTree, FNTYPE_JOLIET);
+
+ printf("writing supplementary directory tree at %X\n", (int)wcSeekTell(volInfo));fflush(NULL);
+ sRealRootDrOffset = wcSeekTell(volInfo);
+
+ rc = writeDir(volInfo, &newTree, 0, 0, 0, creationTime,
+ FNTYPE_JOLIET, true);
+ if(rc <= 0)
+ {
+ freeDirToWriteContents(&newTree);
+ bkClose(volInfo->imageForWriting);
+ unlink(newImagePathAndName);
+ return rc;
+ }
+
+ sRootDirSize = rc;
+ }
+
+ printf("writing 9660 path tables at %X\n", (int)wcSeekTell(volInfo));fflush(NULL);
+
+ lPathTable9660Loc = wcSeekTell(volInfo);
+ rc = writePathTable(volInfo, &newTree, true, FNTYPE_9660);
+ if(rc <= 0)
+ {
+ freeDirToWriteContents(&newTree);
+ bkClose(volInfo->imageForWriting);
+ unlink(newImagePathAndName);
+ return rc;
+ }
+ pathTable9660Size = rc;
+
+ mPathTable9660Loc = wcSeekTell(volInfo);
+ rc = writePathTable(volInfo, &newTree, false, FNTYPE_9660);
+ if(rc <= 0)
+ {
+ freeDirToWriteContents(&newTree);
+ bkClose(volInfo->imageForWriting);
+ unlink(newImagePathAndName);
+ return rc;
+ }
+
+ if(filenameTypes & FNTYPE_JOLIET)
+ {
+ printf("writing joliet path tables at %X\n", (int)wcSeekTell(volInfo));fflush(NULL);
+ lPathTableJolietLoc = wcSeekTell(volInfo);
+ rc = writePathTable(volInfo, &newTree, true, FNTYPE_JOLIET);
+ if(rc <= 0)
+ {
+ freeDirToWriteContents(&newTree);
+ bkClose(volInfo->imageForWriting);
+ unlink(newImagePathAndName);
+ return rc;
+ }
+ pathTableJolietSize = rc;
+
+ mPathTableJolietLoc = wcSeekTell(volInfo);
+ rc = writePathTable(volInfo, &newTree, false, FNTYPE_JOLIET);
+ if(rc <= 0)
+ {
+ freeDirToWriteContents(&newTree);
+ bkClose(volInfo->imageForWriting);
+ unlink(newImagePathAndName);
+ return rc;
+ }
+ }
+
+ printf("writing files at %X\n", (int)wcSeekTell(volInfo));fflush(NULL);
+ resetWriteStatus(volInfo->fileLocations);
+ /* all files and offsets/sizes */
+ rc = writeFileContents(volInfo, &newTree, filenameTypes);
+ if(rc <= 0)
+ {
+ freeDirToWriteContents(&newTree);
+ bkClose(volInfo->imageForWriting);
+ unlink(newImagePathAndName);
+ return rc;
+ }
+
+ if(filenameTypes & FNTYPE_ROCKRIDGE)
+ {
+ printf("writing long NMs at %X\n", (int)wcSeekTell(volInfo));fflush(NULL);
+ rc = writeLongNMsInDir(volInfo, &newTree);
+ if(rc <= 0)
+ {
+ freeDirToWriteContents(&newTree);
+ bkClose(volInfo->imageForWriting);
+ unlink(newImagePathAndName);
+ return rc;
+ }
+ }
+
+ wcSeekSet(volInfo, NBYTES_LOGICAL_BLOCK * NLS_SYSTEM_AREA);
+
+ printf("writing pvd at %X\n", (int)wcSeekTell(volInfo));fflush(NULL);
+ rc = writeVolDescriptor(volInfo, pRealRootDrOffset,
+ pRootDirSize, lPathTable9660Loc, mPathTable9660Loc,
+ pathTable9660Size, creationTime, true);
+ if(rc <= 0)
+ {
+ freeDirToWriteContents(&newTree);
+ bkClose(volInfo->imageForWriting);
+ unlink(newImagePathAndName);
+ return rc;
+ }
+
+ if(filenameTypes & FNTYPE_JOLIET)
+ {
+ wcSeekSet(volInfo, svdOffset);
+
+ printf("writing svd at %X\n", (int)wcSeekTell(volInfo));fflush(NULL);
+ rc = writeVolDescriptor(volInfo, sRealRootDrOffset,
+ sRootDirSize, lPathTableJolietLoc, mPathTableJolietLoc,
+ pathTableJolietSize, creationTime, false);
+ if(rc <= 0)
+ {
+ freeDirToWriteContents(&newTree);
+ bkClose(volInfo->imageForWriting);
+ unlink(newImagePathAndName);
+ return rc;
+ }
+ }
+
+ printf("freeing memory\n");fflush(NULL);
+ freeDirToWriteContents(&newTree);
+ bkClose(volInfo->imageForWriting);
+
+ return 1;
+}
+
+/******************************************************************************
+* bootInfoTableChecksum()
+* Calculate the checksum to be written into the boot info table.
+* */
+int bootInfoTableChecksum(int oldImage, FileToWrite* file, unsigned* checksum)
+{
+ int numTrailingBytes; /* to make sure the file size is divisible by 4 */
+ ssize_t rc;
+ int srcFile;
+ unsigned char* contents;
+ unsigned count;
+
+ numTrailingBytes = file->size % 4;
+
+ contents = malloc(file->size + numTrailingBytes);
+ if(contents == NULL)
+ return BKERROR_OUT_OF_MEMORY;
+
+ /* make sure the extra bytes i added are 0s */
+ memset(contents + file->size, 0, numTrailingBytes);
+
+ if(file->onImage)
+ /* read file from original image */
+ {
+ bkSeekSet(oldImage, file->offset, SEEK_SET);
+
+ rc = bkRead(oldImage, contents, file->size);
+ if(rc == -1 || rc != (int)(file->size))
+ {
+ free(contents);
+ return BKERROR_READ_GENERIC;
+ }
+ }
+ else
+ /* read file from fs */
+ {
+ srcFile = open(file->pathAndName, O_RDONLY, 0);
+ if(srcFile == -1)
+ {
+ free(contents);
+ return BKERROR_OPEN_READ_FAILED;
+ }
+
+ rc = bkRead(srcFile, contents, file->size);
+
+ bkClose(srcFile);
+
+ if(rc == -1 || rc != (int)(file->size))
+ {
+ free(contents);
+ return BKERROR_READ_GENERIC;
+ }
+ }
+
+ *checksum = 0;
+ /* do 32 bit checksum starting from byte 64
+ * because i check above that the file is divisible by 4 i will not be
+ * reading wrong memory */
+ for(count = 64; count < file->size; count += 4)
+ {
+ unsigned toAdd;
+
+ toAdd = *(contents + count) | (*(contents + count + 1) << 8) |
+ (*(contents + count + 2) << 16) | (*(contents + count + 3) << 24);
+
+ *checksum += toAdd;
+ }
+
+ free(contents);
+
+ return 1;
+}
+
+/******************************************************************************
+* countDirsOnLevel()
+* a 'level' is described in ecma119 6.8.2
+* it's needed for path tables, don't remember exactly what for
+* */
+int countDirsOnLevel(const DirToWrite* dir, int targetLevel, int thisLevel)
+{
+ BaseToWrite* child;
+ int sum;
+
+ if(targetLevel == thisLevel)
+ {
+ return 1;
+ }
+ else
+ {
+ sum = 0;
+
+ child = dir->children;
+ while(child != NULL)
+ {
+ if( IS_DIR(child->posixFileMode) )
+ sum += countDirsOnLevel(DIRTW_PTR(child), targetLevel, thisLevel + 1);
+
+ child = child->next;
+ }
+
+ return sum;
+ }
+}
+
+/******************************************************************************
+* countTreeHeight()
+* caller should set heightSoFar to 1
+* */
+int countTreeHeight(const DirToWrite* dir, int heightSoFar)
+{
+ BaseToWrite* child;
+ int maxHeight;
+ int thisHeight;
+
+ maxHeight = heightSoFar;
+ child = dir->children;
+ while(child != NULL)
+ {
+ if( IS_DIR(child->posixFileMode) )
+ {
+ thisHeight = countTreeHeight(DIRTW_PTR(child), heightSoFar + 1);
+
+ if(thisHeight > maxHeight)
+ maxHeight = thisHeight;
+ }
+
+ child = child->next;
+ }
+
+ return maxHeight;
+}
+
+/******************************************************************************
+* elToritoChecksum()
+* Algorithm: the sum of all words, including the checksum must trunkate to
+* a 16-bit 0x0000
+* */
+unsigned short elToritoChecksum(const unsigned char* record)
+{
+ short sum;
+ int i;
+
+ sum = 0;
+ for(i = 0; i < 32; i += 2)
+ {
+ sum += *(record + i) | (*(record + i + 1) << 8);
+ }
+
+ return 0xFFFF - sum + 1;
+}
+
+/******************************************************************************
+* writeByteBlock()
+* Fills numBytes with byteToWrite.
+
+* */
+int writeByteBlock(VolInfo* volInfo, unsigned char byteToWrite, int numBytes)
+{
+ int rc;
+ int count;
+ int numBlocks;
+ int sizeLastBlock;
+
+ memset(volInfo->readWriteBuffer, byteToWrite, READ_WRITE_BUFFER_SIZE);
+
+ numBlocks = numBytes / READ_WRITE_BUFFER_SIZE;
+ sizeLastBlock = numBytes % READ_WRITE_BUFFER_SIZE;
+
+ for(count = 0; count < numBlocks; count++)
+ {
+ rc = wcWrite(volInfo, volInfo->readWriteBuffer, READ_WRITE_BUFFER_SIZE);
+ if(rc <= 0)
+ return rc;
+ }
+
+ if(sizeLastBlock > 0)
+ {
+ rc = wcWrite(volInfo, volInfo->readWriteBuffer, sizeLastBlock);
+ if(rc <= 0)
+ return rc;
+ }
+
+ return 1;
+}
+
+/******************************************************************************
+* writeByteBlockFromFile()
+* copies numBytes from src into the image to write in blocks of 10K
+* */
+int writeByteBlockFromFile(int src, VolInfo* volInfo, unsigned numBytes)
+{
+ int rc;
+ int count;
+ int numBlocks;
+ int sizeLastBlock;
+
+ numBlocks = numBytes / READ_WRITE_BUFFER_SIZE;
+ sizeLastBlock = numBytes % READ_WRITE_BUFFER_SIZE;
+
+ for(count = 0; count < numBlocks; count++)
+ {
+ if(volInfo->stopOperation)
+ return BKERROR_OPER_CANCELED_BY_USER;
+
+ rc = bkRead(src, volInfo->readWriteBuffer, READ_WRITE_BUFFER_SIZE);
+ if(rc != READ_WRITE_BUFFER_SIZE)
+ return BKERROR_READ_GENERIC;
+ rc = wcWrite(volInfo, volInfo->readWriteBuffer, READ_WRITE_BUFFER_SIZE);
+ if(rc <= 0)
+ return rc;
+ }
+
+ if(sizeLastBlock > 0)
+ {
+ rc = bkRead(src, volInfo->readWriteBuffer, sizeLastBlock);
+ if(rc != sizeLastBlock)
+ return BKERROR_READ_GENERIC;
+ rc = wcWrite(volInfo, volInfo->readWriteBuffer, sizeLastBlock);
+ if(rc <= 0)
+ return rc;
+ }
+
+ return 1;
+}
+
+/******************************************************************************
+* writeDir()
+* Writes the contents of a directory. Also writes locations and sizes of
+* directory records for directories but not for files.
+* Returns data length of the dir written.
+* */
+int writeDir(VolInfo* volInfo, DirToWrite* dir, int parentLbNum,
+ int parentNumBytes, int parentPosix, time_t recordingTime,
+ int filenameTypes, bool isRoot)
+{
+ int rc;
+
+ bk_off_t startPos;
+ int numUnusedBytes;
+ bk_off_t endPos;
+
+ DirToWrite selfDir; /* will have a different filename */
+ DirToWrite parentDir;
+
+ BaseToWrite* child;
+
+ if(wcSeekTell(volInfo) % NBYTES_LOGICAL_BLOCK != 0)
+ return BKERROR_SANITY;
+
+ /* names other then 9660 are not used for self and parent */
+ selfDir.base.name9660[0] = 0x00;
+ selfDir.base.posixFileMode = dir->base.posixFileMode;
+
+ parentDir.base.name9660[0] = 0x01;
+ parentDir.base.name9660[1] = '\0';
+ if(isRoot)
+ parentDir.base.posixFileMode = selfDir.base.posixFileMode;
+ else
+ parentDir.base.posixFileMode = parentPosix;
+
+ startPos = wcSeekTell(volInfo);
+
+ if( startPos % NBYTES_LOGICAL_BLOCK != 0 )
+ /* this should never happen */
+ return BKERROR_SANITY;
+
+ if(filenameTypes & FNTYPE_JOLIET)
+ dir->extentNumber2 = startPos / NBYTES_LOGICAL_BLOCK;
+ else
+ dir->base.extentNumber = startPos / NBYTES_LOGICAL_BLOCK;
+
+ /* write self */
+ if(isRoot)
+ {
+ rc = writeDr(volInfo, BASETW_PTR(&selfDir), recordingTime, true, true, true, filenameTypes);
+ if(rc < 0)
+ return rc;
+
+ if(filenameTypes & FNTYPE_JOLIET)
+ dir->base.extentLocationOffset2 = selfDir.base.extentLocationOffset2;
+ else
+ dir->base.extentLocationOffset = selfDir.base.extentLocationOffset;
+ }
+ else
+ {
+ rc = writeDr(volInfo, BASETW_PTR(&selfDir), recordingTime, true, true, false, filenameTypes);
+ if(rc < 0)
+ return rc;
+ }
+ if(rc < 0)
+ return rc;
+
+ /* write parent */
+ rc = writeDr(volInfo, BASETW_PTR(&parentDir), recordingTime, true, true, false, filenameTypes);
+ if(rc < 0)
+ return rc;
+
+ child = dir->children;
+
+ /* WRITE children drs */
+ while(child != NULL)
+ {
+ if(IS_DIR(child->posixFileMode))
+ {
+ rc = writeDr(volInfo, child, recordingTime,
+ true, false, false, filenameTypes);
+ }
+ else
+ {
+ rc = writeDr(volInfo, child, recordingTime,
+ false, false, false, filenameTypes);
+ }
+ if(rc < 0)
+ return rc;
+
+ child = child->next;
+ }
+ /* END WRITE children drs */
+
+ /* write blank to conclude extent */
+ numUnusedBytes = NBYTES_LOGICAL_BLOCK -
+ wcSeekTell(volInfo) % NBYTES_LOGICAL_BLOCK;
+ rc = writeByteBlock(volInfo, 0x00, numUnusedBytes);
+ if(rc < 0)
+ return rc;
+
+ if(filenameTypes & FNTYPE_JOLIET)
+ dir->dataLength2 = wcSeekTell(volInfo) - startPos;
+ else
+ dir->dataLength = wcSeekTell(volInfo) - startPos;
+
+ /* write subdirectories */
+ child = dir->children;
+ while(child != NULL)
+ {
+ if(IS_DIR(child->posixFileMode))
+ {
+ if(filenameTypes & FNTYPE_JOLIET)
+ {
+ rc = writeDir(volInfo, DIRTW_PTR(child), dir->extentNumber2,
+ dir->dataLength2, BASETW_PTR(dir)->posixFileMode, recordingTime,
+ filenameTypes, false);
+ }
+ else
+ {
+ rc = writeDir(volInfo, DIRTW_PTR(child), BASETW_PTR(dir)->extentNumber,
+ dir->dataLength, BASETW_PTR(dir)->posixFileMode, recordingTime,
+ filenameTypes, false);
+ }
+ if(rc < 0)
+ return rc;
+ }
+
+ child = child->next;
+ }
+
+ endPos = wcSeekTell(volInfo);
+
+ /* SELF extent location and size */
+ if(filenameTypes & FNTYPE_JOLIET)
+ wcSeekSet(volInfo, selfDir.base.extentLocationOffset2);
+ else
+ wcSeekSet(volInfo, selfDir.base.extentLocationOffset);
+
+ if(filenameTypes & FNTYPE_JOLIET)
+ {
+ rc = write733(volInfo, dir->extentNumber2);
+ if(rc <= 0)
+ return rc;
+
+ rc = write733(volInfo, dir->dataLength2);
+ if(rc <= 0)
+ return rc;
+ }
+ else
+ {
+ rc = write733(volInfo, BASETW_PTR(dir)->extentNumber);
+ if(rc <= 0)
+ return rc;
+
+ rc = write733(volInfo, dir->dataLength);
+ if(rc <= 0)
+ return rc;
+ }
+ /* END SELF extent location and size */
+
+ /* PARENT extent location and size */
+ if(filenameTypes & FNTYPE_JOLIET)
+ wcSeekSet(volInfo, parentDir.base.extentLocationOffset2);
+ else
+ wcSeekSet(volInfo, parentDir.base.extentLocationOffset);
+
+ if(parentLbNum == 0)
+ /* root, parent is same as self */
+ {
+ if(filenameTypes & FNTYPE_JOLIET)
+ {
+ rc = write733(volInfo, dir->extentNumber2);
+ if(rc <= 0)
+ return rc;
+
+ rc = write733(volInfo, dir->dataLength2);
+ if(rc <= 0)
+ return rc;
+ }
+ else
+ {
+ rc = write733(volInfo, BASETW_PTR(dir)->extentNumber);
+ if(rc <= 0)
+ return rc;
+
+ rc = write733(volInfo, dir->dataLength);
+ if(rc <= 0)
+ return rc;
+ }
+ }
+ else
+ /* normal parent */
+ {
+ rc = write733(volInfo, parentLbNum);
+ if(rc <= 0)
+ return rc;
+
+ rc = write733(volInfo, parentNumBytes);
+ if(rc <= 0)
+ return rc;
+ }
+ /* END PARENT extent location and size */
+
+ /* ALL subdir extent locations and sizes */
+ child = dir->children;
+ while(child != NULL)
+ {
+ if(IS_DIR(child->posixFileMode))
+ {
+ if(filenameTypes & FNTYPE_JOLIET)
+ {
+ wcSeekSet(volInfo, child->extentLocationOffset2);
+
+ rc = write733(volInfo, DIRTW_PTR(child)->extentNumber2);
+ if(rc <= 0)
+ return rc;
+
+ rc = write733(volInfo, DIRTW_PTR(child)->dataLength2);
+ if(rc <= 0)
+ return rc;
+ }
+ else
+ {
+ wcSeekSet(volInfo, child->extentLocationOffset);
+
+ rc = write733(volInfo, child->extentNumber);
+ if(rc <= 0)
+ return rc;
+
+ rc = write733(volInfo, DIRTW_PTR(child)->dataLength);
+ if(rc <= 0)
+ return rc;
+ }
+ }
+
+ child = child->next;
+ }
+ /* END ALL subdir extent locations and sizes */
+
+ wcSeekSet(volInfo, endPos);
+
+ if(filenameTypes & FNTYPE_JOLIET)
+ return dir->dataLength2;
+ else
+ return dir->dataLength;
+}
+
+/******************************************************************************
+* writeDr()
+* Writes a directory record.
+* Note that it uses only the members of DirToWrite and FileToWrite that are
+* the same.
+* */
+int writeDr(VolInfo* volInfo, BaseToWrite* node, time_t recordingTime, bool isADir,
+ bool isSelfOrParent, bool isFirstRecord, int filenameTypes)
+{
+ int rc;
+ unsigned char byte;
+ char aString[256];
+ unsigned short aShort;
+ bk_off_t startPos;
+ bk_off_t endPos;
+ unsigned char lenFileId;
+ unsigned char recordLen;
+
+ /* look at the end of the function for an explanation */
+ writeDrStartLabel:
+
+ startPos = wcSeekTell(volInfo);
+
+ /* record length is recorded in the end */
+ wcSeekForward(volInfo, 1);
+
+ /* extended attribute record length */
+ byte = 0;
+ rc = write711(volInfo, byte);
+ if(rc <= 0)
+ return rc;
+
+ if(filenameTypes & FNTYPE_JOLIET)
+ node->extentLocationOffset2 = wcSeekTell(volInfo);
+ else
+ node->extentLocationOffset = wcSeekTell(volInfo);
+
+ /* location of extent not recorded in this function */
+ wcSeekForward(volInfo, 8);
+
+ /* data length not recorded in this function */
+ wcSeekForward(volInfo, 8);
+
+ /* RECORDING time and date */
+ epochToShortString(recordingTime, aString);
+
+ rc = write711(volInfo, aString[0]);
+ if(rc <= 0)
+ return rc;
+ rc = write711(volInfo, aString[1]);
+ if(rc <= 0)
+ return rc;
+ rc = write711(volInfo, aString[2]);
+ if(rc <= 0)
+ return rc;
+ rc = write711(volInfo, aString[3]);
+ if(rc <= 0)
+ return rc;
+ rc = write711(volInfo, aString[4]);
+ if(rc <= 0)
+ return rc;
+ rc = write711(volInfo, aString[5]);
+ if(rc <= 0)
+ return rc;
+ rc = write711(volInfo, aString[6]);
+ if(rc <= 0)
+ return rc;
+ /* END RECORDING time and date */
+
+ /* FILE flags */
+ if(isADir)
+ /* (only directory bit on) */
+ byte = 0x02;
+ else
+ /* nothing on */
+ byte = 0x00;
+
+ rc = wcWrite(volInfo, (char*)&byte, 1);
+ if(rc <= 0)
+ return rc;
+ /* END FILE flags */
+
+ /* file unit size (always 0, non-interleaved mode) */
+ byte = 0;
+ rc = write711(volInfo, byte);
+ if(rc <= 0)
+ return rc;
+
+ /* interleave gap size (also always 0, non-interleaved mode) */
+ rc = write711(volInfo, byte);
+ if(rc <= 0)
+ return rc;
+
+ /* volume sequence number (always 1) */
+ aShort = 1;
+ rc = write723(volInfo, aShort);
+ if(rc <= 0)
+ return rc;
+
+ /* LENGTH of file identifier */
+ if(isSelfOrParent)
+ lenFileId = 1;
+ else
+ {
+ if(filenameTypes & FNTYPE_JOLIET)
+ lenFileId = 2 * strlen(node->nameJoliet);
+ else
+ /*if(isADir) see microsoft comment below */
+ lenFileId = strlen(node->name9660);
+ /*else
+ lenFileId = strlen(node->name9660) + 2; */
+ }
+
+ rc = write711(volInfo, lenFileId);
+ if(rc <= 0)
+ return rc;
+ /* END LENGTH of file identifier */
+
+ /* FILE identifier */
+ if(isSelfOrParent)
+ {
+ /* that byte has 0x00 or 0x01 */
+ rc = write711(volInfo, node->name9660[0]);
+ if(rc <= 0)
+ return rc;
+ }
+ else
+ {
+ if(filenameTypes & FNTYPE_JOLIET)
+ {
+ rc = writeJolietStringField(volInfo, node->nameJoliet,
+ 2 * strlen(node->nameJoliet));
+ if(rc < 0)
+ return rc;
+ }
+ else
+ {
+ /* ISO9660 requires ";1" after the filename (not directory name)
+ * but the windows NT/2K boot loaders cannot find NTLDR inside
+ * the I386 directory because they are looking for "NTLDR" not
+ * "NTLDR;1". i guess if microsoft can do it, i can do it. filenames
+ * on images written by me do not end with ";1"
+ if(isADir)
+ {*/
+ /* the name */
+ rc = wcWrite(volInfo, node->name9660, lenFileId);
+ if(rc <= 0)
+ return rc;
+ /*}
+ else
+ {
+ rc = writeWrapper(image, node->name9660, lenFileId - 2);
+ if(rc <= 0)
+ return rc;
+
+ rc = writeWrapper(image, ";1", 2);
+ if(rc <= 0)
+ return rc;
+ }*/
+ }
+ }
+ /* END FILE identifier */
+
+ /* padding field */
+ if(lenFileId % 2 == 0)
+ {
+ byte = 0;
+ rc = write711(volInfo, byte);
+ if(rc <= 0)
+ return rc;
+ }
+
+ if(filenameTypes & FNTYPE_ROCKRIDGE)
+ {
+ if(isFirstRecord)
+ {
+ rc = writeRockSP(volInfo);
+ if(rc < 0)
+ return rc;
+
+ rc = writeRockER(volInfo);
+ if(rc < 0)
+ return rc;
+ }
+
+ rc = writeRockPX(volInfo, node->posixFileMode, isADir);
+ if(rc < 0)
+ return rc;
+
+ if(!isSelfOrParent)
+ {
+ if(wcSeekTell(volInfo) - startPos < (int)strlen(node->nameRock) + 5)
+ /* have no room for the NM entry in this directory record */
+ {
+ node->offsetForCE = wcSeekTell(volInfo);
+ /* leave room for CE entry */
+ wcSeekForward(volInfo, 28);
+ }
+ else
+ {
+ rc = writeRockNM(volInfo, node->nameRock, strlen(node->nameRock), false);
+ if(rc < 0)
+ return rc;
+ }
+
+ if(IS_SYMLINK(node->posixFileMode))
+ {
+ rc = writeRockSL(volInfo, SYMLINKTW_PTR(node), true);
+ if(rc < 0)
+ return rc;
+ }
+ }
+ }
+
+ /* RECORD length */
+ endPos = wcSeekTell(volInfo);
+
+ wcSeekSet(volInfo, startPos);
+
+ recordLen = endPos - startPos;
+ rc = write711(volInfo, recordLen);
+ if(rc <= 0)
+ return rc;
+
+ wcSeekSet(volInfo, endPos);
+ /* END RECORD length */
+
+ /* the goto is good! really!
+ * if, after writing the record we see that the record is in two logical
+ * sectors (that's not allowed by iso9660) we erase the record just
+ * written, write zeroes to the end of the first logical sector
+ * (as required by iso9660) and restart the function, which will write
+ * the same record again but at the beginning of the next logical sector
+ * yeah, so don't complain :) */
+
+ if(endPos / NBYTES_LOGICAL_BLOCK > startPos / NBYTES_LOGICAL_BLOCK)
+ /* crossed a logical sector boundary while writing the record */
+ {
+ wcSeekSet(volInfo, startPos);
+
+ /* overwrite a piece of the record written in this function
+ * (the piece that's in the first sector) with zeroes */
+ rc = writeByteBlock(volInfo, 0x00, recordLen - endPos % NBYTES_LOGICAL_BLOCK);
+ if(rc < 0)
+ return rc;
+
+ goto writeDrStartLabel;
+ }
+
+ return 1;
+}
+
+/******************************************************************************
+* writeElToritoBootCatalog()
+* Write the el torito boot catalog (validation entry and inital/default entry).
+* Returns the offset where the boot record sector number should
+* be written (7.3.1).
+* */
+int writeElToritoBootCatalog(VolInfo* volInfo,
+ bk_off_t* bootRecordSectorNumberOffset)
+{
+ unsigned char buffer[NBYTES_LOGICAL_BLOCK];
+ int rc;
+
+ memset(buffer, 0, NBYTES_LOGICAL_BLOCK);
+
+ if(wcSeekTell(volInfo) % NBYTES_LOGICAL_BLOCK != 0)
+ /* file pointer not at sector boundary */
+ return BKERROR_SANITY;
+
+ /* SETUP VALIDATION entry (first 20 bytes of boot catalog) */
+ /* header, must be 1 */
+ buffer[0] = 1;
+ /* platform id, 0 for x86 (bzero at start took care of this) */
+ /* 2 bytes reserved, must be 0 (bzero at start took care of this) */
+ /* 24 bytes id string for manufacturer/developer of cdrom */
+ strncpy((char*)&(buffer[4]), "Edited with ISO Master", 22);
+ /* key byte 0x55 */
+ buffer[30] = 0x55;
+ /* key byte 0xAA */
+ buffer[31] = 0xAA;
+
+ /* checksum */
+ write721ToByteArray(&(buffer[28]), elToritoChecksum(buffer));
+ /* END SETUP VALIDATION validation entry (first 20 bytes of boot catalog) */
+
+ /* SETUP INITIAL entry (next 20 bytes of boot catalog) */
+ /* boot indicator. 0x88 = bootable */
+ buffer[32] = 0x88;
+ /* boot media type */
+ if(volInfo->bootMediaType == BOOT_MEDIA_NO_EMULATION)
+ buffer[33] = 0;
+ else if(volInfo->bootMediaType == BOOT_MEDIA_1_2_FLOPPY)
+ buffer[33] = 1;
+ else if(volInfo->bootMediaType == BOOT_MEDIA_1_44_FLOPPY)
+ buffer[33] = 2;
+ else if(volInfo->bootMediaType == BOOT_MEDIA_2_88_FLOPPY)
+ buffer[33] = 3;
+ else if(volInfo->bootMediaType == BOOT_MEDIA_HARD_DISK)
+ buffer[33] = 4;
+ /* load segment leave it at 0 */
+ /* system type, leave it at 0 */
+ /* 1 byte unused, leave it at 0 */
+ /* sector count. i have yet to see a boot record with a sector count
+ * that's not 4 */
+ write721ToByteArray(&(buffer[38]), 4);
+ /* logical block number of boot record file. this is not known until
+ * after that file is written */
+ *bootRecordSectorNumberOffset = wcSeekTell(volInfo) + 40;
+ /* the rest is unused, leave it at 0 */
+ /* END SETUP INITIAL entry (next 20 bytes of boot catalog) */
+
+ rc = wcWrite(volInfo, (char*)buffer, NBYTES_LOGICAL_BLOCK);
+ if(rc <= 0)
+ return rc;
+
+ return 1;
+}
+
+/******************************************************************************
+* writeElToritoVd()
+* Write the el torito volume descriptor.
+* Returns the offset where the boot catalog sector number should
+* be written (7.3.1).
+* */
+int writeElToritoVd(VolInfo* volInfo, bk_off_t* bootCatalogSectorNumberOffset)
+{
+ char buffer[NBYTES_LOGICAL_BLOCK];
+ int rc;
+
+ memset(buffer, 0, NBYTES_LOGICAL_BLOCK);
+
+ if(wcSeekTell(volInfo) % NBYTES_LOGICAL_BLOCK != 0)
+ /* file pointer not at sector boundary */
+ return BKERROR_SANITY;
+
+ /* SETUP BOOT record volume descriptor sector */
+ /* boot record indicator, must be 0 (bzero at start took care of this) */
+ /* iso9660 identifier, must be "CD001" */
+ strncpy((char*)buffer + 1, "CD001", 5);
+ /* version, must be 1 */
+ buffer[6] = 1;
+ /* boot system identifier, must be 32 bytes "EL TORITO SPECIFICATION"
+ * padded with 0x00 (bzero at start took care of this) */
+ strncpy(&(buffer[7]), "EL TORITO SPECIFICATION", 23);
+ /* unused 32 bytes, must be 0 (bzero at start took care of this) */
+ /* boot catalog location, 4 byte intel format. written later. */
+ *bootCatalogSectorNumberOffset = wcSeekTell(volInfo) + 71;
+ /*write731ToByteArray(&(buffer[71]), bootCatalogSectorNumber);*/
+ /* the rest of this sector is unused, must be set to 0 */
+ /* END SETUP BOOT record volume descriptor sector */
+
+ rc = wcWrite(volInfo, buffer, NBYTES_LOGICAL_BLOCK);
+ if(rc <= 0)
+ return rc;
+
+ return 1;
+}
+
+/******************************************************************************
+* writeFileContents()
+* Write file contents into an extent and also write the file's location and
+* size into the directory records back in the tree.
+* Also write location and size for symbolic links.
+* */
+int writeFileContents(VolInfo* volInfo, DirToWrite* dir, int filenameTypes)
+{
+ int rc;
+
+ BaseToWrite* child;
+ int numUnusedBytes;
+ int srcFile;
+ bk_off_t endPos;
+
+ child = dir->children;
+ while(child != NULL)
+ /* each file in current directory */
+ {
+ if(volInfo->stopOperation)
+ return BKERROR_OPER_CANCELED_BY_USER;
+
+ if(wcSeekTell(volInfo) % NBYTES_LOGICAL_BLOCK != 0)
+ return BKERROR_SANITY;
+
+ if( IS_REG_FILE(child->posixFileMode) )
+ {
+ bool needToCopy = true;
+
+ child->extentNumber = wcSeekTell(volInfo) / NBYTES_LOGICAL_BLOCK;
+ if(volInfo->scanForDuplicateFiles)
+ {
+ if(FILETW_PTR(child)->location->extentNumberWrittenTo == 0)
+ /* file not yet written */
+ {
+ FILETW_PTR(child)->location->extentNumberWrittenTo = child->extentNumber;
+ }
+ else
+ {
+ child->extentNumber = FILETW_PTR(child)->location->extentNumberWrittenTo;
+ needToCopy = false;
+ }
+ }
+
+ if(volInfo->bootMediaType != BOOT_MEDIA_NONE &&
+ volInfo->bootRecordIsVisible &&
+ FILETW_PTR(child)->origFile == volInfo->bootRecordOnImage)
+ /* this file is the boot record. write its sector number in
+ * the boot catalog */
+ {
+ bk_off_t currPos;
+
+ currPos = wcSeekTell(volInfo);
+
+ wcSeekSet(volInfo, volInfo->bootRecordSectorNumberOffset);
+ rc = write731(volInfo, child->extentNumber);
+ if(rc <= 0)
+ return rc;
+
+ wcSeekSet(volInfo, currPos);
+ }
+
+ if(needToCopy)
+ {
+ if(FILETW_PTR(child)->onImage)
+ /* copy file from original image to new one */
+ {
+ readSeekSet(volInfo, FILETW_PTR(child)->offset,
+ SEEK_SET);
+
+ rc = writeByteBlockFromFile(volInfo->imageForReading,
+ volInfo, FILETW_PTR(child)->size);
+ if(rc < 0)
+ return rc;
+ }
+ else
+ /* copy file from fs to new image */
+ {
+ /* UPDATE the file's size, in case it's changed since we added it */
+ BkStatStruct statStruct;
+
+ rc = bkStat(FILETW_PTR(child)->pathAndName, &statStruct);
+ if(rc != 0)
+ return BKERROR_STAT_FAILED;
+
+ if(statStruct.st_size > 0xFFFFFFFF)
+ /* size won't fit in a 32bit variable on the iso */
+ return BKERROR_EDITED_WRITE_TOO_BIG;
+
+ FILETW_PTR(child)->size = statStruct.st_size;
+ /* UPDATE the file's size, in case it's changed since we added it */
+
+ srcFile = open(FILETW_PTR(child)->pathAndName, O_RDONLY, 0);
+ if(srcFile == -1)
+ return BKERROR_OPEN_READ_FAILED;
+
+ rc = writeByteBlockFromFile(srcFile,
+ volInfo, FILETW_PTR(child)->size);
+
+ bkClose(srcFile);
+
+ if(rc < 0)
+ return rc;
+ }
+
+ /* fill extent with zeroes */
+ numUnusedBytes = NBYTES_LOGICAL_BLOCK -
+ wcSeekTell(volInfo) % NBYTES_LOGICAL_BLOCK;
+ rc = writeByteBlock(volInfo, 0x00, numUnusedBytes);
+ if(rc < 0)
+ return rc;
+ }
+
+ endPos = wcSeekTell(volInfo);
+
+ bool isIsolinux;
+ rc = wroteIsolinuxBootRecord(volInfo, FILETW_PTR(child), &isIsolinux);
+ if(rc < 0)
+ return rc;
+
+ if(isIsolinux)
+ /* write the boot info table for the isolinux boot record */
+ {
+ unsigned char bootInfoTable[56];
+ unsigned checksum;
+
+ memset(bootInfoTable, 0, 56);
+
+ /* go to the offset in the file where the boot info table is */
+ wcSeekSet(volInfo, child->extentNumber *
+ NBYTES_LOGICAL_BLOCK + 8);
+
+ /* sector number of pvd */
+ write731ToByteArray(bootInfoTable, 16);
+ /* sector number of boot file (this one) */
+ write731ToByteArray(bootInfoTable + 4, child->extentNumber);
+ /* boot file length in bytes */
+ write731ToByteArray(bootInfoTable + 8, FILETW_PTR(child)->size);
+ /* 32 bit checksum (the sum of all the 32-bit words in the boot
+ * file starting at byte offset 64 */
+ rc = bootInfoTableChecksum(volInfo->imageForReading, FILETW_PTR(child), &checksum);
+ if(rc <= 0)
+ return rc;
+ write731ToByteArray(bootInfoTable + 12, checksum);
+ /* the rest is reserved, leave at zero */
+
+ rc = wcWrite(volInfo, (char*)bootInfoTable, 56);
+ if(rc <= 0)
+ return rc;
+ }
+
+ /* WRITE file location and size */
+ wcSeekSet(volInfo, child->extentLocationOffset);
+
+ rc = write733(volInfo, child->extentNumber);
+ if(rc <= 0)
+ return rc;
+
+ rc = write733(volInfo, FILETW_PTR(child)->size);
+ if(rc <= 0)
+ return rc;
+
+ if(filenameTypes & FNTYPE_JOLIET)
+ /* also update location and size on joliet tree */
+ {
+ wcSeekSet(volInfo, child->extentLocationOffset2);
+
+ rc = write733(volInfo, child->extentNumber);
+ if(rc <= 0)
+ return rc;
+
+ rc = write733(volInfo, FILETW_PTR(child)->size);
+ if(rc <= 0)
+ return rc;
+ }
+
+ wcSeekSet(volInfo, endPos);
+ /* END WRITE file location and size */
+ }
+ else if( IS_DIR(child->posixFileMode) )
+ {
+ rc = writeFileContents(volInfo, DIRTW_PTR(child), filenameTypes);
+ if(rc < 0)
+ return rc;
+ }
+ else if( IS_SYMLINK(child->posixFileMode) )
+ {
+ /* WRITE symlink location and size (0) */
+ endPos = wcSeekTell(volInfo);
+
+ wcSeekSet(volInfo, child->extentLocationOffset);
+
+ rc = write733(volInfo, 0);
+ if(rc <= 0)
+ return rc;
+
+ rc = write733(volInfo, 0);
+ if(rc <= 0)
+ return rc;
+
+ if(filenameTypes & FNTYPE_JOLIET)
+ /* also update location and size on joliet tree */
+ {
+ wcSeekSet(volInfo, child->extentLocationOffset2);
+
+ rc = write733(volInfo, 0);
+ if(rc <= 0)
+ return rc;
+
+ rc = write733(volInfo, 0);
+ if(rc <= 0)
+ return rc;
+ }
+
+ wcSeekSet(volInfo, endPos);
+ /* END WRITE symlink location and size (0) */
+ }
+
+ child = child->next;
+
+ } /* while(nextFile != NULL) */
+
+ return 1;
+}
+
+/* field size must be even. !!check all calls to make sure */
+int writeJolietStringField(VolInfo* volInfo, const char* name, size_t fieldSize)
+{
+ char jolietName[512]; /* don't see why would ever want
+ * to write a longer one */
+ int srcCount;
+ size_t destCount;
+ int rc;
+
+ srcCount = 0;
+ destCount = 0;
+ while(name[srcCount] != '\0' && destCount < fieldSize)
+ {
+ /* first byte zero */
+ jolietName[destCount] = 0x00;
+ /* second byte character */
+ jolietName[destCount + 1] = name[srcCount];
+
+ srcCount += 1;
+ destCount += 2;
+ }
+
+ while(destCount < fieldSize)
+ /* pad with ucs2 spaces */
+ {
+ jolietName[destCount] = 0x00;
+ jolietName[destCount + 1] = ' ';
+
+ destCount += 2;
+ }
+
+ rc = wcWrite(volInfo, jolietName, destCount);
+ if(rc <= 0)
+ return rc;
+
+ return 1;
+}
+
+/* write NM that won't fit in a directory record */
+int writeLongNM(VolInfo* volInfo, BaseToWrite* node)
+{
+ bk_off_t startPos;
+ size_t fullNameLen;
+ unsigned char CErecord[28];
+ bool fitsInOneNM;
+ size_t firstNMlen;
+ bk_off_t endPos;
+ int rc;
+ int lenOfCE;
+
+ startPos = wcSeekTell(volInfo);
+
+ fullNameLen = strlen(node->nameRock);
+
+ /* should have checked for this before getting into this function */
+ if(fullNameLen > 255)
+ return BKERROR_SANITY;
+
+ if(fullNameLen > 250)
+ {
+ fitsInOneNM = false;
+ firstNMlen = 250;
+ }
+ else
+ {
+ fitsInOneNM = true;
+ firstNMlen = fullNameLen;
+ }
+
+ /* NM record(s) */
+ if(fitsInOneNM)
+ {
+ rc = writeRockNM(volInfo, node->nameRock, firstNMlen, false);
+ if(rc <= 0)
+ return rc;
+ }
+ else
+ {
+ rc = writeRockNM(volInfo, node->nameRock, firstNMlen, true);
+ if(rc <= 0)
+ return rc;
+ rc = writeRockNM(volInfo, node->nameRock + firstNMlen, fullNameLen - firstNMlen, false);
+ if(rc <= 0)
+ return rc;
+ }
+
+ lenOfCE = wcSeekTell(volInfo) - startPos;
+
+ /* write blank to conclude extent */
+ rc = writeByteBlock(volInfo, 0x00, NBYTES_LOGICAL_BLOCK -
+ wcSeekTell(volInfo) % NBYTES_LOGICAL_BLOCK);
+ if(rc < 0)
+ return rc;
+
+ endPos = wcSeekTell(volInfo);
+
+ /* CE record back in the directory record */
+ wcSeekSet(volInfo, node->offsetForCE);
+
+ CErecord[0] = 'C';
+ CErecord[1] = 'E';
+ CErecord[2] = 28; /* length */
+ CErecord[3] = 1; /* version */
+ write733ToByteArray(CErecord + 4, startPos / NBYTES_LOGICAL_BLOCK); /* block location */
+ /* i'm always using 1 logical block per name */
+ write733ToByteArray(CErecord + 12, 0); /* offset to start */
+ write733ToByteArray(CErecord + 20, lenOfCE); /* length */
+
+ rc = wcWrite(volInfo, (char*)CErecord, CErecord[2]);
+ if(rc <= 0)
+ return rc;
+ /* END CE record back in the directory record */
+
+ wcSeekSet(volInfo, endPos);
+
+ return 1;
+}
+
+/* write all NMs in the tree that won't fit in directory records */
+int writeLongNMsInDir(VolInfo* volInfo, DirToWrite* dir)
+{
+ BaseToWrite* child;
+ int rc;
+
+ child = dir->children;
+ while(child != NULL)
+ {
+ if(child->offsetForCE != 0)
+ {
+ rc = writeLongNM(volInfo, child);
+ if(rc <= 0)
+ return rc;
+ }
+
+ if( IS_DIR(child->posixFileMode) )
+ {
+ rc = writeLongNMsInDir(volInfo, DIRTW_PTR(child));
+ if(rc <= 0)
+ return rc;
+ }
+
+ child = child->next;
+ }
+
+ return 1;
+}
+
+/* returns path table size (number of bytes not counting the blank) */
+int writePathTable(VolInfo* volInfo, const DirToWrite* tree, bool isTypeL,
+ int filenameType)
+{
+ int treeHeight;
+ int count;
+ int level;
+ int* dirsPerLevel; /* a dynamic array of the number of dirs per level */
+ int numDirsSoFar;
+ bk_off_t origPos;
+ int numBytesWritten;
+ int rc;
+
+ origPos = wcSeekTell(volInfo);
+
+ if(origPos % NBYTES_LOGICAL_BLOCK != 0)
+ return BKERROR_SANITY;
+
+ treeHeight = countTreeHeight(tree, 1);
+
+ dirsPerLevel = malloc(sizeof(int) * treeHeight);
+ if(dirsPerLevel == NULL)
+ return BKERROR_OUT_OF_MEMORY;
+
+ for(count = 0; count < treeHeight; count++)
+ {
+ dirsPerLevel[count] = countDirsOnLevel(tree, count + 1, 1);
+ }
+
+ for(level = 1; level <= treeHeight; level++)
+ {
+ if(level == 1)
+ /* numDirsSoFar = parent dir num */
+ numDirsSoFar = 1;
+ else if(level == 2)
+ numDirsSoFar = 1;
+ else
+ {
+ /* ex. when i am on level 4 i want number of dirs on levels 1 + 2 */
+ numDirsSoFar = 0;
+ for(count = 0; count < level - 2; count++)
+ {
+ numDirsSoFar += dirsPerLevel[count];
+ }
+ }
+
+ rc = writePathTableRecordsOnLevel(volInfo, tree, isTypeL, filenameType,
+ level, 1, &numDirsSoFar);
+ if(rc < 0)
+ {
+ free(dirsPerLevel);
+ return rc;
+ }
+ }
+
+ numBytesWritten = wcSeekTell(volInfo) - origPos;
+
+ /* blank to conclude extent */
+ rc = writeByteBlock(volInfo, 0x00, NBYTES_LOGICAL_BLOCK -
+ numBytesWritten % NBYTES_LOGICAL_BLOCK);
+ if(rc < 0)
+ {
+ free(dirsPerLevel);
+ return rc;
+ }
+
+ free(dirsPerLevel);
+
+ return numBytesWritten;
+}
+
+int writePathTableRecordsOnLevel(VolInfo* volInfo, const DirToWrite* dir,
+ bool isTypeL, int filenameType,
+ int targetLevel, int thisLevel,
+ int* parentDirNum)
+{
+ int rc;
+ BaseToWrite* child;
+
+ unsigned char fileIdLen;
+ unsigned char byte;
+ unsigned exentLocation;
+ unsigned short parentDirId; /* copy of *parentDirNum */
+ static const char rootId = 0x00;
+
+ if(thisLevel == targetLevel)
+ /* write path table record */
+ {
+ /* LENGTH of directory identifier */
+ if(targetLevel == 1)
+ /* root */
+ fileIdLen = 1;
+ else
+ {
+ if(filenameType & FNTYPE_JOLIET)
+ {
+ fileIdLen = 2 * strlen(BASETW_PTR(dir)->nameJoliet);
+ }
+ else
+ {
+ fileIdLen = strlen(BASETW_PTR(dir)->name9660);
+ }
+ }
+
+ rc = write711(volInfo, fileIdLen);
+ if(rc <= 0)
+ return rc;
+ /* END LENGTH of directory identifier */
+
+ /* extended attribute record length */
+ byte = 0;
+ rc = write711(volInfo, byte);
+ if(rc <= 0)
+ return rc;
+
+ /* LOCATION of extent */
+ if(filenameType & FNTYPE_JOLIET)
+ exentLocation = dir->extentNumber2;
+ else
+ exentLocation = BASETW_PTR(dir)->extentNumber;
+
+ if(isTypeL)
+ rc = write731(volInfo, exentLocation);
+ else
+ rc = write732(volInfo, exentLocation);
+ if(rc <= 0)
+ return rc;
+ /* END LOCATION of extent */
+
+ /* PARENT directory number */
+ parentDirId = *parentDirNum;
+
+ if(isTypeL)
+ rc = write721(volInfo, parentDirId);
+ else
+ rc = write722(volInfo, parentDirId);
+
+ if(rc <= 0)
+ return rc;
+ /* END PARENT directory number */
+
+ /* DIRECTORY identifier */
+ if(targetLevel == 1)
+ /* root */
+ {
+ rc = wcWrite(volInfo, &rootId, 1);
+ if(rc <= 0)
+ return rc;
+ }
+ else
+ {
+ if(filenameType & FNTYPE_JOLIET)
+ {
+ rc = writeJolietStringField(volInfo, BASETW_PTR(dir)->nameJoliet, fileIdLen);
+ if(rc < 0)
+ return rc;
+ }
+ else
+ {
+ rc = wcWrite(volInfo, BASETW_PTR(dir)->name9660, fileIdLen);
+ if(rc <= 0)
+ return rc;
+ }
+ }
+ /* END DIRECTORY identifier */
+
+ /* padding field */
+ if(fileIdLen % 2 != 0)
+ {
+ byte = 0;
+ rc = write711(volInfo, byte);
+ if(rc <= 0)
+ return rc;
+ }
+
+ }
+ else /* if(thisLevel < targetLevel) */
+ {
+ child = dir->children;
+ while(child != NULL)
+ {
+ if( IS_DIR(child->posixFileMode) )
+ {
+ if(thisLevel == targetLevel - 2)
+ /* am now going throught the list of dirs where the parent is */
+ {
+ if(targetLevel != 2)
+ /* first and second level have the same parent: 1 */
+ {
+ (*parentDirNum)++;
+ }
+ }
+
+ rc = writePathTableRecordsOnLevel(volInfo, DIRTW_PTR(child), isTypeL,
+ filenameType, targetLevel,
+ thisLevel + 1, parentDirNum);
+ if(rc < 0)
+ return rc;
+ }
+
+ child = child->next;
+ }
+ }
+
+ return 1;
+}
+
+/* This doesn't need support for CE because it's only written in one place,
+* the root 'self' directory record. */
+int writeRockER(VolInfo* volInfo)
+{
+ int rc;
+ char record[46];
+
+ /* identification */
+ record[0] = 'E';
+ record[1] = 'R';
+
+ /* record length */
+ record[2] = 46;
+
+ /* entry version */
+ record[3] = 1;
+
+ /* extension identifier length */
+ record[4] = 10;
+
+ /* extension descriptor length */
+ record[5] = 10;
+
+ /* extension source length */
+ record[6] = 18;
+
+ /* extension version */
+ record[7] = 1;
+
+ /* extension identifier */
+ strncpy(&(record[8]), "IEEE_P1282", 10);
+
+ /* extension descriptor */
+ strncpy(&(record[18]), "DRAFT_1_12", 10);
+
+ /* extension source */
+ strncpy(&(record[28]), "ADOPTED_1994_07_08", 18);
+
+ rc = wcWrite(volInfo, record, 46);
+ if(rc <= 0)
+ return rc;
+
+ return 1;
+}
+
+int writeRockNM(VolInfo* volInfo, char* name, size_t nameLen, bool doesContinue)
+{
+ int rc;
+ char recordStart[5];
+
+ /* identification */
+ recordStart[0] = 'N';
+ recordStart[1] = 'M';
+
+ /* record length */
+ recordStart[2] = 5 + nameLen;
+
+ /* entry version */
+ recordStart[3] = 1;
+
+ /* flags */
+ if(doesContinue)
+ recordStart[4] = 0x01;
+ else
+ recordStart[4] = 0;
+
+ rc = wcWrite(volInfo, recordStart, 5);
+ if(rc <= 0)
+ return rc;
+
+ rc = wcWrite(volInfo, name, nameLen);
+ if(rc <= 0)
+ return rc;
+
+ return 1;
+}
+
+/* the slackware cd has 36 byte PX entries, missing the file serial number
+* so i will do the same */
+int writeRockPX(VolInfo* volInfo, unsigned posixFileMode, bool isADir)
+{
+ int rc;
+ unsigned char record[36];
+ unsigned posixFileLinks;
+
+ /* identification */
+ record[0] = 'P';
+ record[1] = 'X';
+
+ /* record length */
+ record[2] = 36;
+
+ /* entry version */
+ record[3] = 1;
+
+ /* posix file mode */
+ write733ToByteArray(&(record[4]), posixFileMode);
+
+ /* POSIX file links */
+ /*
+ * this i think is number of subdirectories + 2 (self and parent)
+ * and 1 for a file
+ * it's probably not used on read-only filesystems
+ * to add it, i would need to pass the number of links in a parent dir
+ * recursively in writeDir(). brrrrr.
+ */
+ if(isADir)
+ posixFileLinks = 2;
+ else
+ posixFileLinks = 1;
+
+ write733ToByteArray(&(record[12]), posixFileLinks);
+ /* END POSIX file links */
+
+ /* posix file user id, posix file group id */
+ memset(&(record[20]), 0, 16);
+
+ rc = wcWrite(volInfo, (char*)record, 36);
+ if(rc <= 0)
+ return rc;
+
+ return 1;
+}
+
+int writeRockSL(VolInfo* volInfo, SymLinkToWrite* symlink, bool doWrite)
+{
+ size_t stringCount;
+ size_t targetLen;
+ size_t numBytesNeeded;
+ size_t numBytesToSkip;
+ unsigned char* record;
+ size_t recordCount;
+ int rc;
+
+ targetLen = strlen(symlink->target);
+
+ /* figure out how much room i need */
+ numBytesNeeded = 0;
+ numBytesToSkip = 0;
+ stringCount = 0;
+ while(stringCount < targetLen)
+ {
+ char* nextSlash;
+
+ if(symlink->target[stringCount] == '/')
+ /* root (/) */
+ {
+ numBytesNeeded += 2;
+ numBytesToSkip = 1;
+ }
+ else if( symlink->target[stringCount] == '.' &&
+ (stringCount + 1 == targetLen || symlink->target[stringCount + 1] == '/') )
+ /* current (.) */
+ {
+ numBytesNeeded += 2;
+ numBytesToSkip = 2;
+ }
+ else if( symlink->target[stringCount] == '.' &&
+ stringCount + 1 < targetLen && symlink->target[stringCount + 1] == '.' )
+ /* parent (..) */
+ {
+ numBytesNeeded += 2;
+ numBytesToSkip = 3;
+ }
+ else
+ /* regular filename */
+ {
+ nextSlash = strchr(symlink->target + stringCount, '/');
+ if(nextSlash != NULL)
+ numBytesToSkip = nextSlash - (symlink->target + stringCount);
+ else
+ numBytesToSkip = targetLen - stringCount;
+
+ numBytesNeeded += 2 + numBytesToSkip;
+
+ numBytesToSkip += 1;
+ }
+
+ stringCount += numBytesToSkip;
+ }
+
+ if(!doWrite)
+ return (int)(5 + numBytesNeeded);
+
+ if(numBytesNeeded > NCHARS_SYMLINK_TARGET_MAX - 1)
+ return BKERROR_SYMLINK_TARGET_TOO_LONG;
+
+ record = malloc(5 + numBytesNeeded);
+ if(record == NULL)
+ return BKERROR_OUT_OF_MEMORY;
+
+ record[0] = 'S';
+ record[1] = 'L';
+ record[2] = 5 + numBytesNeeded; /* length */
+ record[3] = 1; /* version */
+ record[4] = 0x00; /* flags */
+
+ /* write SL */
+ numBytesToSkip = 0;
+ stringCount = 0;
+ recordCount = 5;
+ while(stringCount < targetLen)
+ {
+ char* nextSlash;
+
+ if(symlink->target[stringCount] == '/')
+ /* root (/) */
+ {
+ numBytesToSkip = 1;
+ record[recordCount] = 0x08;
+ record[recordCount + 1] = 0;
+ recordCount += 2;
+ }
+ else if( symlink->target[stringCount] == '.' &&
+ (stringCount + 1 == targetLen || symlink->target[stringCount + 1] == '/') )
+ /* current (.) */
+ {
+ numBytesToSkip = 2;
+ record[recordCount] = 0x02;
+ record[recordCount + 1] = 0;
+ recordCount += 2;
+ }
+ else if( symlink->target[stringCount] == '.' &&
+ stringCount + 1 < targetLen && symlink->target[stringCount + 1] == '.' )
+ /* parent (..) */
+ {
+ numBytesToSkip = 3;
+ record[recordCount] = 0x04;
+ record[recordCount + 1] = 0;
+ recordCount += 2;
+ }
+ else
+ /* regular filename */
+ {
+ nextSlash = strchr(symlink->target + stringCount, '/');
+ if(nextSlash != NULL)
+ numBytesToSkip = nextSlash - (symlink->target + stringCount);
+ else
+ numBytesToSkip = targetLen - stringCount;
+
+ record[recordCount] = 0x00;
+ record[recordCount + 1] = numBytesToSkip;
+ strncpy((char*)record + recordCount + 2, symlink->target + stringCount, numBytesToSkip);
+ recordCount += 2 + numBytesToSkip;
+
+ numBytesToSkip += 1;
+ }
+
+ /* + separator */
+ stringCount += numBytesToSkip;
+ }
+
+ if(recordCount != numBytesNeeded + 5)
+ {
+ free(record);
+ return BKERROR_SANITY;
+ }
+
+ rc = wcWrite(volInfo, (char*)record, recordCount);
+ if(rc <= 0)
+ {
+ free(record);
+ return rc;
+ }
+
+ free(record);
+
+ return (int)(5 + numBytesNeeded);
+}
+
+/* This doesn't need support for CE because it's only written in one place,
+* the root 'self' directory record. */
+int writeRockSP(VolInfo* volInfo)
+{
+ int rc;
+ unsigned char record[7];
+
+ /* identification */
+ record[0] = 'S';
+ record[1] = 'P';
+
+ /* record length */
+ record[2] = 7;
+
+ /* entry version */
+ record[3] = 1;
+
+ /* check bytes */
+ record[4] = 0xBE;
+ record[5] = 0xEF;
+
+ /* bytes skipped */
+ record[6] = 0;
+
+ rc = wcWrite(volInfo, (char*)record, 7);
+ if(rc <= 0)
+ return rc;
+
+ return 1;
+}
+
+int writeVdsetTerminator(VolInfo* volInfo)
+{
+ int rc;
+ unsigned char byte;
+ unsigned char aString[6];
+
+ /* volume descriptor type */
+ byte = 255;
+ rc = write711(volInfo, byte);
+ if(rc <= 0)
+ return rc;
+
+ /* standard identifier */
+ strcpy((char*)aString, "CD001");
+ rc = wcWrite(volInfo, (char*)aString, 5);
+ if(rc <= 0)
+ return rc;
+
+ /* volume descriptor version */
+ byte = 1;
+ rc = write711(volInfo, byte);
+ if(rc <= 0)
+ return rc;
+
+ rc = writeByteBlock(volInfo, 0, 2041);
+ if(rc < 0)
+ return rc;
+
+ return 1;
+}
+
+/*
+* -has to be called after the files were written so that the
+* volume size is recorded properly
+* -rootdr location, size are in bytes
+* -note strings are not terminated on image
+*/
+int writeVolDescriptor(VolInfo* volInfo, bk_off_t rootDrLocation,
+ unsigned rootDrSize, bk_off_t lPathTableLoc,
+ bk_off_t mPathTableLoc, unsigned pathTableSize,
+ time_t creationTime, bool isPrimary)
+{
+ int rc;
+ size_t count;
+
+ unsigned char byte;
+ unsigned char aString[129];
+ unsigned anUnsigned;
+ unsigned short anUnsignedShort;
+ bk_off_t currPos;
+
+ /* VOLUME descriptor type */
+ if(isPrimary)
+ byte = 1;
+ else
+ byte = 2;
+ /* END VOLUME descriptor type */
+
+ rc = write711(volInfo, byte);
+ if(rc <= 0)
+ return rc;
+
+ /* standard identifier */
+ strcpy((char*)aString, "CD001");
+ rc = wcWrite(volInfo, (char*)aString, 5);
+ if(rc <= 0)
+ return rc;
+
+ /* volume descriptor version (always 1) */
+ byte = 1;
+ rc = write711(volInfo, byte);
+ if(rc <= 0)
+ return rc;
+
+ /* primary: unused field
+ * supplementary: volume flags, 0x00 */
+ byte = 0;
+ rc = write711(volInfo, byte);
+ if(rc <= 0)
+ return rc;
+
+ /* system identifier (32 spaces) */
+ if(isPrimary)
+ {
+ strcpy((char*)aString, " ");
+ rc = wcWrite(volInfo, (char*)aString, 32);
+ if(rc <= 0)
+ return rc;
+ }
+ else
+ {
+ rc = writeJolietStringField(volInfo, "", 32);
+ if(rc < 0)
+ return rc;
+ }
+
+ /* VOLUME identifier */
+ if(isPrimary)
+ {
+ strcpy((char*)aString, volInfo->volId);
+
+ for(count = strlen((char*)aString); count < 32; count++)
+ aString[count] = ' ';
+
+ rc = wcWrite(volInfo, (char*)aString, 32);
+ if(rc <= 0)
+ return rc;
+ }
+ else
+ {
+ rc = writeJolietStringField(volInfo, volInfo->volId, 32);
+ if(rc < 0)
+ return rc;
+ }
+ /* END VOLUME identifier */
+
+ /* unused field */
+ rc = writeByteBlock(volInfo, 0, 8);
+ if(rc < 0)
+ return rc;
+
+ /* VOLUME space size (number of logical blocks, absolutely everything) */
+ /* it's safe to not use wcSeek() here since everything is left as it is */
+ currPos = bkSeekTell(volInfo->imageForWriting);
+
+ bkSeekSet(volInfo->imageForWriting, 0, SEEK_END);
+ anUnsigned = bkSeekTell(volInfo->imageForWriting) /
+ NBYTES_LOGICAL_BLOCK;
+
+ bkSeekSet(volInfo->imageForWriting, currPos, SEEK_SET);
+
+ rc = write733(volInfo, anUnsigned);
+ if(rc <= 0)
+ return rc;
+ /* END VOLUME space size (number of logical blocks, absolutely everything) */
+
+ /* primary: unused field
+ * joliet: escape sequences */
+ if(isPrimary)
+ {
+ rc = writeByteBlock(volInfo, 0, 32);
+ if(rc < 0)
+ return rc;
+ }
+ else
+ {
+ /* this is the only joliet field that's padded with 0x00 instead of ' ' */
+ aString[0] = 0x25;
+ aString[1] = 0x2F;
+ aString[2] = 0x45;
+
+ rc = wcWrite(volInfo, (char*)aString, 3);
+ if(rc <= 0)
+ return rc;
+
+ rc = writeByteBlock(volInfo, 0, 29);
+ if(rc < 0)
+ return rc;
+ }
+
+ /* volume set size (always 1) */
+ anUnsignedShort = 1;
+ rc = write723(volInfo, anUnsignedShort);
+ if(rc <= 0)
+ return rc;
+
+ /* volume sequence number (also always 1) */
+ rc = write723(volInfo, anUnsignedShort);
+ if(rc <= 0)
+ return rc;
+
+ /* logical block size (always 2048) */
+ anUnsignedShort = NBYTES_LOGICAL_BLOCK;
+ rc = write723(volInfo, anUnsignedShort);
+ if(rc <= 0)
+ return rc;
+
+ /* path table size */
+ anUnsigned = pathTableSize;
+ rc = write733(volInfo, anUnsigned);
+ if(rc <= 0)
+ return rc;
+
+ /* location of occurence of type l path table */
+ anUnsigned = lPathTableLoc / NBYTES_LOGICAL_BLOCK;
+ rc = write731(volInfo, anUnsigned);
+ if(rc <= 0)
+ return rc;
+
+ /* location of optional occurence of type l path table */
+ anUnsigned = 0;
+ rc = write731(volInfo, anUnsigned);
+ if(rc <= 0)
+ return rc;
+
+ /* location of occurence of type m path table */
+ anUnsigned = mPathTableLoc / NBYTES_LOGICAL_BLOCK;
+ rc = write732(volInfo, anUnsigned);
+ if(rc <= 0)
+ return rc;
+
+ /* location of optional occurence of type m path table */
+ anUnsigned = 0;
+ rc = write732(volInfo, anUnsigned);
+ if(rc <= 0)
+ return rc;
+
+ /* ROOT dr */
+ /* record length (always 34 here) */
+ byte = 34;
+ rc = write711(volInfo, byte);
+ if(rc <= 0)
+ return rc;
+
+ /* extended attribute record length (always none) */
+ byte = 0;
+ rc = write711(volInfo, byte);
+ if(rc <= 0)
+ return rc;
+
+ /* location of extent */
+ anUnsigned = rootDrLocation / NBYTES_LOGICAL_BLOCK;
+ rc = write733(volInfo, anUnsigned);
+ if(rc <= 0)
+ return rc;
+
+ /* data length */
+ rc = write733(volInfo, rootDrSize);
+ if(rc <= 0)
+ return rc;
+
+ /* recording time */
+ epochToShortString(creationTime, (char*)aString);
+ rc = wcWrite(volInfo, (char*)aString, 7);
+ if(rc <= 0)
+ return rc;
+
+ /* file flags (always binary 00000010 here) */
+ byte = 0x02;
+ rc = write711(volInfo, byte);
+ if(rc <= 0)
+ return rc;
+
+ /* file unit size (not in interleaved mode -> 0) */
+ byte = 0;
+ rc = write711(volInfo, byte);
+ if(rc <= 0)
+ return rc;
+
+ /* interleave gap size (not in interleaved mode -> 0) */
+ rc = write711(volInfo, byte);
+ if(rc <= 0)
+ return rc;
+
+ /* volume sequence number */
+ anUnsignedShort = 1;
+ rc = write723(volInfo, anUnsignedShort);
+ if(rc <= 0)
+ return rc;
+
+ /* length of file identifier */
+ byte = 1;
+ rc = write711(volInfo, byte);
+ if(rc <= 0)
+ return rc;
+
+ /* file identifier */
+ byte = 0;
+ rc = write711(volInfo, byte);
+ if(rc <= 0)
+ return rc;
+ /* END ROOT dr */
+
+ /* volume set identidier */
+ if(isPrimary)
+ {
+ rc = writeByteBlock(volInfo, ' ', 128);
+ if(rc < 0)
+ return rc;
+ }
+ else
+ {
+ rc = writeJolietStringField(volInfo, "", 128);
+ if(rc < 0)
+ return rc;
+ }
+
+ /* PUBLISHER identifier */
+ strcpy((char*)aString, volInfo->publisher);
+
+ if(isPrimary)
+ {
+ for(count = strlen((char*)aString); count < 128; count++)
+ aString[count] = ' ';
+
+ rc = wcWrite(volInfo, (char*)aString, 128);
+ if(rc <= 0)
+ return rc;
+ }
+ else
+ {
+ rc = writeJolietStringField(volInfo, (char*)aString, 128);
+ if(rc < 0)
+ return rc;
+ }
+ /* PUBLISHER identifier */
+
+ /* DATA preparer identifier */
+ if(isPrimary)
+ {
+ rc = wcWrite(volInfo, "ISO Master", 10);
+ if(rc <= 0)
+ return rc;
+
+ rc = writeByteBlock(volInfo, ' ', 118);
+ if(rc < 0)
+ return rc;
+ }
+ else
+ {
+ rc = writeJolietStringField(volInfo, "ISO Master", 128);
+ if(rc < 0)
+ return rc;
+ }
+ /* END DATA preparer identifier */
+
+ /* application identifier, copyright file identifier, abstract file
+ * identifier, bibliographic file identifier (128 + 3*37) */
+ if(isPrimary)
+ {
+ rc = writeByteBlock(volInfo, ' ', 239);
+ if(rc < 0)
+ return rc;
+ }
+ else
+ {
+ /* application id */
+ rc = writeJolietStringField(volInfo, "", 128);
+ if(rc < 0)
+ return rc;
+
+ /* 18 ucs2 spaces + 0x00 */
+ for(count = 0; count < 3; count++)
+ {
+ rc = writeJolietStringField(volInfo, "", 36);
+ if(rc < 0)
+ return rc;
+
+ byte = 0x00;
+ rc = wcWrite(volInfo, (char*)&byte, 1);
+ if(rc <= 0)
+ return rc;
+ }
+ }
+
+ /* VOLUME creation date */
+ epochToLongString(creationTime, (char*)aString);
+
+ rc = wcWrite(volInfo, (char*)aString, 17);
+ if(rc <= 0)
+ return rc;
+ /* END VOLUME creation date */
+
+ /* volume modification date (same as creation) */
+ rc = wcWrite(volInfo, (char*)aString, 17);
+ if(rc <= 0)
+ return rc;
+
+ /* VOLUME expiration date (none) */
+ rc = writeByteBlock(volInfo, '0', 16);
+ if(rc < 0)
+ return rc;
+
+ byte = 0;
+ rc = write711(volInfo, byte);
+ if(rc <= 0)
+ return rc;
+ /* END VOLUME expiration date (none) */
+
+ /* volume effective date (same as creation) */
+ rc = wcWrite(volInfo, (char*)aString, 17);
+ if(rc <= 0)
+ return rc;
+
+ /* file structure version */
+ byte = 1;
+ rc = write711(volInfo, byte);
+ if(rc <= 0)
+ return rc;
+
+ /* reserved, applications use, reserved */
+ rc = writeByteBlock(volInfo, 0, 1166);
+ if(rc < 0)
+ return rc;
+
+ return 1;
+}
+
+/******************************************************************************
+* wroteIsolinuxBootRecord()
+* Check whether the file already written to the new iso was a boot record.
+* */
+int wroteIsolinuxBootRecord(VolInfo* volInfo, FileToWrite* file,
+ bool* isIsolinux)
+{
+ *isIsolinux = false;
+
+ if(volInfo->bootMediaType == BOOT_MEDIA_NO_EMULATION &&
+ volInfo->bootRecordIsVisible &&
+ file->origFile == volInfo->bootRecordOnImage)
+ /* Likely true, do one more check to make sure. The extra check
+ * is needed for Windows XP isos with SP2 added by c't slipstreamer */
+ {
+ bk_off_t origPos;
+ int rc;
+ char fourBytes[4];
+
+ origPos = wcSeekTell(volInfo);
+
+ wcSeekSet(volInfo, BASETW_PTR(file)->extentNumber *
+ NBYTES_LOGICAL_BLOCK + 8);
+
+ rc = bkRead(volInfo->imageForWriting, fourBytes, 4);
+ if(rc != 4)
+ return BKERROR_READ_GENERIC;
+
+ if(fourBytes[0] == 16 && fourBytes[1] == 0 &&
+ fourBytes[2] == 0 && fourBytes[3] == 0)
+ *isIsolinux = true;
+
+ wcSeekSet(volInfo, origPos);
+ }
+
+ return 1;
+}