1 /******************************* LICENCE **************************************
2 * Any code in this file may be redistributed or modified under the terms of
3 * the GNU General Public Licence as published by the Free Software
4 * Foundation; version 2 of the licence.
5 ****************************** END LICENCE ***********************************/
6
7 /******************************************************************************
8 * Author:
9 * Andrew Smith, http://littlesvr.ca/misc/contactandrew.php
10 *
11 * Contributors:
12 *
13 ******************************************************************************/
14
15 /******************************************************************************
16 * Functions in this file write to volInfo.imageForWriting and are probably
17 * unsutable for anything else.
18 ******************************************************************************/
19
20 #include <strings.h>
21 #include <string.h>
22 #include <time.h>
23 #include <stdio.h>
24 #include <fcntl.h>
25 #include <sys/stat.h>
26
27 #include "bk.h"
28 #include "bkInternal.h"
29 #include "bkWrite7x.h"
30 #include "bkTime.h"
31 #include "bkWrite.h"
32 #include "bkMangle.h"
33 #include "bkError.h"
34 #include "bkSort.h"
35 #include "bkPath.h"
36 #include "bkCache.h"
37 #include "bkRead7x.h"
38 #include "bkLink.h"
39 #include "bkIoWrappers.h"
40
41 /******************************************************************************
42 * bk_write_image()
43 * Writes everything from first to last byte of the iso.
44 * Public function.
45 * */
bk_write_image(const char * newImagePathAndName,VolInfo * volInfo,time_t creationTime,int filenameTypes,void (* progressFunction)(VolInfo *,double))46 int bk_write_image(const char* newImagePathAndName, VolInfo* volInfo,
47 time_t creationTime, int filenameTypes,
48 void(*progressFunction)(VolInfo*, double))
49 {
50 int rc;
51 DirToWrite newTree;
52 bk_off_t svdOffset;
53 bk_off_t pRealRootDrOffset;
54 int pRootDirSize;
55 bk_off_t sRealRootDrOffset;
56 int sRootDirSize;
57 bk_off_t lPathTable9660Loc;
58 bk_off_t mPathTable9660Loc;
59 int pathTable9660Size;
60 bk_off_t lPathTableJolietLoc;
61 bk_off_t mPathTableJolietLoc;
62 int pathTableJolietSize;
63 bk_off_t bootCatalogSectorNumberOffset;
64 bk_off_t currPos;
65
66 volInfo->writeProgressFunction = progressFunction;
67 volInfo->stopOperation = false;
68
69 volInfo->estimatedIsoSize = bk_estimate_iso_size(volInfo, filenameTypes);
70 progressFunction(volInfo, 0);
71
72 BkStatStruct statStruct;
73 rc = bkStat(newImagePathAndName, &statStruct);
74 if(rc == 0 && statStruct.st_ino == volInfo->imageForReadingInode)
75 return BKERROR_SAVE_OVERWRITE;
76
77 /* because mangleDir works on dir's children i need to
78 * copy the root manually */
79 memset(&newTree, 0, sizeof(DirToWrite));
80 newTree.base.posixFileMode = volInfo->dirTree.base.posixFileMode;
81
82 printf("mangling\n");fflush(NULL);
83 /* create tree to write */
84 rc = mangleDir(&(volInfo->dirTree), &newTree, filenameTypes);
85 if(rc <= 0)
86 {
87 freeDirToWriteContents(&newTree);
88 return rc;
89 }
90
91 printf("opening '%s' for writing\n", newImagePathAndName);fflush(NULL);
92 volInfo->imageForWriting = open(newImagePathAndName,
93 O_RDWR | O_CREAT | O_TRUNC,
94 S_IRUSR | S_IWUSR);
95 if(volInfo->imageForWriting == -1)
96 {
97 freeDirToWriteContents(&newTree);
98 return BKERROR_OPEN_WRITE_FAILED;
99 }
100
101 printf("writing blank at %X\n", (int)wcSeekTell(volInfo));fflush(NULL);
102 /* system area, always zeroes */
103 rc = writeByteBlock(volInfo, 0, NBYTES_LOGICAL_BLOCK * NLS_SYSTEM_AREA);
104 if(rc <= 0)
105 {
106 freeDirToWriteContents(&newTree);
107 bkClose(volInfo->imageForWriting);
108 unlink(newImagePathAndName);
109 return rc;
110 }
111
112 /* skip pvd (1 block), write it after files */
113 wcSeekForward(volInfo, NBYTES_LOGICAL_BLOCK);
114
115 if(volInfo->bootMediaType != BOOT_MEDIA_NONE)
116 {
117 /* el torito volume descriptor */
118 rc = writeElToritoVd(volInfo, &bootCatalogSectorNumberOffset);
119 if(rc <= 0)
120 {
121 freeDirToWriteContents(&newTree);
122 bkClose(volInfo->imageForWriting);
123 unlink(newImagePathAndName);
124 return rc;
125 }
126 }
127
128 if(filenameTypes & FNTYPE_JOLIET)
129 /* skip svd (1 block), write it after pvd */
130 {
131 svdOffset = wcSeekTell(volInfo);
132 wcSeekForward(volInfo, NBYTES_LOGICAL_BLOCK);
133 }
134
135 printf("writing terminator at %X\n", (int)wcSeekTell(volInfo));fflush(NULL);
136 /* volume descriptor set terminator */
137 rc = writeVdsetTerminator(volInfo);
138 if(rc <= 0)
139 {
140 freeDirToWriteContents(&newTree);
141 bkClose(volInfo->imageForWriting);
142 unlink(newImagePathAndName);
143 return rc;
144 }
145
146 if(volInfo->bootMediaType != BOOT_MEDIA_NONE)
147 {
148 /* write boot catalog sector number */
149 currPos = wcSeekTell(volInfo);
150 wcSeekSet(volInfo, bootCatalogSectorNumberOffset);
151 rc = write731(volInfo, currPos / NBYTES_LOGICAL_BLOCK);
152 if(rc <= 0)
153 {
154 freeDirToWriteContents(&newTree);
155 bkClose(volInfo->imageForWriting);
156 unlink(newImagePathAndName);
157 return rc;
158 }
159 wcSeekSet(volInfo, currPos);
160
161 /* write el torito booting catalog */
162 rc = writeElToritoBootCatalog(volInfo, &(volInfo->bootRecordSectorNumberOffset));
163 if(rc <= 0)
164 {
165 freeDirToWriteContents(&newTree);
166 bkClose(volInfo->imageForWriting);
167 unlink(newImagePathAndName);
168 return rc;
169 }
170 }
171
172 /* MAYBE write boot record file now */
173 if(volInfo->bootMediaType != BOOT_MEDIA_NONE &&
174 !volInfo->bootRecordIsVisible)
175 {
176 int blankSize;
177 int srcFile; /* either the old image or the boot record file on
178 * the regular filesystem */
179 bool srcFileOpened;
180
181 /* set up source file pointer */
182 if(volInfo->bootRecordIsOnImage)
183 {
184 srcFile = volInfo->imageForReading;
185 bkSeekSet(volInfo->imageForReading, volInfo->bootRecordOffset, SEEK_SET);
186 srcFileOpened = false;
187 }
188 else
189 {
190 srcFile = open(volInfo->bootRecordPathAndName, O_RDONLY, 0);
191 if(srcFile == -1)
192 {
193 freeDirToWriteContents(&newTree);
194 bkClose(volInfo->imageForWriting);
195 unlink(newImagePathAndName);
196 return BKERROR_OPEN_READ_FAILED;
197 }
198 srcFileOpened = true;
199 }
200
201 /* write boot record sector number */
202 currPos = wcSeekTell(volInfo);
203 wcSeekSet(volInfo, volInfo->bootRecordSectorNumberOffset);
204
205 rc = write731(volInfo, currPos / NBYTES_LOGICAL_BLOCK);
206 if(rc <= 0)
207 {
208 freeDirToWriteContents(&newTree);
209 if(srcFileOpened)
210 bkClose(srcFile);
211 bkClose(volInfo->imageForWriting);
212 unlink(newImagePathAndName);
213 return rc;
214 }
215 wcSeekSet(volInfo, currPos);
216
217 /* file contents */
218 rc = writeByteBlockFromFile(srcFile, volInfo, volInfo->bootRecordSize);
219 if(rc < 0)
220 {
221 freeDirToWriteContents(&newTree);
222 if(srcFileOpened)
223 bkClose(srcFile);
224 bkClose(volInfo->imageForWriting);
225 unlink(newImagePathAndName);
226 return rc;
227 }
228
229 blankSize = NBYTES_LOGICAL_BLOCK -
230 volInfo->bootRecordSize % NBYTES_LOGICAL_BLOCK;
231
232 /* fill the last sector with 0s */
233 rc = writeByteBlock(volInfo, 0x00, blankSize);
234 if(rc < 0)
235 {
236 freeDirToWriteContents(&newTree);
237 if(srcFileOpened)
238 bkClose(srcFile);
239 bkClose(volInfo->imageForWriting);
240 unlink(newImagePathAndName);
241 return rc;
242 }
243
244 if(srcFileOpened)
245 bkClose(srcFile);
246 }
247 /* END MAYBE write boot record file now */
248
249 printf("sorting 9660\n");
250 sortDir(&newTree, FNTYPE_9660);
251
252 pRealRootDrOffset = wcSeekTell(volInfo);
253
254 printf("writing primary directory tree at %X\n", (int)wcSeekTell(volInfo));fflush(NULL);
255 /* 9660 and maybe rockridge dir tree */
256 rc = writeDir(volInfo, &newTree, 0, 0, 0, creationTime,
257 filenameTypes & (FNTYPE_9660 | FNTYPE_ROCKRIDGE), true);
258 if(rc <= 0)
259 {
260 freeDirToWriteContents(&newTree);
261 bkClose(volInfo->imageForWriting);
262 unlink(newImagePathAndName);
263 return rc;
264 }
265
266 pRootDirSize = rc;
267
268 /* joliet dir tree */
269 if(filenameTypes & FNTYPE_JOLIET)
270 {
271 printf("sorting joliet\n");
272 sortDir(&newTree, FNTYPE_JOLIET);
273
274 printf("writing supplementary directory tree at %X\n", (int)wcSeekTell(volInfo));fflush(NULL);
275 sRealRootDrOffset = wcSeekTell(volInfo);
276
277 rc = writeDir(volInfo, &newTree, 0, 0, 0, creationTime,
278 FNTYPE_JOLIET, true);
279 if(rc <= 0)
280 {
281 freeDirToWriteContents(&newTree);
282 bkClose(volInfo->imageForWriting);
283 unlink(newImagePathAndName);
284 return rc;
285 }
286
287 sRootDirSize = rc;
288 }
289
290 printf("writing 9660 path tables at %X\n", (int)wcSeekTell(volInfo));fflush(NULL);
291
292 lPathTable9660Loc = wcSeekTell(volInfo);
293 rc = writePathTable(volInfo, &newTree, true, FNTYPE_9660);
294 if(rc <= 0)
295 {
296 freeDirToWriteContents(&newTree);
297 bkClose(volInfo->imageForWriting);
298 unlink(newImagePathAndName);
299 return rc;
300 }
301 pathTable9660Size = rc;
302
303 mPathTable9660Loc = wcSeekTell(volInfo);
304 rc = writePathTable(volInfo, &newTree, false, FNTYPE_9660);
305 if(rc <= 0)
306 {
307 freeDirToWriteContents(&newTree);
308 bkClose(volInfo->imageForWriting);
309 unlink(newImagePathAndName);
310 return rc;
311 }
312
313 if(filenameTypes & FNTYPE_JOLIET)
314 {
315 printf("writing joliet path tables at %X\n", (int)wcSeekTell(volInfo));fflush(NULL);
316 lPathTableJolietLoc = wcSeekTell(volInfo);
317 rc = writePathTable(volInfo, &newTree, true, FNTYPE_JOLIET);
318 if(rc <= 0)
319 {
320 freeDirToWriteContents(&newTree);
321 bkClose(volInfo->imageForWriting);
322 unlink(newImagePathAndName);
323 return rc;
324 }
325 pathTableJolietSize = rc;
326
327 mPathTableJolietLoc = wcSeekTell(volInfo);
328 rc = writePathTable(volInfo, &newTree, false, FNTYPE_JOLIET);
329 if(rc <= 0)
330 {
331 freeDirToWriteContents(&newTree);
332 bkClose(volInfo->imageForWriting);
333 unlink(newImagePathAndName);
334 return rc;
335 }
336 }
337
338 printf("writing files at %X\n", (int)wcSeekTell(volInfo));fflush(NULL);
339 resetWriteStatus(volInfo->fileLocations);
340 /* all files and offsets/sizes */
341 rc = writeFileContents(volInfo, &newTree, filenameTypes);
342 if(rc <= 0)
343 {
344 freeDirToWriteContents(&newTree);
345 bkClose(volInfo->imageForWriting);
346 unlink(newImagePathAndName);
347 return rc;
348 }
349
350 if(filenameTypes & FNTYPE_ROCKRIDGE)
351 {
352 printf("writing long NMs at %X\n", (int)wcSeekTell(volInfo));fflush(NULL);
353 rc = writeLongNMsInDir(volInfo, &newTree);
354 if(rc <= 0)
355 {
356 freeDirToWriteContents(&newTree);
357 bkClose(volInfo->imageForWriting);
358 unlink(newImagePathAndName);
359 return rc;
360 }
361 }
362
363 wcSeekSet(volInfo, NBYTES_LOGICAL_BLOCK * NLS_SYSTEM_AREA);
364
365 printf("writing pvd at %X\n", (int)wcSeekTell(volInfo));fflush(NULL);
366 rc = writeVolDescriptor(volInfo, pRealRootDrOffset,
367 pRootDirSize, lPathTable9660Loc, mPathTable9660Loc,
368 pathTable9660Size, creationTime, true);
369 if(rc <= 0)
370 {
371 freeDirToWriteContents(&newTree);
372 bkClose(volInfo->imageForWriting);
373 unlink(newImagePathAndName);
374 return rc;
375 }
376
377 if(filenameTypes & FNTYPE_JOLIET)
378 {
379 wcSeekSet(volInfo, svdOffset);
380
381 printf("writing svd at %X\n", (int)wcSeekTell(volInfo));fflush(NULL);
382 rc = writeVolDescriptor(volInfo, sRealRootDrOffset,
383 sRootDirSize, lPathTableJolietLoc, mPathTableJolietLoc,
384 pathTableJolietSize, creationTime, false);
385 if(rc <= 0)
386 {
387 freeDirToWriteContents(&newTree);
388 bkClose(volInfo->imageForWriting);
389 unlink(newImagePathAndName);
390 return rc;
391 }
392 }
393
394 printf("freeing memory\n");fflush(NULL);
395 freeDirToWriteContents(&newTree);
396 bkClose(volInfo->imageForWriting);
397
398 return 1;
399 }
400
401 /******************************************************************************
402 * bootInfoTableChecksum()
403 * Calculate the checksum to be written into the boot info table.
404 * */
bootInfoTableChecksum(int oldImage,FileToWrite * file,unsigned * checksum)405 int bootInfoTableChecksum(int oldImage, FileToWrite* file, unsigned* checksum)
406 {
407 int numTrailingBytes; /* to make sure the file size is divisible by 4 */
408 ssize_t rc;
409 int srcFile;
410 unsigned char* contents;
411 unsigned count;
412
413 numTrailingBytes = file->size % 4;
414
415 contents = malloc(file->size + numTrailingBytes);
416 if(contents == NULL)
417 return BKERROR_OUT_OF_MEMORY;
418
419 /* make sure the extra bytes i added are 0s */
420 memset(contents + file->size, 0, numTrailingBytes);
421
422 if(file->onImage)
423 /* read file from original image */
424 {
425 bkSeekSet(oldImage, file->offset, SEEK_SET);
426
427 rc = bkRead(oldImage, contents, file->size);
428 if(rc == -1 || rc != (int)(file->size))
429 {
430 free(contents);
431 return BKERROR_READ_GENERIC;
432 }
433 }
434 else
435 /* read file from fs */
436 {
437 srcFile = open(file->pathAndName, O_RDONLY, 0);
438 if(srcFile == -1)
439 {
440 free(contents);
441 return BKERROR_OPEN_READ_FAILED;
442 }
443
444 rc = bkRead(srcFile, contents, file->size);
445
446 bkClose(srcFile);
447
448 if(rc == -1 || rc != (int)(file->size))
449 {
450 free(contents);
451 return BKERROR_READ_GENERIC;
452 }
453 }
454
455 *checksum = 0;
456 /* do 32 bit checksum starting from byte 64
457 * because i check above that the file is divisible by 4 i will not be
458 * reading wrong memory */
459 for(count = 64; count < file->size; count += 4)
460 {
461 unsigned toAdd;
462
463 toAdd = *(contents + count) | (*(contents + count + 1) << 8) |
464 (*(contents + count + 2) << 16) | (*(contents + count + 3) << 24);
465
466 *checksum += toAdd;
467 }
468
469 free(contents);
470
471 return 1;
472 }
473
474 /******************************************************************************
475 * countDirsOnLevel()
476 * a 'level' is described in ecma119 6.8.2
477 * it's needed for path tables, don't remember exactly what for
478 * */
countDirsOnLevel(const DirToWrite * dir,int targetLevel,int thisLevel)479 int countDirsOnLevel(const DirToWrite* dir, int targetLevel, int thisLevel)
480 {
481 BaseToWrite* child;
482 int sum;
483
484 if(targetLevel == thisLevel)
485 {
486 return 1;
487 }
488 else
489 {
490 sum = 0;
491
492 child = dir->children;
493 while(child != NULL)
494 {
495 if( IS_DIR(child->posixFileMode) )
496 sum += countDirsOnLevel(DIRTW_PTR(child), targetLevel, thisLevel + 1);
497
498 child = child->next;
499 }
500
501 return sum;
502 }
503 }
504
505 /******************************************************************************
506 * countTreeHeight()
507 * caller should set heightSoFar to 1
508 * */
countTreeHeight(const DirToWrite * dir,int heightSoFar)509 int countTreeHeight(const DirToWrite* dir, int heightSoFar)
510 {
511 BaseToWrite* child;
512 int maxHeight;
513 int thisHeight;
514
515 maxHeight = heightSoFar;
516 child = dir->children;
517 while(child != NULL)
518 {
519 if( IS_DIR(child->posixFileMode) )
520 {
521 thisHeight = countTreeHeight(DIRTW_PTR(child), heightSoFar + 1);
522
523 if(thisHeight > maxHeight)
524 maxHeight = thisHeight;
525 }
526
527 child = child->next;
528 }
529
530 return maxHeight;
531 }
532
533 /******************************************************************************
534 * elToritoChecksum()
535 * Algorithm: the sum of all words, including the checksum must trunkate to
536 * a 16-bit 0x0000
537 * */
elToritoChecksum(const unsigned char * record)538 unsigned short elToritoChecksum(const unsigned char* record)
539 {
540 short sum;
541 int i;
542
543 sum = 0;
544 for(i = 0; i < 32; i += 2)
545 {
546 sum += *(record + i) | (*(record + i + 1) << 8);
547 }
548
549 return 0xFFFF - sum + 1;
550 }
551
552 /******************************************************************************
553 * writeByteBlock()
554 * Fills numBytes with byteToWrite.
555
556 * */
writeByteBlock(VolInfo * volInfo,unsigned char byteToWrite,int numBytes)557 int writeByteBlock(VolInfo* volInfo, unsigned char byteToWrite, int numBytes)
558 {
559 int rc;
560 int count;
561 int numBlocks;
562 int sizeLastBlock;
563
564 memset(volInfo->readWriteBuffer, byteToWrite, READ_WRITE_BUFFER_SIZE);
565
566 numBlocks = numBytes / READ_WRITE_BUFFER_SIZE;
567 sizeLastBlock = numBytes % READ_WRITE_BUFFER_SIZE;
568
569 for(count = 0; count < numBlocks; count++)
570 {
571 rc = wcWrite(volInfo, volInfo->readWriteBuffer, READ_WRITE_BUFFER_SIZE);
572 if(rc <= 0)
573 return rc;
574 }
575
576 if(sizeLastBlock > 0)
577 {
578 rc = wcWrite(volInfo, volInfo->readWriteBuffer, sizeLastBlock);
579 if(rc <= 0)
580 return rc;
581 }
582
583 return 1;
584 }
585
586 /******************************************************************************
587 * writeByteBlockFromFile()
588 * copies numBytes from src into the image to write in blocks of 10K
589 * */
writeByteBlockFromFile(int src,VolInfo * volInfo,unsigned numBytes)590 int writeByteBlockFromFile(int src, VolInfo* volInfo, unsigned numBytes)
591 {
592 int rc;
593 int count;
594 int numBlocks;
595 int sizeLastBlock;
596
597 numBlocks = numBytes / READ_WRITE_BUFFER_SIZE;
598 sizeLastBlock = numBytes % READ_WRITE_BUFFER_SIZE;
599
600 for(count = 0; count < numBlocks; count++)
601 {
602 if(volInfo->stopOperation)
603 return BKERROR_OPER_CANCELED_BY_USER;
604
605 rc = bkRead(src, volInfo->readWriteBuffer, READ_WRITE_BUFFER_SIZE);
606 if(rc != READ_WRITE_BUFFER_SIZE)
607 return BKERROR_READ_GENERIC;
608 rc = wcWrite(volInfo, volInfo->readWriteBuffer, READ_WRITE_BUFFER_SIZE);
609 if(rc <= 0)
610 return rc;
611 }
612
613 if(sizeLastBlock > 0)
614 {
615 rc = bkRead(src, volInfo->readWriteBuffer, sizeLastBlock);
616 if(rc != sizeLastBlock)
617 return BKERROR_READ_GENERIC;
618 rc = wcWrite(volInfo, volInfo->readWriteBuffer, sizeLastBlock);
619 if(rc <= 0)
620 return rc;
621 }
622
623 return 1;
624 }
625
626 /******************************************************************************
627 * writeDir()
628 * Writes the contents of a directory. Also writes locations and sizes of
629 * directory records for directories but not for files.
630 * Returns data length of the dir written.
631 * */
writeDir(VolInfo * volInfo,DirToWrite * dir,int parentLbNum,int parentNumBytes,int parentPosix,time_t recordingTime,int filenameTypes,bool isRoot)632 int writeDir(VolInfo* volInfo, DirToWrite* dir, int parentLbNum,
633 int parentNumBytes, int parentPosix, time_t recordingTime,
634 int filenameTypes, bool isRoot)
635 {
636 int rc;
637
638 bk_off_t startPos;
639 int numUnusedBytes;
640 bk_off_t endPos;
641
642 DirToWrite selfDir; /* will have a different filename */
643 DirToWrite parentDir;
644
645 BaseToWrite* child;
646
647 if(wcSeekTell(volInfo) % NBYTES_LOGICAL_BLOCK != 0)
648 return BKERROR_SANITY;
649
650 /* names other then 9660 are not used for self and parent */
651 selfDir.base.name9660[0] = 0x00;
652 selfDir.base.posixFileMode = dir->base.posixFileMode;
653
654 parentDir.base.name9660[0] = 0x01;
655 parentDir.base.name9660[1] = '\0';
656 if(isRoot)
657 parentDir.base.posixFileMode = selfDir.base.posixFileMode;
658 else
659 parentDir.base.posixFileMode = parentPosix;
660
661 startPos = wcSeekTell(volInfo);
662
663 if( startPos % NBYTES_LOGICAL_BLOCK != 0 )
664 /* this should never happen */
665 return BKERROR_SANITY;
666
667 if(filenameTypes & FNTYPE_JOLIET)
668 dir->extentNumber2 = startPos / NBYTES_LOGICAL_BLOCK;
669 else
670 dir->base.extentNumber = startPos / NBYTES_LOGICAL_BLOCK;
671
672 /* write self */
673 if(isRoot)
674 {
675 rc = writeDr(volInfo, BASETW_PTR(&selfDir), recordingTime, true, true, true, filenameTypes);
676 if(rc < 0)
677 return rc;
678
679 if(filenameTypes & FNTYPE_JOLIET)
680 dir->base.extentLocationOffset2 = selfDir.base.extentLocationOffset2;
681 else
682 dir->base.extentLocationOffset = selfDir.base.extentLocationOffset;
683 }
684 else
685 {
686 rc = writeDr(volInfo, BASETW_PTR(&selfDir), recordingTime, true, true, false, filenameTypes);
687 if(rc < 0)
688 return rc;
689 }
690 if(rc < 0)
691 return rc;
692
693 /* write parent */
694 rc = writeDr(volInfo, BASETW_PTR(&parentDir), recordingTime, true, true, false, filenameTypes);
695 if(rc < 0)
696 return rc;
697
698 child = dir->children;
699
700 /* WRITE children drs */
701 while(child != NULL)
702 {
703 if(IS_DIR(child->posixFileMode))
704 {
705 rc = writeDr(volInfo, child, recordingTime,
706 true, false, false, filenameTypes);
707 }
708 else
709 {
710 rc = writeDr(volInfo, child, recordingTime,
711 false, false, false, filenameTypes);
712 }
713 if(rc < 0)
714 return rc;
715
716 child = child->next;
717 }
718 /* END WRITE children drs */
719
720 /* write blank to conclude extent */
721 numUnusedBytes = NBYTES_LOGICAL_BLOCK -
722 wcSeekTell(volInfo) % NBYTES_LOGICAL_BLOCK;
723 rc = writeByteBlock(volInfo, 0x00, numUnusedBytes);
724 if(rc < 0)
725 return rc;
726
727 if(filenameTypes & FNTYPE_JOLIET)
728 dir->dataLength2 = wcSeekTell(volInfo) - startPos;
729 else
730 dir->dataLength = wcSeekTell(volInfo) - startPos;
731
732 /* write subdirectories */
733 child = dir->children;
734 while(child != NULL)
735 {
736 if(IS_DIR(child->posixFileMode))
737 {
738 if(filenameTypes & FNTYPE_JOLIET)
739 {
740 rc = writeDir(volInfo, DIRTW_PTR(child), dir->extentNumber2,
741 dir->dataLength2, BASETW_PTR(dir)->posixFileMode, recordingTime,
742 filenameTypes, false);
743 }
744 else
745 {
746 rc = writeDir(volInfo, DIRTW_PTR(child), BASETW_PTR(dir)->extentNumber,
747 dir->dataLength, BASETW_PTR(dir)->posixFileMode, recordingTime,
748 filenameTypes, false);
749 }
750 if(rc < 0)
751 return rc;
752 }
753
754 child = child->next;
755 }
756
757 endPos = wcSeekTell(volInfo);
758
759 /* SELF extent location and size */
760 if(filenameTypes & FNTYPE_JOLIET)
761 wcSeekSet(volInfo, selfDir.base.extentLocationOffset2);
762 else
763 wcSeekSet(volInfo, selfDir.base.extentLocationOffset);
764
765 if(filenameTypes & FNTYPE_JOLIET)
766 {
767 rc = write733(volInfo, dir->extentNumber2);
768 if(rc <= 0)
769 return rc;
770
771 rc = write733(volInfo, dir->dataLength2);
772 if(rc <= 0)
773 return rc;
774 }
775 else
776 {
777 rc = write733(volInfo, BASETW_PTR(dir)->extentNumber);
778 if(rc <= 0)
779 return rc;
780
781 rc = write733(volInfo, dir->dataLength);
782 if(rc <= 0)
783 return rc;
784 }
785 /* END SELF extent location and size */
786
787 /* PARENT extent location and size */
788 if(filenameTypes & FNTYPE_JOLIET)
789 wcSeekSet(volInfo, parentDir.base.extentLocationOffset2);
790 else
791 wcSeekSet(volInfo, parentDir.base.extentLocationOffset);
792
793 if(parentLbNum == 0)
794 /* root, parent is same as self */
795 {
796 if(filenameTypes & FNTYPE_JOLIET)
797 {
798 rc = write733(volInfo, dir->extentNumber2);
799 if(rc <= 0)
800 return rc;
801
802 rc = write733(volInfo, dir->dataLength2);
803 if(rc <= 0)
804 return rc;
805 }
806 else
807 {
808 rc = write733(volInfo, BASETW_PTR(dir)->extentNumber);
809 if(rc <= 0)
810 return rc;
811
812 rc = write733(volInfo, dir->dataLength);
813 if(rc <= 0)
814 return rc;
815 }
816 }
817 else
818 /* normal parent */
819 {
820 rc = write733(volInfo, parentLbNum);
821 if(rc <= 0)
822 return rc;
823
824 rc = write733(volInfo, parentNumBytes);
825 if(rc <= 0)
826 return rc;
827 }
828 /* END PARENT extent location and size */
829
830 /* ALL subdir extent locations and sizes */
831 child = dir->children;
832 while(child != NULL)
833 {
834 if(IS_DIR(child->posixFileMode))
835 {
836 if(filenameTypes & FNTYPE_JOLIET)
837 {
838 wcSeekSet(volInfo, child->extentLocationOffset2);
839
840 rc = write733(volInfo, DIRTW_PTR(child)->extentNumber2);
841 if(rc <= 0)
842 return rc;
843
844 rc = write733(volInfo, DIRTW_PTR(child)->dataLength2);
845 if(rc <= 0)
846 return rc;
847 }
848 else
849 {
850 wcSeekSet(volInfo, child->extentLocationOffset);
851
852 rc = write733(volInfo, child->extentNumber);
853 if(rc <= 0)
854 return rc;
855
856 rc = write733(volInfo, DIRTW_PTR(child)->dataLength);
857 if(rc <= 0)
858 return rc;
859 }
860 }
861
862 child = child->next;
863 }
864 /* END ALL subdir extent locations and sizes */
865
866 wcSeekSet(volInfo, endPos);
867
868 if(filenameTypes & FNTYPE_JOLIET)
869 return dir->dataLength2;
870 else
871 return dir->dataLength;
872 }
873
874 /******************************************************************************
875 * writeDr()
876 * Writes a directory record.
877 * Note that it uses only the members of DirToWrite and FileToWrite that are
878 * the same.
879 * */
writeDr(VolInfo * volInfo,BaseToWrite * node,time_t recordingTime,bool isADir,bool isSelfOrParent,bool isFirstRecord,int filenameTypes)880 int writeDr(VolInfo* volInfo, BaseToWrite* node, time_t recordingTime, bool isADir,
881 bool isSelfOrParent, bool isFirstRecord, int filenameTypes)
882 {
883 int rc;
884 unsigned char byte;
885 char aString[256];
886 unsigned short aShort;
887 bk_off_t startPos;
888 bk_off_t endPos;
889 unsigned char lenFileId;
890 unsigned char recordLen;
891
892 /* look at the end of the function for an explanation */
893 writeDrStartLabel:
894
895 startPos = wcSeekTell(volInfo);
896
897 /* record length is recorded in the end */
898 wcSeekForward(volInfo, 1);
899
900 /* extended attribute record length */
901 byte = 0;
902 rc = write711(volInfo, byte);
903 if(rc <= 0)
904 return rc;
905
906 if(filenameTypes & FNTYPE_JOLIET)
907 node->extentLocationOffset2 = wcSeekTell(volInfo);
908 else
909 node->extentLocationOffset = wcSeekTell(volInfo);
910
911 /* location of extent not recorded in this function */
912 wcSeekForward(volInfo, 8);
913
914 /* data length not recorded in this function */
915 wcSeekForward(volInfo, 8);
916
917 /* RECORDING time and date */
918 epochToShortString(recordingTime, aString);
919
920 rc = write711(volInfo, aString[0]);
921 if(rc <= 0)
922 return rc;
923 rc = write711(volInfo, aString[1]);
924 if(rc <= 0)
925 return rc;
926 rc = write711(volInfo, aString[2]);
927 if(rc <= 0)
928 return rc;
929 rc = write711(volInfo, aString[3]);
930 if(rc <= 0)
931 return rc;
932 rc = write711(volInfo, aString[4]);
933 if(rc <= 0)
934 return rc;
935 rc = write711(volInfo, aString[5]);
936 if(rc <= 0)
937 return rc;
938 rc = write711(volInfo, aString[6]);
939 if(rc <= 0)
940 return rc;
941 /* END RECORDING time and date */
942
943 /* FILE flags */
944 if(isADir)
945 /* (only directory bit on) */
946 byte = 0x02;
947 else
948 /* nothing on */
949 byte = 0x00;
950
951 rc = wcWrite(volInfo, (char*)&byte, 1);
952 if(rc <= 0)
953 return rc;
954 /* END FILE flags */
955
956 /* file unit size (always 0, non-interleaved mode) */
957 byte = 0;
958 rc = write711(volInfo, byte);
959 if(rc <= 0)
960 return rc;
961
962 /* interleave gap size (also always 0, non-interleaved mode) */
963 rc = write711(volInfo, byte);
964 if(rc <= 0)
965 return rc;
966
967 /* volume sequence number (always 1) */
968 aShort = 1;
969 rc = write723(volInfo, aShort);
970 if(rc <= 0)
971 return rc;
972
973 /* LENGTH of file identifier */
974 if(isSelfOrParent)
975 lenFileId = 1;
976 else
977 {
978 if(filenameTypes & FNTYPE_JOLIET)
979 lenFileId = 2 * strlen(node->nameJoliet);
980 else
981 /*if(isADir) see microsoft comment below */
982 lenFileId = strlen(node->name9660);
983 /*else
984 lenFileId = strlen(node->name9660) + 2; */
985 }
986
987 rc = write711(volInfo, lenFileId);
988 if(rc <= 0)
989 return rc;
990 /* END LENGTH of file identifier */
991
992 /* FILE identifier */
993 if(isSelfOrParent)
994 {
995 /* that byte has 0x00 or 0x01 */
996 rc = write711(volInfo, node->name9660[0]);
997 if(rc <= 0)
998 return rc;
999 }
1000 else
1001 {
1002 if(filenameTypes & FNTYPE_JOLIET)
1003 {
1004 rc = writeJolietStringField(volInfo, node->nameJoliet,
1005 2 * strlen(node->nameJoliet));
1006 if(rc < 0)
1007 return rc;
1008 }
1009 else
1010 {
1011 /* ISO9660 requires ";1" after the filename (not directory name)
1012 * but the windows NT/2K boot loaders cannot find NTLDR inside
1013 * the I386 directory because they are looking for "NTLDR" not
1014 * "NTLDR;1". i guess if microsoft can do it, i can do it. filenames
1015 * on images written by me do not end with ";1"
1016 if(isADir)
1017 {*/
1018 /* the name */
1019 rc = wcWrite(volInfo, node->name9660, lenFileId);
1020 if(rc <= 0)
1021 return rc;
1022 /*}
1023 else
1024 {
1025 rc = writeWrapper(image, node->name9660, lenFileId - 2);
1026 if(rc <= 0)
1027 return rc;
1028
1029 rc = writeWrapper(image, ";1", 2);
1030 if(rc <= 0)
1031 return rc;
1032 }*/
1033 }
1034 }
1035 /* END FILE identifier */
1036
1037 /* padding field */
1038 if(lenFileId % 2 == 0)
1039 {
1040 byte = 0;
1041 rc = write711(volInfo, byte);
1042 if(rc <= 0)
1043 return rc;
1044 }
1045
1046 if(filenameTypes & FNTYPE_ROCKRIDGE)
1047 {
1048 if(isFirstRecord)
1049 {
1050 rc = writeRockSP(volInfo);
1051 if(rc < 0)
1052 return rc;
1053
1054 rc = writeRockER(volInfo);
1055 if(rc < 0)
1056 return rc;
1057 }
1058
1059 rc = writeRockPX(volInfo, node->posixFileMode, isADir);
1060 if(rc < 0)
1061 return rc;
1062
1063 if(!isSelfOrParent)
1064 {
1065 if(wcSeekTell(volInfo) - startPos < (int)strlen(node->nameRock) + 5)
1066 /* have no room for the NM entry in this directory record */
1067 {
1068 node->offsetForCE = wcSeekTell(volInfo);
1069 /* leave room for CE entry */
1070 wcSeekForward(volInfo, 28);
1071 }
1072 else
1073 {
1074 rc = writeRockNM(volInfo, node->nameRock, strlen(node->nameRock), false);
1075 if(rc < 0)
1076 return rc;
1077 }
1078
1079 if(IS_SYMLINK(node->posixFileMode))
1080 {
1081 rc = writeRockSL(volInfo, SYMLINKTW_PTR(node), true);
1082 if(rc < 0)
1083 return rc;
1084 }
1085 }
1086 }
1087
1088 /* RECORD length */
1089 endPos = wcSeekTell(volInfo);
1090
1091 wcSeekSet(volInfo, startPos);
1092
1093 recordLen = endPos - startPos;
1094 rc = write711(volInfo, recordLen);
1095 if(rc <= 0)
1096 return rc;
1097
1098 wcSeekSet(volInfo, endPos);
1099 /* END RECORD length */
1100
1101 /* the goto is good! really!
1102 * if, after writing the record we see that the record is in two logical
1103 * sectors (that's not allowed by iso9660) we erase the record just
1104 * written, write zeroes to the end of the first logical sector
1105 * (as required by iso9660) and restart the function, which will write
1106 * the same record again but at the beginning of the next logical sector
1107 * yeah, so don't complain :) */
1108
1109 if(endPos / NBYTES_LOGICAL_BLOCK > startPos / NBYTES_LOGICAL_BLOCK)
1110 /* crossed a logical sector boundary while writing the record */
1111 {
1112 wcSeekSet(volInfo, startPos);
1113
1114 /* overwrite a piece of the record written in this function
1115 * (the piece that's in the first sector) with zeroes */
1116 rc = writeByteBlock(volInfo, 0x00, recordLen - endPos % NBYTES_LOGICAL_BLOCK);
1117 if(rc < 0)
1118 return rc;
1119
1120 goto writeDrStartLabel;
1121 }
1122
1123 return 1;
1124 }
1125
1126 /******************************************************************************
1127 * writeElToritoBootCatalog()
1128 * Write the el torito boot catalog (validation entry and inital/default entry).
1129 * Returns the offset where the boot record sector number should
1130 * be written (7.3.1).
1131 * */
writeElToritoBootCatalog(VolInfo * volInfo,bk_off_t * bootRecordSectorNumberOffset)1132 int writeElToritoBootCatalog(VolInfo* volInfo,
1133 bk_off_t* bootRecordSectorNumberOffset)
1134 {
1135 unsigned char buffer[NBYTES_LOGICAL_BLOCK];
1136 int rc;
1137
1138 memset(buffer, 0, NBYTES_LOGICAL_BLOCK);
1139
1140 if(wcSeekTell(volInfo) % NBYTES_LOGICAL_BLOCK != 0)
1141 /* file pointer not at sector boundary */
1142 return BKERROR_SANITY;
1143
1144 /* SETUP VALIDATION entry (first 20 bytes of boot catalog) */
1145 /* header, must be 1 */
1146 buffer[0] = 1;
1147 /* platform id, 0 for x86 (bzero at start took care of this) */
1148 /* 2 bytes reserved, must be 0 (bzero at start took care of this) */
1149 /* 24 bytes id string for manufacturer/developer of cdrom */
1150 strncpy((char*)&(buffer[4]), "Edited with ISO Master", 22);
1151 /* key byte 0x55 */
1152 buffer[30] = 0x55;
1153 /* key byte 0xAA */
1154 buffer[31] = 0xAA;
1155
1156 /* checksum */
1157 write721ToByteArray(&(buffer[28]), elToritoChecksum(buffer));
1158 /* END SETUP VALIDATION validation entry (first 20 bytes of boot catalog) */
1159
1160 /* SETUP INITIAL entry (next 20 bytes of boot catalog) */
1161 /* boot indicator. 0x88 = bootable */
1162 buffer[32] = 0x88;
1163 /* boot media type */
1164 if(volInfo->bootMediaType == BOOT_MEDIA_NO_EMULATION)
1165 buffer[33] = 0;
1166 else if(volInfo->bootMediaType == BOOT_MEDIA_1_2_FLOPPY)
1167 buffer[33] = 1;
1168 else if(volInfo->bootMediaType == BOOT_MEDIA_1_44_FLOPPY)
1169 buffer[33] = 2;
1170 else if(volInfo->bootMediaType == BOOT_MEDIA_2_88_FLOPPY)
1171 buffer[33] = 3;
1172 else if(volInfo->bootMediaType == BOOT_MEDIA_HARD_DISK)
1173 buffer[33] = 4;
1174 /* load segment leave it at 0 */
1175 /* system type, leave it at 0 */
1176 /* 1 byte unused, leave it at 0 */
1177 /* sector count */
1178 write721ToByteArray(&(buffer[38]), volInfo->bootRecordSize / NBYTES_VIRTUAL_SECTOR);
1179 /* logical block number of boot record file. this is not known until
1180 * after that file is written */
1181 *bootRecordSectorNumberOffset = wcSeekTell(volInfo) + 40;
1182 /* the rest is unused, leave it at 0 */
1183 /* END SETUP INITIAL entry (next 20 bytes of boot catalog) */
1184
1185 rc = wcWrite(volInfo, (char*)buffer, NBYTES_LOGICAL_BLOCK);
1186 if(rc <= 0)
1187 return rc;
1188
1189 return 1;
1190 }
1191
1192 /******************************************************************************
1193 * writeElToritoVd()
1194 * Write the el torito volume descriptor.
1195 * Returns the offset where the boot catalog sector number should
1196 * be written (7.3.1).
1197 * */
writeElToritoVd(VolInfo * volInfo,bk_off_t * bootCatalogSectorNumberOffset)1198 int writeElToritoVd(VolInfo* volInfo, bk_off_t* bootCatalogSectorNumberOffset)
1199 {
1200 char buffer[NBYTES_LOGICAL_BLOCK];
1201 int rc;
1202
1203 memset(buffer, 0, NBYTES_LOGICAL_BLOCK);
1204
1205 if(wcSeekTell(volInfo) % NBYTES_LOGICAL_BLOCK != 0)
1206 /* file pointer not at sector boundary */
1207 return BKERROR_SANITY;
1208
1209 /* SETUP BOOT record volume descriptor sector */
1210 /* boot record indicator, must be 0 (bzero at start took care of this) */
1211 /* iso9660 identifier, must be "CD001" */
1212 strncpy((char*)buffer + 1, "CD001", 5);
1213 /* version, must be 1 */
1214 buffer[6] = 1;
1215 /* boot system identifier, must be 32 bytes "EL TORITO SPECIFICATION"
1216 * padded with 0x00 (bzero at start took care of this) */
1217 strncpy(&(buffer[7]), "EL TORITO SPECIFICATION", 23);
1218 /* unused 32 bytes, must be 0 (bzero at start took care of this) */
1219 /* boot catalog location, 4 byte intel format. written later. */
1220 *bootCatalogSectorNumberOffset = wcSeekTell(volInfo) + 71;
1221 /*write731ToByteArray(&(buffer[71]), bootCatalogSectorNumber);*/
1222 /* the rest of this sector is unused, must be set to 0 */
1223 /* END SETUP BOOT record volume descriptor sector */
1224
1225 rc = wcWrite(volInfo, buffer, NBYTES_LOGICAL_BLOCK);
1226 if(rc <= 0)
1227 return rc;
1228
1229 return 1;
1230 }
1231
1232 /******************************************************************************
1233 * writeFileContents()
1234 * Write file contents into an extent and also write the file's location and
1235 * size into the directory records back in the tree.
1236 * Also write location and size for symbolic links.
1237 * */
writeFileContents(VolInfo * volInfo,DirToWrite * dir,int filenameTypes)1238 int writeFileContents(VolInfo* volInfo, DirToWrite* dir, int filenameTypes)
1239 {
1240 int rc;
1241
1242 BaseToWrite* child;
1243 int numUnusedBytes;
1244 int srcFile;
1245 bk_off_t endPos;
1246
1247 child = dir->children;
1248 while(child != NULL)
1249 /* each file in current directory */
1250 {
1251 if(volInfo->stopOperation)
1252 return BKERROR_OPER_CANCELED_BY_USER;
1253
1254 if(wcSeekTell(volInfo) % NBYTES_LOGICAL_BLOCK != 0)
1255 return BKERROR_SANITY;
1256
1257 if( IS_REG_FILE(child->posixFileMode) )
1258 {
1259 bool needToCopy = true;
1260
1261 child->extentNumber = wcSeekTell(volInfo) / NBYTES_LOGICAL_BLOCK;
1262 if(volInfo->scanForDuplicateFiles)
1263 {
1264 if(FILETW_PTR(child)->location->extentNumberWrittenTo == 0)
1265 /* file not yet written */
1266 {
1267 FILETW_PTR(child)->location->extentNumberWrittenTo = child->extentNumber;
1268 }
1269 else
1270 {
1271 child->extentNumber = FILETW_PTR(child)->location->extentNumberWrittenTo;
1272 needToCopy = false;
1273 }
1274 }
1275
1276 if(volInfo->bootMediaType != BOOT_MEDIA_NONE &&
1277 volInfo->bootRecordIsVisible &&
1278 FILETW_PTR(child)->origFile == volInfo->bootRecordOnImage)
1279 /* this file is the boot record. write its sector number in
1280 * the boot catalog */
1281 {
1282 bk_off_t currPos;
1283
1284 currPos = wcSeekTell(volInfo);
1285
1286 wcSeekSet(volInfo, volInfo->bootRecordSectorNumberOffset);
1287 rc = write731(volInfo, child->extentNumber);
1288 if(rc <= 0)
1289 return rc;
1290
1291 wcSeekSet(volInfo, currPos);
1292 }
1293
1294 if(needToCopy)
1295 {
1296 if(FILETW_PTR(child)->onImage)
1297 /* copy file from original image to new one */
1298 {
1299 readSeekSet(volInfo, FILETW_PTR(child)->offset,
1300 SEEK_SET);
1301
1302 rc = writeByteBlockFromFile(volInfo->imageForReading,
1303 volInfo, FILETW_PTR(child)->size);
1304 if(rc < 0)
1305 return rc;
1306 }
1307 else
1308 /* copy file from fs to new image */
1309 {
1310 /* UPDATE the file's size, in case it's changed since we added it */
1311 BkStatStruct statStruct;
1312
1313 rc = bkStat(FILETW_PTR(child)->pathAndName, &statStruct);
1314 if(rc != 0)
1315 return BKERROR_STAT_FAILED;
1316
1317 if(statStruct.st_size > 0xFFFFFFFF)
1318 /* size won't fit in a 32bit variable on the iso */
1319 return BKERROR_EDITED_WRITE_TOO_BIG;
1320
1321 FILETW_PTR(child)->size = statStruct.st_size;
1322 /* UPDATE the file's size, in case it's changed since we added it */
1323
1324 srcFile = open(FILETW_PTR(child)->pathAndName, O_RDONLY, 0);
1325 if(srcFile == -1)
1326 return BKERROR_OPEN_READ_FAILED;
1327
1328 rc = writeByteBlockFromFile(srcFile,
1329 volInfo, FILETW_PTR(child)->size);
1330
1331 bkClose(srcFile);
1332
1333 if(rc < 0)
1334 return rc;
1335 }
1336
1337 /* fill extent with zeroes */
1338 numUnusedBytes = NBYTES_LOGICAL_BLOCK -
1339 wcSeekTell(volInfo) % NBYTES_LOGICAL_BLOCK;
1340 rc = writeByteBlock(volInfo, 0x00, numUnusedBytes);
1341 if(rc < 0)
1342 return rc;
1343 }
1344
1345 endPos = wcSeekTell(volInfo);
1346
1347 bool isIsolinux;
1348 rc = wroteIsolinuxBootRecord(volInfo, FILETW_PTR(child), &isIsolinux);
1349 if(rc < 0)
1350 return rc;
1351
1352 if(isIsolinux)
1353 /* write the boot info table for the isolinux boot record */
1354 {
1355 unsigned char bootInfoTable[56];
1356 unsigned checksum;
1357
1358 memset(bootInfoTable, 0, 56);
1359
1360 /* go to the offset in the file where the boot info table is */
1361 wcSeekSet(volInfo, child->extentNumber *
1362 NBYTES_LOGICAL_BLOCK + 8);
1363
1364 /* sector number of pvd */
1365 write731ToByteArray(bootInfoTable, 16);
1366 /* sector number of boot file (this one) */
1367 write731ToByteArray(bootInfoTable + 4, child->extentNumber);
1368 /* boot file length in bytes */
1369 write731ToByteArray(bootInfoTable + 8, FILETW_PTR(child)->size);
1370 /* 32 bit checksum (the sum of all the 32-bit words in the boot
1371 * file starting at byte offset 64 */
1372 rc = bootInfoTableChecksum(volInfo->imageForReading, FILETW_PTR(child), &checksum);
1373 if(rc <= 0)
1374 return rc;
1375 write731ToByteArray(bootInfoTable + 12, checksum);
1376 /* the rest is reserved, leave at zero */
1377
1378 rc = wcWrite(volInfo, (char*)bootInfoTable, 56);
1379 if(rc <= 0)
1380 return rc;
1381 }
1382
1383 /* WRITE file location and size */
1384 wcSeekSet(volInfo, child->extentLocationOffset);
1385
1386 rc = write733(volInfo, child->extentNumber);
1387 if(rc <= 0)
1388 return rc;
1389
1390 rc = write733(volInfo, FILETW_PTR(child)->size);
1391 if(rc <= 0)
1392 return rc;
1393
1394 if(filenameTypes & FNTYPE_JOLIET)
1395 /* also update location and size on joliet tree */
1396 {
1397 wcSeekSet(volInfo, child->extentLocationOffset2);
1398
1399 rc = write733(volInfo, child->extentNumber);
1400 if(rc <= 0)
1401 return rc;
1402
1403 rc = write733(volInfo, FILETW_PTR(child)->size);
1404 if(rc <= 0)
1405 return rc;
1406 }
1407
1408 wcSeekSet(volInfo, endPos);
1409 /* END WRITE file location and size */
1410 }
1411 else if( IS_DIR(child->posixFileMode) )
1412 {
1413 rc = writeFileContents(volInfo, DIRTW_PTR(child), filenameTypes);
1414 if(rc < 0)
1415 return rc;
1416 }
1417 else if( IS_SYMLINK(child->posixFileMode) )
1418 {
1419 /* WRITE symlink location and size (0) */
1420 endPos = wcSeekTell(volInfo);
1421
1422 wcSeekSet(volInfo, child->extentLocationOffset);
1423
1424 rc = write733(volInfo, 0);
1425 if(rc <= 0)
1426 return rc;
1427
1428 rc = write733(volInfo, 0);
1429 if(rc <= 0)
1430 return rc;
1431
1432 if(filenameTypes & FNTYPE_JOLIET)
1433 /* also update location and size on joliet tree */
1434 {
1435 wcSeekSet(volInfo, child->extentLocationOffset2);
1436
1437 rc = write733(volInfo, 0);
1438 if(rc <= 0)
1439 return rc;
1440
1441 rc = write733(volInfo, 0);
1442 if(rc <= 0)
1443 return rc;
1444 }
1445
1446 wcSeekSet(volInfo, endPos);
1447 /* END WRITE symlink location and size (0) */
1448 }
1449
1450 child = child->next;
1451
1452 } /* while(nextFile != NULL) */
1453
1454 return 1;
1455 }
1456
1457 /* field size must be even. !!check all calls to make sure */
writeJolietStringField(VolInfo * volInfo,const char * name,size_t fieldSize)1458 int writeJolietStringField(VolInfo* volInfo, const char* name, size_t fieldSize)
1459 {
1460 char jolietName[512]; /* don't see why would ever want
1461 * to write a longer one */
1462 int srcCount;
1463 size_t destCount;
1464 int rc;
1465
1466 srcCount = 0;
1467 destCount = 0;
1468 while(name[srcCount] != '\0' && destCount < fieldSize)
1469 {
1470 /* first byte zero */
1471 jolietName[destCount] = 0x00;
1472 /* second byte character */
1473 jolietName[destCount + 1] = name[srcCount];
1474
1475 srcCount += 1;
1476 destCount += 2;
1477 }
1478
1479 while(destCount < fieldSize)
1480 /* pad with ucs2 spaces */
1481 {
1482 jolietName[destCount] = 0x00;
1483 jolietName[destCount + 1] = ' ';
1484
1485 destCount += 2;
1486 }
1487
1488 rc = wcWrite(volInfo, jolietName, destCount);
1489 if(rc <= 0)
1490 return rc;
1491
1492 return 1;
1493 }
1494
1495 /* write NM that won't fit in a directory record */
writeLongNM(VolInfo * volInfo,BaseToWrite * node)1496 int writeLongNM(VolInfo* volInfo, BaseToWrite* node)
1497 {
1498 bk_off_t startPos;
1499 size_t fullNameLen;
1500 unsigned char CErecord[28];
1501 bool fitsInOneNM;
1502 size_t firstNMlen;
1503 bk_off_t endPos;
1504 int rc;
1505 int lenOfCE;
1506
1507 startPos = wcSeekTell(volInfo);
1508
1509 fullNameLen = strlen(node->nameRock);
1510
1511 /* should have checked for this before getting into this function */
1512 if(fullNameLen > 255)
1513 return BKERROR_SANITY;
1514
1515 if(fullNameLen > 250)
1516 {
1517 fitsInOneNM = false;
1518 firstNMlen = 250;
1519 }
1520 else
1521 {
1522 fitsInOneNM = true;
1523 firstNMlen = fullNameLen;
1524 }
1525
1526 /* NM record(s) */
1527 if(fitsInOneNM)
1528 {
1529 rc = writeRockNM(volInfo, node->nameRock, firstNMlen, false);
1530 if(rc <= 0)
1531 return rc;
1532 }
1533 else
1534 {
1535 rc = writeRockNM(volInfo, node->nameRock, firstNMlen, true);
1536 if(rc <= 0)
1537 return rc;
1538 rc = writeRockNM(volInfo, node->nameRock + firstNMlen, fullNameLen - firstNMlen, false);
1539 if(rc <= 0)
1540 return rc;
1541 }
1542
1543 lenOfCE = wcSeekTell(volInfo) - startPos;
1544
1545 /* write blank to conclude extent */
1546 rc = writeByteBlock(volInfo, 0x00, NBYTES_LOGICAL_BLOCK -
1547 wcSeekTell(volInfo) % NBYTES_LOGICAL_BLOCK);
1548 if(rc < 0)
1549 return rc;
1550
1551 endPos = wcSeekTell(volInfo);
1552
1553 /* CE record back in the directory record */
1554 wcSeekSet(volInfo, node->offsetForCE);
1555
1556 CErecord[0] = 'C';
1557 CErecord[1] = 'E';
1558 CErecord[2] = 28; /* length */
1559 CErecord[3] = 1; /* version */
1560 write733ToByteArray(CErecord + 4, startPos / NBYTES_LOGICAL_BLOCK); /* block location */
1561 /* i'm always using 1 logical block per name */
1562 write733ToByteArray(CErecord + 12, 0); /* offset to start */
1563 write733ToByteArray(CErecord + 20, lenOfCE); /* length */
1564
1565 rc = wcWrite(volInfo, (char*)CErecord, CErecord[2]);
1566 if(rc <= 0)
1567 return rc;
1568 /* END CE record back in the directory record */
1569
1570 wcSeekSet(volInfo, endPos);
1571
1572 return 1;
1573 }
1574
1575 /* write all NMs in the tree that won't fit in directory records */
writeLongNMsInDir(VolInfo * volInfo,DirToWrite * dir)1576 int writeLongNMsInDir(VolInfo* volInfo, DirToWrite* dir)
1577 {
1578 BaseToWrite* child;
1579 int rc;
1580
1581 child = dir->children;
1582 while(child != NULL)
1583 {
1584 if(child->offsetForCE != 0)
1585 {
1586 rc = writeLongNM(volInfo, child);
1587 if(rc <= 0)
1588 return rc;
1589 }
1590
1591 if( IS_DIR(child->posixFileMode) )
1592 {
1593 rc = writeLongNMsInDir(volInfo, DIRTW_PTR(child));
1594 if(rc <= 0)
1595 return rc;
1596 }
1597
1598 child = child->next;
1599 }
1600
1601 return 1;
1602 }
1603
1604 /* returns path table size (number of bytes not counting the blank) */
writePathTable(VolInfo * volInfo,const DirToWrite * tree,bool isTypeL,int filenameType)1605 int writePathTable(VolInfo* volInfo, const DirToWrite* tree, bool isTypeL,
1606 int filenameType)
1607 {
1608 int treeHeight;
1609 int count;
1610 int level;
1611 int* dirsPerLevel; /* a dynamic array of the number of dirs per level */
1612 int numDirsSoFar;
1613 bk_off_t origPos;
1614 int numBytesWritten;
1615 int rc;
1616
1617 origPos = wcSeekTell(volInfo);
1618
1619 if(origPos % NBYTES_LOGICAL_BLOCK != 0)
1620 return BKERROR_SANITY;
1621
1622 treeHeight = countTreeHeight(tree, 1);
1623
1624 dirsPerLevel = malloc(sizeof(int) * treeHeight);
1625 if(dirsPerLevel == NULL)
1626 return BKERROR_OUT_OF_MEMORY;
1627
1628 for(count = 0; count < treeHeight; count++)
1629 {
1630 dirsPerLevel[count] = countDirsOnLevel(tree, count + 1, 1);
1631 }
1632
1633 for(level = 1; level <= treeHeight; level++)
1634 {
1635 if(level == 1)
1636 /* numDirsSoFar = parent dir num */
1637 numDirsSoFar = 1;
1638 else if(level == 2)
1639 numDirsSoFar = 1;
1640 else
1641 {
1642 /* ex. when i am on level 4 i want number of dirs on levels 1 + 2 */
1643 numDirsSoFar = 0;
1644 for(count = 0; count < level - 2; count++)
1645 {
1646 numDirsSoFar += dirsPerLevel[count];
1647 }
1648 }
1649
1650 rc = writePathTableRecordsOnLevel(volInfo, tree, isTypeL, filenameType,
1651 level, 1, &numDirsSoFar);
1652 if(rc < 0)
1653 {
1654 free(dirsPerLevel);
1655 return rc;
1656 }
1657 }
1658
1659 numBytesWritten = wcSeekTell(volInfo) - origPos;
1660
1661 /* blank to conclude extent */
1662 rc = writeByteBlock(volInfo, 0x00, NBYTES_LOGICAL_BLOCK -
1663 numBytesWritten % NBYTES_LOGICAL_BLOCK);
1664 if(rc < 0)
1665 {
1666 free(dirsPerLevel);
1667 return rc;
1668 }
1669
1670 free(dirsPerLevel);
1671
1672 return numBytesWritten;
1673 }
1674
writePathTableRecordsOnLevel(VolInfo * volInfo,const DirToWrite * dir,bool isTypeL,int filenameType,int targetLevel,int thisLevel,int * parentDirNum)1675 int writePathTableRecordsOnLevel(VolInfo* volInfo, const DirToWrite* dir,
1676 bool isTypeL, int filenameType,
1677 int targetLevel, int thisLevel,
1678 int* parentDirNum)
1679 {
1680 int rc;
1681 BaseToWrite* child;
1682
1683 unsigned char fileIdLen;
1684 unsigned char byte;
1685 unsigned exentLocation;
1686 unsigned short parentDirId; /* copy of *parentDirNum */
1687 static const char rootId = 0x00;
1688
1689 if(thisLevel == targetLevel)
1690 /* write path table record */
1691 {
1692 /* LENGTH of directory identifier */
1693 if(targetLevel == 1)
1694 /* root */
1695 fileIdLen = 1;
1696 else
1697 {
1698 if(filenameType & FNTYPE_JOLIET)
1699 {
1700 fileIdLen = 2 * strlen(BASETW_PTR(dir)->nameJoliet);
1701 }
1702 else
1703 {
1704 fileIdLen = strlen(BASETW_PTR(dir)->name9660);
1705 }
1706 }
1707
1708 rc = write711(volInfo, fileIdLen);
1709 if(rc <= 0)
1710 return rc;
1711 /* END LENGTH of directory identifier */
1712
1713 /* extended attribute record length */
1714 byte = 0;
1715 rc = write711(volInfo, byte);
1716 if(rc <= 0)
1717 return rc;
1718
1719 /* LOCATION of extent */
1720 if(filenameType & FNTYPE_JOLIET)
1721 exentLocation = dir->extentNumber2;
1722 else
1723 exentLocation = BASETW_PTR(dir)->extentNumber;
1724
1725 if(isTypeL)
1726 rc = write731(volInfo, exentLocation);
1727 else
1728 rc = write732(volInfo, exentLocation);
1729 if(rc <= 0)
1730 return rc;
1731 /* END LOCATION of extent */
1732
1733 /* PARENT directory number */
1734 parentDirId = *parentDirNum;
1735
1736 if(isTypeL)
1737 rc = write721(volInfo, parentDirId);
1738 else
1739 rc = write722(volInfo, parentDirId);
1740
1741 if(rc <= 0)
1742 return rc;
1743 /* END PARENT directory number */
1744
1745 /* DIRECTORY identifier */
1746 if(targetLevel == 1)
1747 /* root */
1748 {
1749 rc = wcWrite(volInfo, &rootId, 1);
1750 if(rc <= 0)
1751 return rc;
1752 }
1753 else
1754 {
1755 if(filenameType & FNTYPE_JOLIET)
1756 {
1757 rc = writeJolietStringField(volInfo, BASETW_PTR(dir)->nameJoliet, fileIdLen);
1758 if(rc < 0)
1759 return rc;
1760 }
1761 else
1762 {
1763 rc = wcWrite(volInfo, BASETW_PTR(dir)->name9660, fileIdLen);
1764 if(rc <= 0)
1765 return rc;
1766 }
1767 }
1768 /* END DIRECTORY identifier */
1769
1770 /* padding field */
1771 if(fileIdLen % 2 != 0)
1772 {
1773 byte = 0;
1774 rc = write711(volInfo, byte);
1775 if(rc <= 0)
1776 return rc;
1777 }
1778
1779 }
1780 else /* if(thisLevel < targetLevel) */
1781 {
1782 child = dir->children;
1783 while(child != NULL)
1784 {
1785 if( IS_DIR(child->posixFileMode) )
1786 {
1787 if(thisLevel == targetLevel - 2)
1788 /* am now going throught the list of dirs where the parent is */
1789 {
1790 if(targetLevel != 2)
1791 /* first and second level have the same parent: 1 */
1792 {
1793 (*parentDirNum)++;
1794 }
1795 }
1796
1797 rc = writePathTableRecordsOnLevel(volInfo, DIRTW_PTR(child), isTypeL,
1798 filenameType, targetLevel,
1799 thisLevel + 1, parentDirNum);
1800 if(rc < 0)
1801 return rc;
1802 }
1803
1804 child = child->next;
1805 }
1806 }
1807
1808 return 1;
1809 }
1810
1811 /* This doesn't need support for CE because it's only written in one place,
1812 * the root 'self' directory record. */
writeRockER(VolInfo * volInfo)1813 int writeRockER(VolInfo* volInfo)
1814 {
1815 int rc;
1816 char record[46];
1817
1818 /* identification */
1819 record[0] = 'E';
1820 record[1] = 'R';
1821
1822 /* record length */
1823 record[2] = 46;
1824
1825 /* entry version */
1826 record[3] = 1;
1827
1828 /* extension identifier length */
1829 record[4] = 10;
1830
1831 /* extension descriptor length */
1832 record[5] = 10;
1833
1834 /* extension source length */
1835 record[6] = 18;
1836
1837 /* extension version */
1838 record[7] = 1;
1839
1840 /* extension identifier */
1841 strncpy(&(record[8]), "IEEE_P1282", 10);
1842
1843 /* extension descriptor */
1844 strncpy(&(record[18]), "DRAFT_1_12", 10);
1845
1846 /* extension source */
1847 strncpy(&(record[28]), "ADOPTED_1994_07_08", 18);
1848
1849 rc = wcWrite(volInfo, record, 46);
1850 if(rc <= 0)
1851 return rc;
1852
1853 return 1;
1854 }
1855
writeRockNM(VolInfo * volInfo,char * name,size_t nameLen,bool doesContinue)1856 int writeRockNM(VolInfo* volInfo, char* name, size_t nameLen, bool doesContinue)
1857 {
1858 int rc;
1859 char recordStart[5];
1860
1861 /* identification */
1862 recordStart[0] = 'N';
1863 recordStart[1] = 'M';
1864
1865 /* record length */
1866 recordStart[2] = 5 + nameLen;
1867
1868 /* entry version */
1869 recordStart[3] = 1;
1870
1871 /* flags */
1872 if(doesContinue)
1873 recordStart[4] = 0x01;
1874 else
1875 recordStart[4] = 0;
1876
1877 rc = wcWrite(volInfo, recordStart, 5);
1878 if(rc <= 0)
1879 return rc;
1880
1881 rc = wcWrite(volInfo, name, nameLen);
1882 if(rc <= 0)
1883 return rc;
1884
1885 return 1;
1886 }
1887
1888 /* the slackware cd has 36 byte PX entries, missing the file serial number
1889 * so i will do the same */
writeRockPX(VolInfo * volInfo,unsigned posixFileMode,bool isADir)1890 int writeRockPX(VolInfo* volInfo, unsigned posixFileMode, bool isADir)
1891 {
1892 int rc;
1893 unsigned char record[36];
1894 unsigned posixFileLinks;
1895
1896 /* identification */
1897 record[0] = 'P';
1898 record[1] = 'X';
1899
1900 /* record length */
1901 record[2] = 36;
1902
1903 /* entry version */
1904 record[3] = 1;
1905
1906 /* posix file mode */
1907 write733ToByteArray(&(record[4]), posixFileMode);
1908
1909 /* POSIX file links */
1910 /*
1911 * this i think is number of subdirectories + 2 (self and parent)
1912 * and 1 for a file
1913 * it's probably not used on read-only filesystems
1914 * to add it, i would need to pass the number of links in a parent dir
1915 * recursively in writeDir(). brrrrr.
1916 */
1917 if(isADir)
1918 posixFileLinks = 2;
1919 else
1920 posixFileLinks = 1;
1921
1922 write733ToByteArray(&(record[12]), posixFileLinks);
1923 /* END POSIX file links */
1924
1925 /* posix file user id, posix file group id */
1926 memset(&(record[20]), 0, 16);
1927
1928 rc = wcWrite(volInfo, (char*)record, 36);
1929 if(rc <= 0)
1930 return rc;
1931
1932 return 1;
1933 }
1934
writeRockSL(VolInfo * volInfo,SymLinkToWrite * symlink,bool doWrite)1935 int writeRockSL(VolInfo* volInfo, SymLinkToWrite* symlink, bool doWrite)
1936 {
1937 size_t stringCount;
1938 size_t targetLen;
1939 size_t numBytesNeeded;
1940 size_t numBytesToSkip;
1941 unsigned char* record;
1942 size_t recordCount;
1943 int rc;
1944
1945 targetLen = strlen(symlink->target);
1946
1947 /* figure out how much room i need */
1948 numBytesNeeded = 0;
1949 numBytesToSkip = 0;
1950 stringCount = 0;
1951 while(stringCount < targetLen)
1952 {
1953 char* nextSlash;
1954
1955 if(symlink->target[stringCount] == '/')
1956 /* root (/) */
1957 {
1958 numBytesNeeded += 2;
1959 numBytesToSkip = 1;
1960 }
1961 else if( symlink->target[stringCount] == '.' &&
1962 (stringCount + 1 == targetLen || symlink->target[stringCount + 1] == '/') )
1963 /* current (.) */
1964 {
1965 numBytesNeeded += 2;
1966 numBytesToSkip = 2;
1967 }
1968 else if( symlink->target[stringCount] == '.' &&
1969 stringCount + 1 < targetLen && symlink->target[stringCount + 1] == '.' )
1970 /* parent (..) */
1971 {
1972 numBytesNeeded += 2;
1973 numBytesToSkip = 3;
1974 }
1975 else
1976 /* regular filename */
1977 {
1978 nextSlash = strchr(symlink->target + stringCount, '/');
1979 if(nextSlash != NULL)
1980 numBytesToSkip = nextSlash - (symlink->target + stringCount);
1981 else
1982 numBytesToSkip = targetLen - stringCount;
1983
1984 numBytesNeeded += 2 + numBytesToSkip;
1985
1986 numBytesToSkip += 1;
1987 }
1988
1989 stringCount += numBytesToSkip;
1990 }
1991
1992 if(!doWrite)
1993 return (int)(5 + numBytesNeeded);
1994
1995 if(numBytesNeeded > NCHARS_SYMLINK_TARGET_MAX - 1)
1996 return BKERROR_SYMLINK_TARGET_TOO_LONG;
1997
1998 record = malloc(5 + numBytesNeeded);
1999 if(record == NULL)
2000 return BKERROR_OUT_OF_MEMORY;
2001
2002 record[0] = 'S';
2003 record[1] = 'L';
2004 record[2] = 5 + numBytesNeeded; /* length */
2005 record[3] = 1; /* version */
2006 record[4] = 0x00; /* flags */
2007
2008 /* write SL */
2009 numBytesToSkip = 0;
2010 stringCount = 0;
2011 recordCount = 5;
2012 while(stringCount < targetLen)
2013 {
2014 char* nextSlash;
2015
2016 if(symlink->target[stringCount] == '/')
2017 /* root (/) */
2018 {
2019 numBytesToSkip = 1;
2020 record[recordCount] = 0x08;
2021 record[recordCount + 1] = 0;
2022 recordCount += 2;
2023 }
2024 else if( symlink->target[stringCount] == '.' &&
2025 (stringCount + 1 == targetLen || symlink->target[stringCount + 1] == '/') )
2026 /* current (.) */
2027 {
2028 numBytesToSkip = 2;
2029 record[recordCount] = 0x02;
2030 record[recordCount + 1] = 0;
2031 recordCount += 2;
2032 }
2033 else if( symlink->target[stringCount] == '.' &&
2034 stringCount + 1 < targetLen && symlink->target[stringCount + 1] == '.' )
2035 /* parent (..) */
2036 {
2037 numBytesToSkip = 3;
2038 record[recordCount] = 0x04;
2039 record[recordCount + 1] = 0;
2040 recordCount += 2;
2041 }
2042 else
2043 /* regular filename */
2044 {
2045 nextSlash = strchr(symlink->target + stringCount, '/');
2046 if(nextSlash != NULL)
2047 numBytesToSkip = nextSlash - (symlink->target + stringCount);
2048 else
2049 numBytesToSkip = targetLen - stringCount;
2050
2051 record[recordCount] = 0x00;
2052 record[recordCount + 1] = numBytesToSkip;
2053 strncpy((char*)record + recordCount + 2, symlink->target + stringCount, numBytesToSkip);
2054 recordCount += 2 + numBytesToSkip;
2055
2056 numBytesToSkip += 1;
2057 }
2058
2059 /* + separator */
2060 stringCount += numBytesToSkip;
2061 }
2062
2063 if(recordCount != numBytesNeeded + 5)
2064 {
2065 free(record);
2066 return BKERROR_SANITY;
2067 }
2068
2069 rc = wcWrite(volInfo, (char*)record, recordCount);
2070 if(rc <= 0)
2071 {
2072 free(record);
2073 return rc;
2074 }
2075
2076 free(record);
2077
2078 return (int)(5 + numBytesNeeded);
2079 }
2080
2081 /* This doesn't need support for CE because it's only written in one place,
2082 * the root 'self' directory record. */
writeRockSP(VolInfo * volInfo)2083 int writeRockSP(VolInfo* volInfo)
2084 {
2085 int rc;
2086 unsigned char record[7];
2087
2088 /* identification */
2089 record[0] = 'S';
2090 record[1] = 'P';
2091
2092 /* record length */
2093 record[2] = 7;
2094
2095 /* entry version */
2096 record[3] = 1;
2097
2098 /* check bytes */
2099 record[4] = 0xBE;
2100 record[5] = 0xEF;
2101
2102 /* bytes skipped */
2103 record[6] = 0;
2104
2105 rc = wcWrite(volInfo, (char*)record, 7);
2106 if(rc <= 0)
2107 return rc;
2108
2109 return 1;
2110 }
2111
writeVdsetTerminator(VolInfo * volInfo)2112 int writeVdsetTerminator(VolInfo* volInfo)
2113 {
2114 int rc;
2115 unsigned char byte;
2116 unsigned char aString[6];
2117
2118 /* volume descriptor type */
2119 byte = 255;
2120 rc = write711(volInfo, byte);
2121 if(rc <= 0)
2122 return rc;
2123
2124 /* standard identifier */
2125 strcpy((char*)aString, "CD001");
2126 rc = wcWrite(volInfo, (char*)aString, 5);
2127 if(rc <= 0)
2128 return rc;
2129
2130 /* volume descriptor version */
2131 byte = 1;
2132 rc = write711(volInfo, byte);
2133 if(rc <= 0)
2134 return rc;
2135
2136 rc = writeByteBlock(volInfo, 0, 2041);
2137 if(rc < 0)
2138 return rc;
2139
2140 return 1;
2141 }
2142
2143 /*
2144 * -has to be called after the files were written so that the
2145 * volume size is recorded properly
2146 * -rootdr location, size are in bytes
2147 * -note strings are not terminated on image
2148 */
writeVolDescriptor(VolInfo * volInfo,bk_off_t rootDrLocation,unsigned rootDrSize,bk_off_t lPathTableLoc,bk_off_t mPathTableLoc,unsigned pathTableSize,time_t creationTime,bool isPrimary)2149 int writeVolDescriptor(VolInfo* volInfo, bk_off_t rootDrLocation,
2150 unsigned rootDrSize, bk_off_t lPathTableLoc,
2151 bk_off_t mPathTableLoc, unsigned pathTableSize,
2152 time_t creationTime, bool isPrimary)
2153 {
2154 int rc;
2155 size_t count;
2156
2157 unsigned char byte;
2158 unsigned char aString[129];
2159 unsigned anUnsigned;
2160 unsigned short anUnsignedShort;
2161 bk_off_t currPos;
2162
2163 /* VOLUME descriptor type */
2164 if(isPrimary)
2165 byte = 1;
2166 else
2167 byte = 2;
2168 /* END VOLUME descriptor type */
2169
2170 rc = write711(volInfo, byte);
2171 if(rc <= 0)
2172 return rc;
2173
2174 /* standard identifier */
2175 strcpy((char*)aString, "CD001");
2176 rc = wcWrite(volInfo, (char*)aString, 5);
2177 if(rc <= 0)
2178 return rc;
2179
2180 /* volume descriptor version (always 1) */
2181 byte = 1;
2182 rc = write711(volInfo, byte);
2183 if(rc <= 0)
2184 return rc;
2185
2186 /* primary: unused field
2187 * supplementary: volume flags, 0x00 */
2188 byte = 0;
2189 rc = write711(volInfo, byte);
2190 if(rc <= 0)
2191 return rc;
2192
2193 /* system identifier (32 spaces) */
2194 if(isPrimary)
2195 {
2196 strcpy((char*)aString, " ");
2197 rc = wcWrite(volInfo, (char*)aString, 32);
2198 if(rc <= 0)
2199 return rc;
2200 }
2201 else
2202 {
2203 rc = writeJolietStringField(volInfo, "", 32);
2204 if(rc < 0)
2205 return rc;
2206 }
2207
2208 /* VOLUME identifier */
2209 if(isPrimary)
2210 {
2211 strcpy((char*)aString, volInfo->volId);
2212
2213 for(count = strlen((char*)aString); count < 32; count++)
2214 aString[count] = ' ';
2215
2216 rc = wcWrite(volInfo, (char*)aString, 32);
2217 if(rc <= 0)
2218 return rc;
2219 }
2220 else
2221 {
2222 rc = writeJolietStringField(volInfo, volInfo->volId, 32);
2223 if(rc < 0)
2224 return rc;
2225 }
2226 /* END VOLUME identifier */
2227
2228 /* unused field */
2229 rc = writeByteBlock(volInfo, 0, 8);
2230 if(rc < 0)
2231 return rc;
2232
2233 /* VOLUME space size (number of logical blocks, absolutely everything) */
2234 /* it's safe to not use wcSeek() here since everything is left as it is */
2235 currPos = bkSeekTell(volInfo->imageForWriting);
2236
2237 bkSeekSet(volInfo->imageForWriting, 0, SEEK_END);
2238 anUnsigned = bkSeekTell(volInfo->imageForWriting) /
2239 NBYTES_LOGICAL_BLOCK;
2240
2241 bkSeekSet(volInfo->imageForWriting, currPos, SEEK_SET);
2242
2243 rc = write733(volInfo, anUnsigned);
2244 if(rc <= 0)
2245 return rc;
2246 /* END VOLUME space size (number of logical blocks, absolutely everything) */
2247
2248 /* primary: unused field
2249 * joliet: escape sequences */
2250 if(isPrimary)
2251 {
2252 rc = writeByteBlock(volInfo, 0, 32);
2253 if(rc < 0)
2254 return rc;
2255 }
2256 else
2257 {
2258 /* this is the only joliet field that's padded with 0x00 instead of ' ' */
2259 aString[0] = 0x25;
2260 aString[1] = 0x2F;
2261 aString[2] = 0x45;
2262
2263 rc = wcWrite(volInfo, (char*)aString, 3);
2264 if(rc <= 0)
2265 return rc;
2266
2267 rc = writeByteBlock(volInfo, 0, 29);
2268 if(rc < 0)
2269 return rc;
2270 }
2271
2272 /* volume set size (always 1) */
2273 anUnsignedShort = 1;
2274 rc = write723(volInfo, anUnsignedShort);
2275 if(rc <= 0)
2276 return rc;
2277
2278 /* volume sequence number (also always 1) */
2279 rc = write723(volInfo, anUnsignedShort);
2280 if(rc <= 0)
2281 return rc;
2282
2283 /* logical block size (always 2048) */
2284 anUnsignedShort = NBYTES_LOGICAL_BLOCK;
2285 rc = write723(volInfo, anUnsignedShort);
2286 if(rc <= 0)
2287 return rc;
2288
2289 /* path table size */
2290 anUnsigned = pathTableSize;
2291 rc = write733(volInfo, anUnsigned);
2292 if(rc <= 0)
2293 return rc;
2294
2295 /* location of occurence of type l path table */
2296 anUnsigned = lPathTableLoc / NBYTES_LOGICAL_BLOCK;
2297 rc = write731(volInfo, anUnsigned);
2298 if(rc <= 0)
2299 return rc;
2300
2301 /* location of optional occurence of type l path table */
2302 anUnsigned = 0;
2303 rc = write731(volInfo, anUnsigned);
2304 if(rc <= 0)
2305 return rc;
2306
2307 /* location of occurence of type m path table */
2308 anUnsigned = mPathTableLoc / NBYTES_LOGICAL_BLOCK;
2309 rc = write732(volInfo, anUnsigned);
2310 if(rc <= 0)
2311 return rc;
2312
2313 /* location of optional occurence of type m path table */
2314 anUnsigned = 0;
2315 rc = write732(volInfo, anUnsigned);
2316 if(rc <= 0)
2317 return rc;
2318
2319 /* ROOT dr */
2320 /* record length (always 34 here) */
2321 byte = 34;
2322 rc = write711(volInfo, byte);
2323 if(rc <= 0)
2324 return rc;
2325
2326 /* extended attribute record length (always none) */
2327 byte = 0;
2328 rc = write711(volInfo, byte);
2329 if(rc <= 0)
2330 return rc;
2331
2332 /* location of extent */
2333 anUnsigned = rootDrLocation / NBYTES_LOGICAL_BLOCK;
2334 rc = write733(volInfo, anUnsigned);
2335 if(rc <= 0)
2336 return rc;
2337
2338 /* data length */
2339 rc = write733(volInfo, rootDrSize);
2340 if(rc <= 0)
2341 return rc;
2342
2343 /* recording time */
2344 epochToShortString(creationTime, (char*)aString);
2345 rc = wcWrite(volInfo, (char*)aString, 7);
2346 if(rc <= 0)
2347 return rc;
2348
2349 /* file flags (always binary 00000010 here) */
2350 byte = 0x02;
2351 rc = write711(volInfo, byte);
2352 if(rc <= 0)
2353 return rc;
2354
2355 /* file unit size (not in interleaved mode -> 0) */
2356 byte = 0;
2357 rc = write711(volInfo, byte);
2358 if(rc <= 0)
2359 return rc;
2360
2361 /* interleave gap size (not in interleaved mode -> 0) */
2362 rc = write711(volInfo, byte);
2363 if(rc <= 0)
2364 return rc;
2365
2366 /* volume sequence number */
2367 anUnsignedShort = 1;
2368 rc = write723(volInfo, anUnsignedShort);
2369 if(rc <= 0)
2370 return rc;
2371
2372 /* length of file identifier */
2373 byte = 1;
2374 rc = write711(volInfo, byte);
2375 if(rc <= 0)
2376 return rc;
2377
2378 /* file identifier */
2379 byte = 0;
2380 rc = write711(volInfo, byte);
2381 if(rc <= 0)
2382 return rc;
2383 /* END ROOT dr */
2384
2385 /* volume set identidier */
2386 if(isPrimary)
2387 {
2388 rc = writeByteBlock(volInfo, ' ', 128);
2389 if(rc < 0)
2390 return rc;
2391 }
2392 else
2393 {
2394 rc = writeJolietStringField(volInfo, "", 128);
2395 if(rc < 0)
2396 return rc;
2397 }
2398
2399 /* PUBLISHER identifier */
2400 strcpy((char*)aString, volInfo->publisher);
2401
2402 if(isPrimary)
2403 {
2404 for(count = strlen((char*)aString); count < 128; count++)
2405 aString[count] = ' ';
2406
2407 rc = wcWrite(volInfo, (char*)aString, 128);
2408 if(rc <= 0)
2409 return rc;
2410 }
2411 else
2412 {
2413 rc = writeJolietStringField(volInfo, (char*)aString, 128);
2414 if(rc < 0)
2415 return rc;
2416 }
2417 /* PUBLISHER identifier */
2418
2419 /* DATA preparer identifier */
2420 if(isPrimary)
2421 {
2422 rc = wcWrite(volInfo, "ISO Master", 10);
2423 if(rc <= 0)
2424 return rc;
2425
2426 rc = writeByteBlock(volInfo, ' ', 118);
2427 if(rc < 0)
2428 return rc;
2429 }
2430 else
2431 {
2432 rc = writeJolietStringField(volInfo, "ISO Master", 128);
2433 if(rc < 0)
2434 return rc;
2435 }
2436 /* END DATA preparer identifier */
2437
2438 /* application identifier, copyright file identifier, abstract file
2439 * identifier, bibliographic file identifier (128 + 3*37) */
2440 if(isPrimary)
2441 {
2442 rc = writeByteBlock(volInfo, ' ', 239);
2443 if(rc < 0)
2444 return rc;
2445 }
2446 else
2447 {
2448 /* application id */
2449 rc = writeJolietStringField(volInfo, "", 128);
2450 if(rc < 0)
2451 return rc;
2452
2453 /* 18 ucs2 spaces + 0x00 */
2454 for(count = 0; count < 3; count++)
2455 {
2456 rc = writeJolietStringField(volInfo, "", 36);
2457 if(rc < 0)
2458 return rc;
2459
2460 byte = 0x00;
2461 rc = wcWrite(volInfo, (char*)&byte, 1);
2462 if(rc <= 0)
2463 return rc;
2464 }
2465 }
2466
2467 /* VOLUME creation date */
2468 epochToLongString(creationTime, (char*)aString);
2469
2470 rc = wcWrite(volInfo, (char*)aString, 17);
2471 if(rc <= 0)
2472 return rc;
2473 /* END VOLUME creation date */
2474
2475 /* volume modification date (same as creation) */
2476 rc = wcWrite(volInfo, (char*)aString, 17);
2477 if(rc <= 0)
2478 return rc;
2479
2480 /* VOLUME expiration date (none) */
2481 rc = writeByteBlock(volInfo, '0', 16);
2482 if(rc < 0)
2483 return rc;
2484
2485 byte = 0;
2486 rc = write711(volInfo, byte);
2487 if(rc <= 0)
2488 return rc;
2489 /* END VOLUME expiration date (none) */
2490
2491 /* volume effective date (same as creation) */
2492 rc = wcWrite(volInfo, (char*)aString, 17);
2493 if(rc <= 0)
2494 return rc;
2495
2496 /* file structure version */
2497 byte = 1;
2498 rc = write711(volInfo, byte);
2499 if(rc <= 0)
2500 return rc;
2501
2502 /* reserved, applications use, reserved */
2503 rc = writeByteBlock(volInfo, 0, 1166);
2504 if(rc < 0)
2505 return rc;
2506
2507 return 1;
2508 }
2509
2510 /******************************************************************************
2511 * wroteIsolinuxBootRecord()
2512 * Check whether the file already written to the new iso was a boot record.
2513 * */
wroteIsolinuxBootRecord(VolInfo * volInfo,FileToWrite * file,bool * isIsolinux)2514 int wroteIsolinuxBootRecord(VolInfo* volInfo, FileToWrite* file,
2515 bool* isIsolinux)
2516 {
2517 *isIsolinux = false;
2518
2519 if(volInfo->bootMediaType == BOOT_MEDIA_NO_EMULATION &&
2520 volInfo->bootRecordIsVisible &&
2521 file->origFile == volInfo->bootRecordOnImage)
2522 /* Likely true, do one more check to make sure. The extra check
2523 * is needed for Windows XP isos with SP2 added by c't slipstreamer */
2524 {
2525 bk_off_t origPos;
2526 int rc;
2527 char fourBytes[4];
2528
2529 origPos = wcSeekTell(volInfo);
2530
2531 wcSeekSet(volInfo, BASETW_PTR(file)->extentNumber *
2532 NBYTES_LOGICAL_BLOCK + 8);
2533
2534 rc = bkRead(volInfo->imageForWriting, fourBytes, 4);
2535 if(rc != 4)
2536 return BKERROR_READ_GENERIC;
2537
2538 if(fourBytes[0] == 16 && fourBytes[1] == 0 &&
2539 fourBytes[2] == 0 && fourBytes[3] == 0)
2540 *isIsolinux = true;
2541
2542 wcSeekSet(volInfo, origPos);
2543 }
2544
2545 return 1;
2546 }
2547