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