00001
00002
00003
00004 #include <errno.h>
00005 #include <stdio.h>
00006 #include <time.h>
00007 #include <stdlib.h>
00008 #include <fcntl.h>
00009 #include <string.h>
00010 #include <unistd.h>
00011 #include <dirent.h>
00012 #include <ctype.h>
00013 #include <ibm/partition.h>
00014
00015 #include <sys/stat.h>
00016
00017 #define Writefield(fd, f) Write(fd, &(f), sizeof(f))
00018
00019 extern char *optarg;
00020 extern int optind;
00021
00022 typedef unsigned char u_int8_t;
00023 typedef unsigned short int u_int16_t;
00024 typedef unsigned long int u_int32_t;
00025
00026 #ifndef min
00027 #define min(a,b) ((a) < (b) ? (a) : (b))
00028 #endif
00029
00030 #define FLAG_DIR 2
00031
00032 #include <sys/types.h>
00033 #include <sys/stat.h>
00034
00035 #define NAMELEN (DIRSIZ+5)
00036 #define ISONAMELEN 12
00037 #define PLATFORM_80X86 0
00038
00039 #define ISO_SECTOR 2048
00040 #define VIRTUAL_SECTOR 512
00041
00042 #define CURRENTDIR "."
00043 #define PARENTDIR ".."
00044
00045
00046
00047
00048
00049 struct pvd {
00050 u_int8_t one;
00051 char set[6];
00052 u_int8_t zero;
00053 char system[32];
00054 char volume[32];
00055 u_int8_t zeroes1[8];
00056 u_int32_t sectors[2];
00057 u_int8_t zeroes2[32];
00058 u_int16_t setsize[2];
00059 u_int16_t seq[2];
00060 u_int16_t sectorsize[2];
00061 u_int32_t pathtable[2];
00062 u_int32_t first_little_pathtable_start;
00063 u_int32_t second_little_pathtable_start;
00064 u_int32_t first_big_pathtable_start;
00065 u_int32_t second_big_pathtable_start;
00066 u_int8_t rootrecord[34];
00067 u_int8_t volumeset[128];
00068 u_int8_t publisher[128];
00069 u_int8_t preparer[128];
00070 u_int8_t application[128];
00071 u_int8_t copyrightfile[37];
00072 u_int8_t abstractfile[37];
00073 u_int8_t bibliofile[37];
00074 u_int8_t create[17];
00075 u_int8_t modified[17];
00076 char expiry[17];
00077 u_int8_t effective[17];
00078 u_int8_t one2;
00079 u_int8_t zero2;
00080 u_int8_t zeroes3[512];
00081 u_int8_t zeroes4[653];
00082 };
00083
00084
00085
00086 struct bootrecord {
00087 u_int8_t indicator;
00088 char set[5];
00089 u_int8_t version;
00090 char ident[32];
00091 u_int8_t zero[32];
00092 u_int32_t bootcatalog;
00093 u_int8_t zero2[1973];
00094 };
00095
00096
00097
00098 struct bc_validation {
00099 u_int8_t headerid;
00100 u_int8_t platform;
00101 u_int8_t zero[2];
00102 char idstring[24];
00103 u_int16_t checksum;
00104 u_int8_t keys[2];
00105 };
00106
00107
00108
00109 #define INDICATE_BOOTABLE 0x88
00110
00111 #define BOOTMEDIA_NONE 0
00112 #define BOOTMEDIA_120M 1
00113 #define BOOTMEDIA_144M 2
00114 #define BOOTMEDIA_288M 3
00115 #define BOOTMEDIA_HARDDISK 4
00116
00117 struct bc_initial {
00118 u_int8_t indicator;
00119 u_int8_t media;
00120 u_int16_t seg;
00121 u_int8_t type;
00122 u_int8_t zero;
00123 u_int16_t sectors;
00124 u_int32_t startsector;
00125 u_int8_t zero2[20];
00126 };
00127
00128
00129
00130 struct dir {
00131 u_int8_t recordsize;
00132 u_int8_t extended;
00133 u_int32_t datasector[2];
00134 u_int32_t filesize[2];
00135 u_int8_t year;
00136 u_int8_t month;
00137 u_int8_t day;
00138 u_int8_t hour;
00139 u_int8_t minute;
00140 u_int8_t second;
00141 u_int8_t offset;
00142 u_int8_t flags;
00143 u_int8_t interleaved;
00144 u_int8_t interleavegap;
00145 u_int16_t sequence[2];
00146 u_int8_t namelen;
00147 char name[NAMELEN];
00148 };
00149
00150
00151
00152 struct node {
00153 char name[NAMELEN];
00154 int isdir;
00155 int pathtablerecord;
00156 struct node *firstchild, *nextchild;
00157
00158
00159 u_int32_t startsector, bytesize;
00160 };
00161
00162 int n_reserved_pathtableentries = 0, n_used_pathtableentries = 0;
00163 int harddisk_emulation = 0;
00164 int system_type = 0;
00165
00166 int get_system_type(int fd);
00167
00168 ssize_t
00169 Write(int fd, void *buf, ssize_t len)
00170 {
00171 ssize_t r;
00172 if((r=write(fd, buf, len)) != len) {
00173 if(r < 0) { perror("write"); }
00174 fprintf(stderr, "failed or short write - aborting.\n");
00175 exit(1);
00176 }
00177 return len;
00178 }
00179
00180 off_t
00181 Lseek(int fd, off_t pos, int rel)
00182 {
00183 off_t r;
00184
00185 if((r=lseek(fd, pos, rel)) < 0) {
00186 perror("lseek");
00187 fprintf(stderr, "lseek failed - aborting.\n");
00188 exit(1);
00189 }
00190
00191 return r;
00192 }
00193
00194 void
00195 writesector(int fd, char *block, int *currentsector)
00196 {
00197 Write(fd, block, ISO_SECTOR);
00198 (*currentsector)++;
00199 return;
00200 }
00201
00202 void
00203 seeksector(int fd, int sector, int *currentsector)
00204 {
00205 Lseek(fd, sector*ISO_SECTOR, SEEK_SET);
00206 *currentsector = sector;
00207 }
00208
00209 void
00210 seekwritesector(int fd, int sector, char *block, int *currentsector)
00211 {
00212 seeksector(fd, sector, currentsector);
00213 writesector(fd, block, currentsector);
00214 }
00215
00216 ssize_t
00217 Read(int fd, void *buf, ssize_t len)
00218 {
00219 ssize_t r;
00220 if((r=read(fd, buf, len)) != len) {
00221 if(r < 0) { perror("read"); }
00222 fprintf(stderr, "failed or short read.\n");
00223 exit(1);
00224 }
00225
00226 return len;
00227 }
00228
00229 void both16(unsigned char *both, unsigned short i16)
00230 {
00231 unsigned char *little, *big;
00232
00233 little = both;
00234 big = both + 2;
00235
00236 little[0] = big[1] = i16 & 0xFF;
00237 little[1] = big[0] = (i16 >> 8) & 0xFF;
00238 }
00239
00240 void both32(unsigned char *both, unsigned long i32)
00241 {
00242 unsigned char *little, *big;
00243
00244 little = both;
00245 big = both + 4;
00246
00247 little[0] = big[3] = i32 & 0xFF;
00248 little[1] = big[2] = (i32 >> 8) & 0xFF;
00249 little[2] = big[1] = (i32 >> 16) & 0xFF;
00250 little[3] = big[0] = (i32 >> 24) & 0xFF;
00251 }
00252
00253 #define MINDIRLEN 1
00254 #define MAXDIRLEN 31
00255
00256 #define MAXLEVEL 8
00257
00258 static int cmpf(const void *v1, const void *v2)
00259 {
00260 struct node *n1, *n2;
00261 int i;
00262 char f1[NAMELEN], f2[NAMELEN];
00263
00264 n1 = (struct node *) v1;
00265 n2 = (struct node *) v2;
00266 strcpy(f1, n1->name);
00267 strcpy(f2, n2->name);
00268 for(i = 0; i < strlen(f1); i++) f1[i] = toupper(f1[i]);
00269 for(i = 0; i < strlen(f2); i++) f2[i] = toupper(f2[i]);
00270
00271
00272 return -strcmp(f1, f2);
00273 }
00274
00275 void
00276 maketree(struct node *thisdir, char *name, int level)
00277 {
00278 DIR *dir;
00279 struct dirent *e;
00280 struct node *dirnodes = NULL;
00281 int reserved_dirnodes = 0, used_dirnodes = 0;
00282 struct node *child;
00283
00284 thisdir->firstchild = NULL;
00285 thisdir->isdir = 1;
00286 thisdir->startsector = 0xdeadbeef;
00287
00288 if(level >= MAXLEVEL) {
00289 fprintf(stderr, "ignoring entries in %s (too deep for iso9660)\n",
00290 name);
00291 return;
00292 }
00293
00294 if(!(dir = opendir(CURRENTDIR))) {
00295 perror("opendir");
00296 return;
00297 }
00298
00299
00300 while(readdir(dir)) reserved_dirnodes++;
00301 if(!reserved_dirnodes) {
00302 closedir(dir);
00303 return;
00304 }
00305
00306 if(!(dirnodes = malloc(sizeof(*dirnodes)*reserved_dirnodes))) {
00307 fprintf(stderr, "couldn't allocate dirnodes (%d bytes)\n",
00308 sizeof(*dirnodes)*reserved_dirnodes);
00309 exit(1);
00310 }
00311
00312
00313
00314 rewinddir(dir);
00315
00316 child = dirnodes;
00317 while((e=readdir(dir))) {
00318 struct stat st;
00319 mode_t type;
00320 if(!strcmp(e->d_name, CURRENTDIR) || !strcmp(e->d_name, PARENTDIR))
00321 continue;
00322 if(stat(e->d_name, &st) < 0) {
00323 perror(e->d_name);
00324 fprintf(stderr, "failed to stat file/dir\n");
00325 exit(1);
00326 }
00327
00328 type = st.st_mode & S_IFMT;
00329
00330
00331
00332
00333
00334 if(type != S_IFDIR && type != S_IFREG)
00335 continue;
00336
00337 used_dirnodes++;
00338 if(used_dirnodes > reserved_dirnodes) {
00339 fprintf(stderr, "huh, directory entries appeared "
00340 "(not enough pre-allocated nodes; this can't happen) ?\n");
00341 exit(1);
00342 }
00343
00344 if(type == S_IFDIR) {
00345 child->isdir = 1;
00346 } else {
00347 child->isdir = 0;
00348 child->firstchild = NULL;
00349 }
00350 strncpy(child->name, e->d_name, sizeof(child->name));
00351
00352 child++;
00353 }
00354
00355 closedir(dir);
00356
00357 if(!used_dirnodes)
00358 return;
00359
00360 if(!(dirnodes=realloc(dirnodes, used_dirnodes*sizeof(*dirnodes)))) {
00361 fprintf(stderr, "realloc() of dirnodes failed - aborting\n");
00362 exit(1);
00363 }
00364
00365 qsort(dirnodes, used_dirnodes, sizeof(*dirnodes), cmpf);
00366
00367 child = dirnodes;
00368
00369 while(used_dirnodes--) {
00370 child->nextchild = thisdir->firstchild;
00371 thisdir->firstchild = child;
00372 if(child->isdir) {
00373 if(chdir(child->name) < 0) {
00374 perror(child->name);
00375 } else {
00376 maketree(child, child->name, level+1);
00377 if(chdir(PARENTDIR) < 0) {
00378 perror("chdir() failed");
00379 fprintf(stderr, "couldn't chdir() to parent, aborting\n");
00380 exit(1);
00381 }
00382 }
00383 }
00384
00385 child++;
00386 }
00387
00388 }
00389
00390 void
00391 little32(unsigned char *dest, u_int32_t src)
00392 {
00393 dest[0] = ((src >> 0) & 0xFF);
00394 dest[1] = ((src >> 8) & 0xFF);
00395 dest[2] = ((src >> 16) & 0xFF);
00396 dest[3] = ((src >> 24) & 0xFF);
00397
00398 return;
00399 }
00400
00401 void
00402 little16(unsigned char *dest, u_int16_t src)
00403 {
00404 dest[0] = ((src >> 0) & 0xFF);
00405 dest[1] = ((src >> 8) & 0xFF);
00406
00407 return;
00408 }
00409
00410 void
00411 big32(unsigned char *dest, u_int32_t src)
00412 {
00413 dest[3] = ((src >> 0) & 0xFF);
00414 dest[2] = ((src >> 8) & 0xFF);
00415 dest[1] = ((src >> 16) & 0xFF);
00416 dest[0] = ((src >> 24) & 0xFF);
00417 return;
00418 }
00419
00420 void
00421 big16(unsigned char *dest, u_int16_t src)
00422 {
00423 dest[1] = ((src >> 0) & 0xFF);
00424 dest[0] = ((src >> 8) & 0xFF);
00425 return;
00426 }
00427
00428
00429 void
00430 traversetree(struct node *root, int level, int littleendian,
00431 int maxlevel, int *bytes, int fd, int parentrecord, int *recordno)
00432 {
00433 struct node *child;
00434 struct pte {
00435 u_int8_t len;
00436 u_int8_t zero;
00437 u_int32_t startsector;
00438 u_int16_t parent;
00439 } pte;
00440
00441 if(level == maxlevel) {
00442 int i;
00443 char newname[NAMELEN];
00444 if(!root->isdir)
00445 return;
00446 pte.zero = 0;
00447 if(level == 1) {
00448
00449 pte.len = 1;
00450 pte.parent = 1;
00451 root->name[0] = root->name[1] = '\0';
00452 } else {
00453 pte.len = strlen(root->name);
00454 pte.parent = parentrecord;
00455 }
00456 pte.startsector = root->startsector;
00457 root->pathtablerecord = (*recordno)++;
00458
00459 if(littleendian) {
00460 little32((unsigned char *) &pte.startsector, pte.startsector);
00461 little16((unsigned char *) &pte.parent, pte.parent);
00462 } else {
00463 big32((unsigned char *) &pte.startsector, pte.startsector);
00464 big16((unsigned char *) &pte.parent, pte.parent);
00465 }
00466
00467 *bytes += Write(fd, &pte.len, sizeof(pte.len));
00468 *bytes += Write(fd, &pte.zero, sizeof(pte.zero));
00469 *bytes += Write(fd, &pte.startsector, sizeof(pte.startsector));
00470 *bytes += Write(fd, &pte.parent, sizeof(pte.parent));
00471 if(!(pte.len%2))
00472 root->name[pte.len++] = '\0';
00473 for(i = 0; i < pte.len; i++)
00474 newname[i] = toupper(root->name[i]);
00475 *bytes += Write(fd, newname, pte.len);
00476 return;
00477 }
00478
00479 for(child = root->firstchild; child; child = child->nextchild)
00480 if(child->isdir)
00481 traversetree(child, level+1, littleendian,
00482 maxlevel, bytes, fd, root->pathtablerecord,
00483 recordno);
00484
00485 return;
00486 }
00487
00488 int
00489 makepathtables(struct node *root, int littleendian, int *bytes, int fd)
00490 {
00491 int level;
00492 static char block[ISO_SECTOR];
00493 int recordno;
00494
00495 recordno = 1;
00496
00497 *bytes = 0;
00498
00499 for(level = 1; level <= MAXLEVEL; level++)
00500 traversetree(root, 1, littleendian, level, bytes, fd, 1, &recordno);
00501
00502 if(*bytes % ISO_SECTOR) {
00503 ssize_t x;
00504 x = ISO_SECTOR-(*bytes % ISO_SECTOR);
00505 write(fd, block, x);
00506 *bytes += x;
00507 }
00508
00509 return *bytes/ISO_SECTOR;
00510 }
00511
00512 ssize_t
00513 write_direntry(char *origname, u_int32_t sector, u_int32_t size, int isdir,
00514 int fd)
00515 {
00516 int namelen, total = 0;
00517 struct dir entry;
00518 char copyname[NAMELEN];
00519
00520 memset(&entry, 0, sizeof(entry));
00521
00522 if(!strcmp(origname, CURRENTDIR)) {
00523 namelen = 1;
00524 } else if(!strcmp(origname, PARENTDIR)) {
00525 entry.name[0] = '\001';
00526 namelen = 1;
00527 } else {
00528 int i;
00529 strcpy(copyname, origname);
00530 namelen = strlen(copyname);
00531
00532 if(namelen > ISONAMELEN) {
00533 fprintf(stderr, "%s: truncated, too long for iso9660\n", copyname);
00534 namelen = ISONAMELEN;
00535 copyname[namelen] = '\0';
00536 }
00537
00538 strcpy(entry.name, copyname);
00539 for(i = 0; i < namelen; i++)
00540 entry.name[i] = toupper(entry.name[i]);
00541
00542
00543 entry.name[namelen] = '\0';
00544 entry.name[namelen+1] = '\0';
00545 entry.name[namelen+2] = '\0';
00546 }
00547 entry.namelen = namelen;
00548 if(!(namelen%2)) namelen++;
00549
00550
00551
00552 entry.recordsize = 33 + namelen;
00553 both32((unsigned char *) entry.datasector, sector);
00554 both32((unsigned char *) entry.filesize, size);
00555
00556 if(isdir) entry.flags = FLAG_DIR;
00557
00558
00559
00560 both16((unsigned char *) entry.sequence, 1);
00561
00562 total = Write(fd, &entry.recordsize, sizeof(entry.recordsize));
00563 total += Write(fd, &entry.extended, sizeof(entry.extended));
00564 total += Write(fd, entry.datasector, sizeof(entry.datasector));
00565 total += Write(fd, entry.filesize, sizeof(entry.filesize));
00566 total += Write(fd, &entry.year, sizeof(entry.year));
00567 total += Write(fd, &entry.month, sizeof(entry.month));
00568 total += Write(fd, &entry.day, sizeof(entry.day));
00569 total += Write(fd, &entry.hour, sizeof(entry.hour));
00570 total += Write(fd, &entry.minute, sizeof(entry.minute));
00571 total += Write(fd, &entry.second, sizeof(entry.second));
00572 total += Write(fd, &entry.offset, sizeof(entry.offset));
00573 total += Write(fd, &entry.flags, sizeof(entry.flags));
00574 total += Write(fd, &entry.interleaved, sizeof(entry.interleaved));
00575 total += Write(fd, &entry.interleavegap, sizeof(entry.interleavegap));
00576 total += Write(fd, entry.sequence, sizeof(entry.sequence));
00577 total += Write(fd, &entry.namelen, sizeof(entry.namelen));
00578 total += Write(fd, entry.name, namelen);
00579
00580 if(total != entry.recordsize || (total % 2) != 0) {
00581 printf("%2d, %2d! ", total, entry.recordsize);
00582 printf("%3d = %3d - %2d + %2d\n",
00583 entry.recordsize, sizeof(entry), sizeof(entry.name), namelen);
00584 }
00585
00586 return entry.recordsize;
00587 }
00588
00589 void
00590 writedata(struct node *parent, struct node *root,
00591 int fd, int *currentsector, int dirs, struct dir *rootentry,
00592 int rootsize, int remove_after)
00593 {
00594 static char buf[1024*1024];
00595 struct node *c;
00596 ssize_t written = 0, rest;
00597
00598 for(c = root->firstchild; c; c = c->nextchild) {
00599 if(c->isdir && chdir(c->name) < 0) {
00600 perror(c->name);
00601 fprintf(stderr, "couldn't chdir to %s - aborting\n",
00602 c->name);
00603 exit(1);
00604 }
00605 writedata(root, c, fd, currentsector, dirs, rootentry, rootsize, remove_after);
00606 if(c->isdir && chdir(PARENTDIR) < 0) {
00607 perror("chdir to ..");
00608 fprintf(stderr, "couldn't chdir to parent - "
00609 "aborting\n");
00610 exit(1);
00611 }
00612 }
00613
00614
00615
00616 if(root->isdir && dirs) {
00617
00618 written = 0;
00619 root->startsector = *currentsector;
00620 written += write_direntry(CURRENTDIR, root->startsector,
00621 root->bytesize, root->isdir, fd);
00622 if(parent) {
00623 written += write_direntry(PARENTDIR, parent->startsector,
00624 root->bytesize, root->isdir, fd);
00625 } else {
00626 written += write_direntry(PARENTDIR, root->startsector,
00627 root->bytesize, root->isdir, fd);
00628 }
00629 for(c = root->firstchild; c; c = c->nextchild) {
00630 off_t cur1, cur2;
00631 ssize_t written_before;
00632 cur1 = Lseek(fd, 0, SEEK_CUR);
00633 written_before = written;
00634 written += write_direntry(c->name,
00635 c->startsector, c->bytesize, c->isdir, fd);
00636 cur2 = Lseek(fd, 0, SEEK_CUR);
00637 if(cur1/ISO_SECTOR != (cur2-1)/ISO_SECTOR) {
00638
00639 Lseek(fd, cur1, SEEK_SET);
00640 written = written_before;
00641 rest=(ISO_SECTOR-(written % ISO_SECTOR));
00642 memset(buf, 0, rest);
00643 Write(fd, buf, rest);
00644 written += rest;
00645 written += write_direntry(c->name,
00646 c->startsector, c->bytesize, c->isdir, fd);
00647 }
00648 }
00649 root->bytesize = written;
00650 } else if(!root->isdir && !dirs) {
00651
00652 struct stat st;
00653 ssize_t rem;
00654 int filefd;
00655
00656 if(stat(root->name, &st) < 0) {
00657 perror(root->name);
00658 fprintf(stderr, "couldn't stat %s - aborting\n", root->name);
00659 exit(1);
00660 }
00661
00662 if((filefd = open(root->name, O_RDONLY)) < 0) {
00663 perror(root->name);
00664 fprintf(stderr, "couldn't open %s - aborting\n", root->name);
00665 exit(1);
00666 }
00667
00668 rem = st.st_size;
00669
00670 root->startsector = *currentsector;
00671
00672 while(rem > 0) {
00673 ssize_t chunk;
00674 chunk = min(sizeof(buf), rem);
00675 Read(filefd, buf, chunk);
00676 Write(fd, buf, chunk);
00677 rem -= chunk;
00678 }
00679
00680 close(filefd);
00681
00682 root->bytesize = written = st.st_size;
00683 if(remove_after && unlink(root->name) < 0) {
00684 perror("unlink");
00685 fprintf(stderr, "couldn't remove %s\n", root->name);
00686 }
00687 } else {
00688
00689 return;
00690 }
00691
00692
00693
00694 if((rest=(ISO_SECTOR-(written % ISO_SECTOR)))) {
00695 memset(buf, 0, rest);
00696 Write(fd, buf, rest);
00697 written += rest;
00698 }
00699
00700
00701
00702 if(root->isdir) { root->bytesize = written; }
00703
00704 *currentsector += written/ISO_SECTOR;
00705 }
00706
00707 void
00708 writebootcatalog(int fd, int *currentsector, int imagesector, int imagesectors)
00709 {
00710 static char buf[ISO_SECTOR];
00711 struct bc_validation validate;
00712 struct bc_initial initial;
00713
00714 ssize_t written, rest;
00715 u_int16_t *v, sum = 0;
00716 int i;
00717
00718
00719
00720 memset(&validate, 0, sizeof(validate));
00721 validate.headerid = 1;
00722 validate.platform = PLATFORM_80X86;
00723 strcpy(validate.idstring, "");
00724 validate.keys[0] = 0x55;
00725 validate.keys[1] = 0xaa;
00726
00727 v = (u_int16_t *) &validate;
00728 for(i = 0; i < sizeof(validate)/2; i++)
00729 sum += v[i];
00730 validate.checksum = 65535 - sum + 1;
00731
00732 written = Write(fd, &validate, sizeof(validate));
00733
00734
00735
00736 memset(&initial, 0, sizeof(initial));
00737
00738 initial.indicator = INDICATE_BOOTABLE;
00739 if (harddisk_emulation)
00740 {
00741 initial.media = BOOTMEDIA_HARDDISK;
00742 initial.type = system_type;
00743 }
00744 else
00745 initial.media = BOOTMEDIA_144M;
00746
00747 initial.sectors = 1;
00748 initial.startsector = imagesector;
00749
00750 written += Write(fd, &initial, sizeof(initial));
00751
00752
00753
00754 if((rest = ISO_SECTOR - (written % 2048))) {
00755 memset(buf, 0, sizeof(buf));
00756 written += Write(fd, buf, rest);
00757 }
00758
00759 (*currentsector) += written / ISO_SECTOR;
00760
00761 return;
00762 }
00763
00764 int
00765 writebootimage(char *bootimage, int bootfd, int fd, int *currentsector)
00766 {
00767 static char buf[1024*64];
00768 ssize_t chunk, written = 0, rest;
00769 int virtuals;
00770
00771 while((chunk=read(bootfd, buf, sizeof(buf))) > 0)
00772 written += Write(fd, buf, chunk);
00773
00774 if(chunk < 0) {
00775 perror("read boot image");
00776 exit(1);
00777 }
00778
00779 virtuals = written / VIRTUAL_SECTOR;
00780
00781 if((rest = ISO_SECTOR - (written % 2048))) {
00782 memset(buf, 0, sizeof(buf));
00783 written += Write(fd, buf, rest);
00784 }
00785
00786 (*currentsector) += written/ISO_SECTOR;
00787
00788 return virtuals;
00789 }
00790
00791 void
00792 writebootrecord(int fd, int *currentsector, int bootcatalogsector)
00793 {
00794 int i;
00795 static struct bootrecord bootrecord;
00796 ssize_t w = 0;
00797
00798
00799 memset(&bootrecord, 0, sizeof(bootrecord));
00800 bootrecord.set[0] = 'C';
00801 bootrecord.set[1] = 'D';
00802 bootrecord.set[2] = '0';
00803 bootrecord.set[3] = '0';
00804 bootrecord.set[4] = '1';
00805 bootrecord.version = 1;
00806 bootrecord.bootcatalog = bootcatalogsector;
00807 strcpy(bootrecord.ident, "EL TORITO SPECIFICATION");
00808 for(i = strlen(bootrecord.ident);
00809 i < sizeof(bootrecord.ident); i++)
00810 bootrecord.ident[i] = '\0';
00811
00812 w = Writefield(fd, bootrecord.indicator);
00813 w += Writefield(fd, bootrecord.set);
00814 w += Writefield(fd, bootrecord.version);
00815 w += Writefield(fd, bootrecord.ident);
00816 w += Writefield(fd, bootrecord.zero);
00817 w += Writefield(fd, bootrecord.bootcatalog);
00818 w += Writefield(fd, bootrecord.zero2);
00819
00820 if(w != ISO_SECTOR) {
00821 fprintf(stderr, "WARNING: something went wrong - boot record (%d) isn't a sector size (%d)\n",
00822 w, ISO_SECTOR);
00823 }
00824
00825 (*currentsector)++;
00826 }
00827
00828 int
00829 main(int argc, char *argv[])
00830 {
00831 int currentsector = 0;
00832 int imagesector, imagesectors;
00833 int bootfd, fd, i, ch, nsectors;
00834 int remove_after = 0;
00835 static char block[ISO_SECTOR];
00836 static struct pvd pvd;
00837 char *label = "ISO9660";
00838 struct tm *now;
00839 time_t nowtime;
00840 char timestr[20], *prog;
00841 char *bootimage = NULL;
00842 struct node root;
00843 int pvdsector;
00844 int bigpath, littlepath, pathbytes = 0, dirsector, filesector, enddir;
00845 int bootvolumesector, bootcatalogsector;
00846
00847 prog = argv[0];
00848
00849
00850
00851
00852
00853 if(sizeof(struct pvd) != ISO_SECTOR) {
00854 fprintf(stderr, "Something confusing happened at\n"
00855 "compile-time; pvd should be a sector size. %d != %d\n",
00856 sizeof(struct pvd), ISO_SECTOR);
00857 return 1;
00858 }
00859
00860 while ((ch = getopt(argc, argv, "Rb:hl:")) != -1) {
00861 switch(ch) {
00862 case 'h':
00863 harddisk_emulation= 1;
00864 break;
00865 case 'l':
00866 label = optarg;
00867 break;
00868 case 'r':
00869 remove_after = 1;
00870 break;
00871 case 'b':
00872 bootimage = optarg;
00873 if((bootfd = open(bootimage, O_RDONLY)) < 0) {
00874 perror(bootimage);
00875 return 1;
00876 }
00877 break;
00878 }
00879 }
00880
00881 argc -= optind;
00882 argv += optind;
00883
00884 if(argc != 2) {
00885 fprintf(stderr, "usage: %s [-l <label>] [-b <bootfloppyimage>] <dir> <isofile>\n",
00886 prog);
00887 return 1;
00888 }
00889
00890
00891
00892 if((fd=open(argv[1], O_WRONLY | O_TRUNC | O_CREAT, 0600)) < 0) {
00893 perror(argv[1]);
00894 return 1;
00895 }
00896
00897
00898
00899 if(chdir(argv[0]) < 0) {
00900 perror(argv[0]);
00901 return 1;
00902 }
00903
00904
00905
00906 fprintf(stderr, " * traversing input tree\n");
00907
00908 maketree(&root, "", 1);
00909
00910 fprintf(stderr, " * writing initial zeroes and pvd\n");
00911
00912
00913
00914 memset(block, 0, sizeof(block));
00915
00916 for(i = 0; i < 16; i++)
00917 writesector(fd, block, ¤tsector);
00918
00919
00920 memset(&pvd, 0, sizeof(pvd));
00921 pvd.one = 1;
00922 pvd.set[0] = 67;
00923 pvd.set[1] = 68;
00924 pvd.set[2] = 48;
00925 pvd.set[3] = 48;
00926 pvd.set[4] = 49;
00927 pvd.set[5] = 1;
00928 pvd.set[5] = 1;
00929
00930 strncpy(pvd.volume, label, sizeof(pvd.volume)-1);
00931 for(i = strlen(pvd.volume); i < sizeof(pvd.volume); i++)
00932 pvd.volume[i] = ' ';
00933 for(i = 0; i < sizeof(pvd.system); i++)
00934 pvd.system[i] = ' ';
00935
00936 both16((unsigned char *) pvd.setsize, 1);
00937 both16((unsigned char *) pvd.seq, 1);
00938 both16((unsigned char *) pvd.sectorsize, ISO_SECTOR);
00939
00940
00941 time(&nowtime);
00942 now = gmtime(&nowtime);
00943 strftime(timestr, sizeof(timestr), "%Y%m%d%H%M%S000", now);
00944 memcpy(pvd.create, timestr, strlen(timestr));
00945 memcpy(pvd.modified, timestr, strlen(timestr));
00946 memcpy(pvd.effective, timestr, strlen(timestr));
00947 strcpy(pvd.expiry, "0000000000000000");
00948 pvdsector = currentsector;
00949
00950 writesector(fd, (char *) &pvd, ¤tsector);
00951
00952 if(bootimage) {
00953 fprintf(stderr, " * writing boot record volume descriptor\n");
00954 bootvolumesector = currentsector;
00955 writebootrecord(fd, ¤tsector, 0);
00956 }
00957
00958
00959 memset(block, 0, sizeof(block));
00960 block[0] = 255;
00961 block[1] = 67;
00962 block[2] = 68;
00963 block[3] = 48;
00964 block[4] = 48;
00965 block[5] = 49;
00966 block[6] = 1;
00967
00968 writesector(fd, block, ¤tsector);
00969
00970 if(bootimage) {
00971
00972 fprintf(stderr, " * writing the boot catalog\n");
00973 bootcatalogsector = currentsector;
00974 if (harddisk_emulation)
00975 system_type = get_system_type(bootfd);
00976 writebootcatalog(fd, ¤tsector, imagesector, imagesectors);
00977
00978
00979 fprintf(stderr, " * writing the boot image\n");
00980 imagesector = currentsector;
00981 imagesectors = writebootimage(bootimage, bootfd,
00982 fd, ¤tsector);
00983 fprintf(stderr, " * image: %d virtual sectors @ sector 0x%x\n",
00984 imagesectors, imagesector);
00985
00986 close(bootfd);
00987 }
00988
00989
00990
00991 filesector = currentsector;
00992 fprintf(stderr, " * writing file data\n");
00993 writedata(NULL, &root, fd, ¤tsector, 0,
00994 (struct dir *) &pvd.rootrecord, sizeof(pvd.rootrecord),
00995 remove_after);
00996
00997
00998
00999 dirsector = currentsector;
01000 fprintf(stderr, " * writing dir data\n");
01001 writedata(NULL, &root, fd, ¤tsector, 1,
01002 (struct dir *) &pvd.rootrecord, sizeof(pvd.rootrecord),
01003 remove_after);
01004 enddir = currentsector;
01005 seeksector(fd, dirsector, ¤tsector);
01006 fprintf(stderr, " * rewriting dir data\n");
01007 fflush(NULL);
01008 writedata(NULL, &root, fd, ¤tsector, 1,
01009 (struct dir *) &pvd.rootrecord, sizeof(pvd.rootrecord),
01010 remove_after);
01011 if(currentsector != enddir) {
01012 fprintf(stderr, "warning: inconsistent directories - "
01013 "I have a bug! iso may be broken.\n");
01014 }
01015
01016
01017
01018 fprintf(stderr, " * writing big-endian path table\n");
01019 bigpath = currentsector;
01020 currentsector += makepathtables(&root, 0, &pathbytes, fd);
01021
01022 fprintf(stderr, " * writing little-endian path table\n");
01023 littlepath = currentsector;
01024 currentsector += makepathtables(&root, 1, &pathbytes, fd);
01025
01026
01027
01028 nsectors = currentsector;
01029 both32((unsigned char *) pvd.sectors, nsectors);
01030
01031
01032
01033
01034 fprintf(stderr, " * rewriting pvd\n");
01035 seekwritesector(fd, pvdsector, (char *) &pvd, ¤tsector);
01036
01037 both32((unsigned char *) pvd.pathtable, pathbytes);
01038 little32((unsigned char *) &pvd.first_little_pathtable_start, littlepath);
01039 little32((unsigned char *) &pvd.first_big_pathtable_start, bigpath);
01040
01041
01042 seeksector(fd, pvdsector, ¤tsector);
01043 Lseek(fd, (int)((char *) &pvd.rootrecord - (char *) &pvd), SEEK_CUR);
01044 if(write_direntry(CURRENTDIR, root.startsector, root.bytesize,
01045 root.isdir, fd) > sizeof(pvd.rootrecord)) {
01046 fprintf(stderr, "warning: unexpectedly large root record\n");
01047 }
01048
01049 if(bootimage) {
01050 fprintf(stderr, " * rewriting boot catalog\n");
01051 seeksector(fd, bootcatalogsector, ¤tsector);
01052 writebootcatalog(fd, ¤tsector, imagesector, imagesectors);
01053
01054
01055 fprintf(stderr, " * rewriting the boot rvd\n");
01056 seeksector(fd, bootvolumesector, ¤tsector);
01057 writebootrecord(fd, ¤tsector, bootcatalogsector);
01058 }
01059
01060 fprintf(stderr, " * all ok\n");
01061
01062 return 0;
01063 }
01064
01065 int get_system_type(int fd)
01066 {
01067 off_t old_pos;
01068 size_t size;
01069 ssize_t r;
01070 int type;
01071 struct part_entry *partp;
01072 unsigned char bootsector[512];
01073
01074 errno= 0;
01075 old_pos= lseek(fd, SEEK_SET, 0);
01076 if (old_pos == -1 && errno != 0)
01077 {
01078 fprintf(stderr, "bootimage file is not seekable: %s\n",
01079 strerror(errno));
01080 exit(1);
01081 }
01082 size= sizeof(bootsector);
01083 r= read(fd, bootsector, size);
01084 if (r != size)
01085 {
01086 fprintf(stderr, "error reading bootimage file: %s\n",
01087 r < 0 ? strerror(errno) : "unexpected EOF");
01088 exit(1);
01089 }
01090 if (bootsector[size-2] != 0x55 && bootsector[size-1] != 0xAA)
01091 {
01092 fprintf(stderr, "bad magic in bootimage file\n");
01093 exit(1);
01094 }
01095
01096 partp= (struct part_entry *)&bootsector[PART_TABLE_OFF];
01097 type= partp->sysind;
01098 if (type == NO_PART)
01099 {
01100 fprintf(stderr, "first partition table entry is unused\n");
01101 exit(1);
01102 }
01103 if (!(partp->bootind & ACTIVE_FLAG))
01104 {
01105 fprintf(stderr, "first partition table entry is not active\n");
01106 exit(1);
01107 }
01108
01109 lseek(fd, SEEK_SET, old_pos);
01110 return type;
01111 }