Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygencdmake.c
Go to the documentation of this file.
00001 /* 00002 * CD-ROM Maker 00003 * by Philip J. Erdelsky 00004 * pje@acm.org 00005 * http://www.alumni.caltech.edu/~pje/ 00006 * 00007 * ElTorito-Support 00008 * by Eric Kohl 00009 * 00010 * Linux port 00011 * by Casper S. Hornstrup 00012 * chorns@users.sourceforge.net 00013 * 00014 * Joliet support 00015 * by Filip Navara 00016 * xnavara@volny.cz 00017 * Limitations: 00018 * - No Joliet file name validations 00019 * - Very bad ISO file name generation 00020 * 00021 * 00022 * convert long filename to iso9660 file name by Magnus Olsen 00023 * magnus@greatlord.com 00024 * 00025 * $Id: cdmake.c 54866 2012-01-07 17:45:26Z tfaber $ 00026 */ 00027 00028 /* According to his website, this file was released into the public domain by Phillip J. Erdelsky */ 00029 00030 #include <stdio.h> 00031 #include <fcntl.h> 00032 #include <sys/stat.h> 00033 #include <stdarg.h> 00034 #include <stdlib.h> 00035 #include <string.h> 00036 #ifdef _WIN32 00037 # include <io.h> 00038 # include <dos.h> 00039 #else 00040 # if defined(__FreeBSD__) || defined(__APPLE__) 00041 # include <sys/uio.h> 00042 # else 00043 # include <sys/io.h> 00044 # endif // __FreeBSD__ 00045 # include <errno.h> 00046 # include <sys/types.h> 00047 # include <dirent.h> 00048 # include <unistd.h> 00049 #endif // _WIN32 00050 #include <ctype.h> 00051 #include <setjmp.h> 00052 #include <time.h> 00053 #ifndef _WIN32 00054 #ifndef MAX_PATH 00055 #define MAX_PATH 260 00056 #endif 00057 #define DIR_SEPARATOR_CHAR '/' 00058 #define DIR_SEPARATOR_STRING "/" 00059 #else 00060 #define DIR_SEPARATOR_CHAR '\\' 00061 #define DIR_SEPARATOR_STRING "\\" 00062 #endif 00063 00064 typedef unsigned char BYTE; 00065 typedef unsigned short WORD; 00066 typedef unsigned long DWORD; 00067 typedef int BOOL; 00068 00069 const BOOL TRUE = 1; 00070 const BOOL FALSE = 0; 00071 00072 // file system parameters 00073 00074 #define MAX_LEVEL 8 00075 #define MAX_NAME_LENGTH 64 00076 #define MAX_CDNAME_LENGTH 8 00077 #define MAX_EXTENSION_LENGTH 10 00078 #define MAX_CDEXTENSION_LENGTH 3 00079 #define SECTOR_SIZE 2048 00080 #define BUFFER_SIZE (8 * SECTOR_SIZE) 00081 00082 const BYTE HIDDEN_FLAG = 1; 00083 const BYTE DIRECTORY_FLAG = 2; 00084 00085 00086 struct cd_image 00087 { 00088 FILE *file; 00089 DWORD sector; // sector to receive next byte 00090 int offset; // offset of next byte in sector 00091 int count; // number of bytes in buffer 00092 char filespecs[128]; 00093 BYTE *buffer; 00094 }; 00095 00096 typedef struct date_and_time 00097 { 00098 BYTE second; 00099 BYTE minute; 00100 BYTE hour; 00101 BYTE day; 00102 BYTE month; 00103 WORD year; 00104 } DATE_AND_TIME, *PDATE_AND_TIME; 00105 00106 typedef struct directory_record 00107 { 00108 struct directory_record *next_in_directory; 00109 struct directory_record *next_in_path_table; /* directory record only */ 00110 struct directory_record *next_in_memory; 00111 struct directory_record *first_record; /* directory record only */ 00112 struct directory_record *parent; 00113 BYTE flags; 00114 char name[MAX_NAME_LENGTH+1]; 00115 char name_on_cd[MAX_CDNAME_LENGTH+1]; 00116 char extension[MAX_EXTENSION_LENGTH+1]; 00117 char extension_on_cd[MAX_CDEXTENSION_LENGTH+1]; 00118 char *joliet_name; 00119 DATE_AND_TIME date_and_time; 00120 DWORD sector; 00121 DWORD size; 00122 DWORD joliet_sector; 00123 DWORD joliet_size; 00124 unsigned level; /* directory record only */ 00125 WORD path_table_index; /* directory record only */ 00126 } DIR_RECORD, *PDIR_RECORD; 00127 00128 00129 typedef enum directory_record_type 00130 { 00131 DOT_RECORD, 00132 DOT_DOT_RECORD, 00133 SUBDIRECTORY_RECORD, 00134 FILE_RECORD 00135 } DIR_RECORD_TYPE, *PDIR_RECORD_TYPE; 00136 00137 00138 PDIR_RECORD sort_linked_list(PDIR_RECORD, 00139 unsigned, int (*)(PDIR_RECORD, PDIR_RECORD)); 00140 00141 00142 static char DIRECTORY_TIMESTAMP[] = "~Y$'KOR$.3K&"; 00143 00144 static jmp_buf error; 00145 static struct cd_image cd; 00146 00147 char volume_label[32]; 00148 DIR_RECORD root; 00149 char source[512]; 00150 char *end_source; 00151 enum {QUIET, NORMAL, VERBOSE} verbosity; 00152 BOOL show_progress; 00153 DWORD size_limit; 00154 BOOL accept_punctuation_marks; 00155 00156 DWORD total_sectors; 00157 DWORD path_table_size; 00158 DWORD little_endian_path_table_sector; 00159 DWORD big_endian_path_table_sector; 00160 DWORD number_of_files; 00161 DWORD bytes_in_files; 00162 DWORD unused_bytes_at_ends_of_files; 00163 DWORD number_of_directories; 00164 DWORD bytes_in_directories; 00165 00166 char bootimage[512]; 00167 BOOL eltorito; 00168 DWORD boot_catalog_sector; 00169 DWORD boot_image_sector; 00170 WORD boot_image_size; // counted in 512 byte sectors 00171 00172 BOOL joliet; 00173 DWORD joliet_path_table_size; 00174 DWORD joliet_little_endian_path_table_sector; 00175 DWORD joliet_big_endian_path_table_sector; 00176 00177 /*----------------------------------------------------------------------------- 00178 This function edits a 32-bit unsigned number into a comma-delimited form, such 00179 as 4,294,967,295 for the largest possible number, and returns a pointer to a 00180 static buffer containing the result. It suppresses leading zeros and commas, 00181 but optionally pads the result with blanks at the left so the result is always 00182 exactly 13 characters long (excluding the terminating zero). 00183 00184 CAUTION: A statement containing more than one call on this function, such as 00185 printf("%s, %s", edit_with_commas(a), edit_with_commas(b)), will produce 00186 incorrect results because all calls use the same static bufffer. 00187 -----------------------------------------------------------------------------*/ 00188 00189 static char *edit_with_commas(DWORD x, BOOL pad) 00190 { 00191 static char s[14]; 00192 unsigned i = 13; 00193 do 00194 { 00195 if (i % 4 == 2) s[--i] = ','; 00196 s[--i] = (char)(x % 10 + '0'); 00197 } while ((x/=10) != 0); 00198 if (pad) 00199 { 00200 while (i > 0) s[--i] = ' '; 00201 } 00202 return s + i; 00203 } 00204 00205 /*----------------------------------------------------------------------------- 00206 This function releases all allocated memory blocks. 00207 -----------------------------------------------------------------------------*/ 00208 00209 static void release_memory(void) 00210 { 00211 while (root.next_in_memory != NULL) 00212 { 00213 struct directory_record *next = 00214 root.next_in_memory->next_in_memory; 00215 if (joliet) 00216 free (root.joliet_name); 00217 free (root.next_in_memory); 00218 root.next_in_memory = next; 00219 } 00220 if (cd.buffer != NULL) 00221 { 00222 free (cd.buffer); 00223 cd.buffer = NULL; 00224 } 00225 } 00226 00227 /*----------------------------------------------------------------------------- 00228 This function edits and displays an error message and then jumps back to the 00229 error exit point in main(). 00230 -----------------------------------------------------------------------------*/ 00231 00232 void error_exit ( const char* fmt, ... ) 00233 { 00234 va_list arg; 00235 00236 va_start(arg, fmt); 00237 vprintf(fmt, arg); 00238 va_end(arg); 00239 printf("\n"); 00240 if (cd.file != NULL) 00241 fclose(cd.file); 00242 release_memory(); 00243 exit(1); 00244 } 00245 00246 /*----------------------------------------------------------------------------- 00247 This function, which is called only on the second pass, and only when the 00248 buffer is not empty, flushes the buffer to the CD-ROM image. 00249 -----------------------------------------------------------------------------*/ 00250 00251 static void flush_buffer(void) 00252 { 00253 if (fwrite(cd.buffer, cd.count, 1, cd.file) < 1) 00254 error_exit("File write error"); 00255 cd.count = 0; 00256 if (show_progress) 00257 { 00258 printf("\r%s ", 00259 edit_with_commas((total_sectors - cd.sector) * SECTOR_SIZE, TRUE)); 00260 } 00261 } 00262 00263 /*----------------------------------------------------------------------------- 00264 This function writes a single byte to the CD-ROM image. On the first pass (in 00265 which cd.handle < 0), it does not actually write anything but merely updates 00266 the file pointer as though the byte had been written. 00267 -----------------------------------------------------------------------------*/ 00268 00269 static void write_byte(BYTE x) 00270 { 00271 if (cd.file != NULL) 00272 { 00273 cd.buffer[cd.count] = x; 00274 if (++cd.count == BUFFER_SIZE) 00275 flush_buffer(); 00276 } 00277 if (++cd.offset == SECTOR_SIZE) 00278 { 00279 cd.sector++; 00280 cd.offset = 0; 00281 } 00282 } 00283 00284 /*----------------------------------------------------------------------------- 00285 These functions write a word or double word to the CD-ROM image with the 00286 specified endianity. 00287 -----------------------------------------------------------------------------*/ 00288 00289 static void write_little_endian_word(WORD x) 00290 { 00291 write_byte((BYTE)x); 00292 write_byte((BYTE)(x >> 8)); 00293 } 00294 00295 static void write_big_endian_word(WORD x) 00296 { 00297 write_byte((BYTE)(x >> 8)); 00298 write_byte((BYTE)x); 00299 } 00300 00301 static void write_both_endian_word(WORD x) 00302 { 00303 write_little_endian_word(x); 00304 write_big_endian_word(x); 00305 } 00306 00307 static void write_little_endian_dword(DWORD x) 00308 { 00309 write_byte((BYTE)x); 00310 write_byte((BYTE)(x >> 8)); 00311 write_byte((BYTE)(x >> 16)); 00312 write_byte((BYTE)(x >> 24)); 00313 } 00314 00315 static void write_big_endian_dword(DWORD x) 00316 { 00317 write_byte((BYTE)(x >> 24)); 00318 write_byte((BYTE)(x >> 16)); 00319 write_byte((BYTE)(x >> 8)); 00320 write_byte((BYTE)x); 00321 } 00322 00323 static void write_both_endian_dword(DWORD x) 00324 { 00325 write_little_endian_dword(x); 00326 write_big_endian_dword(x); 00327 } 00328 00329 /*----------------------------------------------------------------------------- 00330 This function writes enough zeros to fill out the end of a sector, and leaves 00331 the file pointer at the beginning of the next sector. If the file pointer is 00332 already at the beginning of a sector, it writes nothing. 00333 -----------------------------------------------------------------------------*/ 00334 00335 static void fill_sector(void) 00336 { 00337 while (cd.offset != 0) 00338 write_byte(0); 00339 } 00340 00341 /*----------------------------------------------------------------------------- 00342 This function writes a string to the CD-ROM image. The terminating \0 is not 00343 written. 00344 -----------------------------------------------------------------------------*/ 00345 00346 static void write_string(char *s) 00347 { 00348 while (*s != 0) 00349 write_byte(*s++); 00350 } 00351 00352 /*----------------------------------------------------------------------------- 00353 This function writes a ansi string as a big endian unicode string to the CD-ROM 00354 image. The terminating \0 is not written. 00355 -----------------------------------------------------------------------------*/ 00356 00357 static void write_string_as_big_endian_unicode(char *s) 00358 { 00359 while (*s != 0) 00360 { 00361 write_byte(0); 00362 write_byte(*s++); 00363 } 00364 } 00365 00366 /*----------------------------------------------------------------------------- 00367 This function writes a block of identical bytes to the CD-ROM image. 00368 -----------------------------------------------------------------------------*/ 00369 00370 static void write_block(unsigned count, BYTE value) 00371 { 00372 while (count != 0) 00373 { 00374 write_byte(value); 00375 count--; 00376 } 00377 } 00378 00379 /*----------------------------------------------------------------------------- 00380 This function writes a block of identical bige endian words to the CD-ROM image. 00381 -----------------------------------------------------------------------------*/ 00382 00383 static void write_word_block(unsigned count, WORD value) 00384 { 00385 while (count != 0) 00386 { 00387 write_big_endian_word(value); 00388 count--; 00389 } 00390 } 00391 00392 /*----------------------------------------------------------------------------- 00393 This function writes a directory record to the CD_ROM image. 00394 -----------------------------------------------------------------------------*/ 00395 00396 static void 00397 write_directory_record(PDIR_RECORD d, 00398 DIR_RECORD_TYPE DirType, 00399 BOOL joliet) 00400 { 00401 unsigned identifier_size; 00402 unsigned record_size; 00403 00404 if (joliet) 00405 { 00406 if (DirType == DOT_RECORD || DirType == DOT_DOT_RECORD) 00407 identifier_size = 1; 00408 else 00409 identifier_size = strlen(d->joliet_name) * 2; 00410 } 00411 else 00412 { 00413 switch (DirType) 00414 { 00415 case DOT_RECORD: 00416 case DOT_DOT_RECORD: 00417 identifier_size = 1; 00418 break; 00419 case SUBDIRECTORY_RECORD: 00420 /*printf ( "Subdir: %s\n", d->name_on_cd );*/ 00421 identifier_size = strlen(d->name_on_cd); 00422 break; 00423 case FILE_RECORD: 00424 /*printf ( "File: %s.%s -> %s.%s\n", d->name, d->extension, d->name_on_cd, d->extension_on_cd );*/ 00425 identifier_size = strlen(d->name_on_cd) + 2; 00426 if (d->extension_on_cd[0] != 0) 00427 identifier_size += 1 + strlen(d->extension_on_cd); 00428 break; 00429 default: 00430 identifier_size = 1; 00431 break; 00432 } 00433 } 00434 record_size = 33 + identifier_size; 00435 if ((identifier_size & 1) == 0) 00436 record_size++; 00437 if (cd.offset + record_size > SECTOR_SIZE) 00438 fill_sector(); 00439 write_byte((BYTE)record_size); 00440 write_byte(0); // number of sectors in extended attribute record 00441 if (joliet) 00442 { 00443 write_both_endian_dword(d->joliet_sector); 00444 write_both_endian_dword(d->joliet_size); 00445 } 00446 else 00447 { 00448 write_both_endian_dword(d->sector); 00449 write_both_endian_dword(d->size); 00450 } 00451 write_byte((BYTE)(d->date_and_time.year - 1900)); 00452 write_byte(d->date_and_time.month); 00453 write_byte(d->date_and_time.day); 00454 write_byte(d->date_and_time.hour); 00455 write_byte(d->date_and_time.minute); 00456 write_byte(d->date_and_time.second); 00457 write_byte(0); // GMT offset 00458 write_byte(d->flags); 00459 write_byte(0); // file unit size for an interleaved file 00460 write_byte(0); // interleave gap size for an interleaved file 00461 write_both_endian_word((WORD) 1); // volume sequence number 00462 write_byte((BYTE)identifier_size); 00463 switch (DirType) 00464 { 00465 case DOT_RECORD: 00466 write_byte(0); 00467 break; 00468 case DOT_DOT_RECORD: 00469 write_byte(1); 00470 break; 00471 case SUBDIRECTORY_RECORD: 00472 if (joliet) 00473 write_string_as_big_endian_unicode(d->joliet_name); 00474 else 00475 write_string(d->name_on_cd); 00476 break; 00477 case FILE_RECORD: 00478 if (joliet) 00479 { 00480 write_string_as_big_endian_unicode(d->joliet_name); 00481 } 00482 else 00483 { 00484 write_string(d->name_on_cd); 00485 if (d->extension_on_cd[0] != 0) 00486 { 00487 write_byte('.'); 00488 write_string(d->extension_on_cd); 00489 } 00490 write_string(";1"); 00491 } 00492 break; 00493 } 00494 if ((identifier_size & 1) == 0) 00495 write_byte(0); 00496 } 00497 00498 /*----------------------------------------------------------------------------- 00499 This function converts the date and time words from an ffblk structure and 00500 puts them into a date_and_time structure. 00501 -----------------------------------------------------------------------------*/ 00502 00503 static void convert_date_and_time(PDATE_AND_TIME dt, time_t *time) 00504 { 00505 struct tm *timedef; 00506 00507 timedef = localtime(time); 00508 00509 dt->second = timedef->tm_sec; 00510 dt->minute = timedef->tm_min; 00511 dt->hour = timedef->tm_hour; 00512 dt->day = timedef->tm_mday; 00513 dt->month = timedef->tm_mon + 1; 00514 dt->year = timedef->tm_year + 1900; 00515 } 00516 00517 /*----------------------------------------------------------------------------- 00518 This function checks the specified character, if necessary, and 00519 generates an error if it is a punctuation mark other than an underscore. 00520 It also converts small letters to capital letters and returns the 00521 result. 00522 -----------------------------------------------------------------------------*/ 00523 00524 static int check_for_punctuation(int c, const char *name) 00525 { 00526 c = toupper(c & 0xFF); 00527 if (!accept_punctuation_marks && !isalnum(c) && c != '_') 00528 error_exit("Punctuation mark in %s", name); 00529 return c; 00530 } 00531 00532 #if _WIN32 00533 #define strcasecmp stricmp 00534 #endif//_WIN32 00535 00536 /*----------------------------------------------------------------------------- 00537 This function checks to see if there's a cdname conflict. 00538 -----------------------------------------------------------------------------*/ 00539 00540 int cdname_exists ( PDIR_RECORD d ) 00541 { 00542 PDIR_RECORD p = d->parent->first_record; 00543 while ( p ) 00544 { 00545 if ( p != d 00546 && !strcasecmp ( p->name_on_cd, d->name_on_cd ) 00547 && !strcasecmp ( p->extension_on_cd, d->extension_on_cd ) ) 00548 return 1; 00549 p = p->next_in_directory; 00550 } 00551 return 0; 00552 } 00553 00554 void parse_filename_into_dirrecord ( const char* filename, PDIR_RECORD d, BOOL dir ) 00555 { 00556 const char *s = filename; 00557 char *t = d->name_on_cd; 00558 char *n = d->name; 00559 int joliet_length; 00560 int filename_counter; 00561 filename_counter = 1; 00562 while (*s != 0) 00563 { 00564 if (*s == '.') 00565 { 00566 s++; 00567 break; 00568 } 00569 00570 if ( (size_t)(t-d->name_on_cd) < sizeof(d->name_on_cd)-1 ) 00571 *t++ = check_for_punctuation(*s, filename); 00572 else if (!joliet) 00573 error_exit ("'%s' is not ISO-9660, aborting...", filename ); 00574 if ( (size_t)(n-d->name) < sizeof(d->name)-1 ) 00575 *n++ = *s; 00576 else if (!joliet) 00577 error_exit ( "'%s' is not ISO-9660, aborting...", filename ); 00578 s++; 00579 } 00580 if (strlen(s) > MAX_EXTENSION_LENGTH) 00581 { 00582 error_exit ( "'%s' has too long extension for cdmake, aborting...", filename ); 00583 } 00584 *t = 0; 00585 strcpy(d->extension, s); 00586 t = d->extension_on_cd; 00587 while ( *s != 0 ) 00588 { 00589 if ( (size_t)(t-d->extension_on_cd) < sizeof(d->extension_on_cd)-1 ) 00590 *t++ = check_for_punctuation(*s, filename); 00591 else if (!joliet) 00592 error_exit ( "'%s' is not ISO-9660, aborting...", filename ); 00593 s++; 00594 } 00595 *t = 0; 00596 *n = 0; 00597 00598 if ( dir ) 00599 { 00600 if (d->extension[0] != 0) 00601 { 00602 if (!joliet) 00603 error_exit("Directory with extension %s", filename); 00604 } 00605 d->flags = DIRECTORY_FLAG; 00606 } else 00607 d->flags = 0; 00608 00609 00610 filename_counter = 1; 00611 while ( cdname_exists ( d ) ) 00612 { 00613 00614 // the file name must be least 8 char long 00615 if (strlen(d->name_on_cd)<8) 00616 error_exit ( "'%s' is a duplicate file name, aborting...", filename ); 00617 00618 if ((d->name_on_cd[8] == '.') && (strlen(d->name_on_cd) < 13)) 00619 error_exit ( "'%s' is a duplicate file name, aborting...", filename ); 00620 00621 // max 255 times for equal short filename 00622 if (filename_counter>255) error_exit ( "'%s' is a duplicate file name, aborting...", filename ); 00623 d->name_on_cd[8] = '~'; 00624 memset(&d->name_on_cd[9],0,5); 00625 sprintf(&d->name_on_cd[9],"%d",filename_counter); 00626 filename_counter++; 00627 00628 } 00629 00630 if ( joliet ) 00631 { 00632 joliet_length = strlen(filename); 00633 if (joliet_length > 64) 00634 error_exit ( "'%s' is not Joliet, aborting...", filename ); 00635 d->joliet_name = malloc(joliet_length + 1); 00636 if (d->joliet_name == NULL) 00637 error_exit("Insufficient memory"); 00638 strcpy(d->joliet_name, filename); 00639 } 00640 } 00641 00642 /*----------------------------------------------------------------------------- 00643 This function creates a new directory record with the information from the 00644 specified ffblk. It links it into the beginning of the directory list 00645 for the specified parent and returns a pointer to the new record. 00646 -----------------------------------------------------------------------------*/ 00647 00648 #if _WIN32 00649 00650 /* Win32 version */ 00651 PDIR_RECORD 00652 new_directory_record (struct _finddata_t *f, 00653 PDIR_RECORD parent) 00654 { 00655 PDIR_RECORD d; 00656 00657 d = malloc(sizeof(DIR_RECORD)); 00658 if (d == NULL) 00659 error_exit("Insufficient memory"); 00660 memset ( d, 0, sizeof(DIR_RECORD) ); 00661 d->next_in_memory = root.next_in_memory; 00662 root.next_in_memory = d; 00663 00664 /* I need the parent set before calling parse_filename_into_dirrecord(), 00665 because that functions checks for duplicate file names*/ 00666 d->parent = parent; 00667 parse_filename_into_dirrecord ( f->name, d, f->attrib & _A_SUBDIR ); 00668 00669 convert_date_and_time(&d->date_and_time, &f->time_write); 00670 d->flags |= f->attrib & _A_HIDDEN ? HIDDEN_FLAG : 0; 00671 d->size = d->joliet_size = f->size; 00672 d->next_in_directory = parent->first_record; 00673 parent->first_record = d; 00674 return d; 00675 } 00676 00677 #else 00678 00679 /* Linux version */ 00680 PDIR_RECORD 00681 new_directory_record (struct dirent *entry, 00682 struct stat *stbuf, 00683 PDIR_RECORD parent) 00684 { 00685 PDIR_RECORD d; 00686 /* 00687 char *s; 00688 char *t; 00689 char *n; 00690 */ 00691 00692 d = malloc(sizeof(DIR_RECORD)); 00693 if (d == NULL) 00694 error_exit("Insufficient memory"); 00695 memset ( d, 0, sizeof(DIR_RECORD) ); 00696 d->next_in_memory = root.next_in_memory; 00697 root.next_in_memory = d; 00698 00699 /* I need the parent set before calling parse_filename_into_dirrecord(), 00700 because that functions checks for duplicate file names*/ 00701 d->parent = parent; 00702 #ifdef HAVE_D_TYPE 00703 parse_filename_into_dirrecord ( entry->d_name, d, entry->d_type == DT_DIR ); 00704 #else 00705 parse_filename_into_dirrecord ( entry->d_name, d, S_ISDIR(stbuf->st_mode) ); 00706 #endif 00707 00708 convert_date_and_time(&d->date_and_time, &stbuf->st_mtime); 00709 d->flags |= entry->d_name[0] == '.' ? HIDDEN_FLAG : 0; 00710 d->size = d->joliet_size = stbuf->st_size; 00711 d->next_in_directory = parent->first_record; 00712 parent->first_record = d; 00713 return d; 00714 } 00715 00716 #endif 00717 00718 /*----------------------------------------------------------------------------- 00719 This function compares two directory records according to the ISO9660 rules 00720 for directory sorting and returns a negative value if p is before q, or a 00721 positive value if p is after q. 00722 -----------------------------------------------------------------------------*/ 00723 00724 static int compare_directory_order(PDIR_RECORD p, PDIR_RECORD q) 00725 { 00726 int n = strcmp(p->name_on_cd, q->name_on_cd); 00727 if (n == 0) 00728 n = strcmp(p->extension_on_cd, q->extension_on_cd); 00729 return n; 00730 } 00731 00732 /*----------------------------------------------------------------------------- 00733 This function compares two directory records (which must represent 00734 directories) according to the ISO9660 rules for path table sorting and returns 00735 a negative value if p is before q, or a positive vlaue if p is after q. 00736 -----------------------------------------------------------------------------*/ 00737 00738 static int compare_path_table_order(PDIR_RECORD p, PDIR_RECORD q) 00739 { 00740 int n = p->level - q->level; 00741 if (p == q) 00742 return 0; 00743 if (n == 0) 00744 { 00745 n = compare_path_table_order(p->parent, q->parent); 00746 if (n == 0) 00747 n = compare_directory_order(p, q); 00748 } 00749 return n; 00750 } 00751 00752 /*----------------------------------------------------------------------------- 00753 This function appends the specified string to the buffer source[]. 00754 -----------------------------------------------------------------------------*/ 00755 00756 static void append_string_to_source(char *s) 00757 { 00758 while (*s != 0) 00759 *end_source++ = *s++; 00760 } 00761 00762 /*----------------------------------------------------------------------------- 00763 This function scans all files from the current source[] (which must end in \, 00764 and represents a directory already in the database as d), 00765 and puts the appropriate directory records into the database in memory, with 00766 the specified root. It calls itself recursively to scan all subdirectories. 00767 -----------------------------------------------------------------------------*/ 00768 00769 #ifdef _WIN32 00770 00771 static void 00772 make_directory_records (PDIR_RECORD d) 00773 { 00774 PDIR_RECORD new_d; 00775 struct _finddata_t f; 00776 char *old_end_source; 00777 int findhandle; 00778 00779 d->first_record = NULL; 00780 strcpy(end_source, "*.*"); 00781 00782 findhandle =_findfirst(source, &f); 00783 if (findhandle != 0) 00784 { 00785 do 00786 { 00787 if ((f.attrib & (_A_HIDDEN | _A_SUBDIR)) == 0 && f.name[0] != '.') 00788 { 00789 if (strcmp(f.name, DIRECTORY_TIMESTAMP) == 0) 00790 { 00791 convert_date_and_time(&d->date_and_time, &f.time_write); 00792 } 00793 else 00794 { 00795 if (verbosity == VERBOSE) 00796 { 00797 old_end_source = end_source; 00798 strcpy(end_source, f.name); 00799 printf("%d: file %s\n", d->level, source); 00800 end_source = old_end_source; 00801 } 00802 (void) new_directory_record(&f, d); 00803 } 00804 } 00805 } 00806 while (_findnext(findhandle, &f) == 0); 00807 00808 _findclose(findhandle); 00809 } 00810 00811 strcpy(end_source, "*.*"); 00812 findhandle= _findfirst(source, &f); 00813 if (findhandle) 00814 { 00815 do 00816 { 00817 if (f.attrib & _A_SUBDIR && f.name[0] != '.') 00818 { 00819 old_end_source = end_source; 00820 append_string_to_source(f.name); 00821 *end_source++ = DIR_SEPARATOR_CHAR; 00822 if (verbosity == VERBOSE) 00823 { 00824 *end_source = 0; 00825 printf("%d: directory %s\n", d->level + 1, source); 00826 } 00827 if (d->level < MAX_LEVEL) 00828 { 00829 new_d = new_directory_record(&f, d); 00830 new_d->next_in_path_table = root.next_in_path_table; 00831 root.next_in_path_table = new_d; 00832 new_d->level = d->level + 1; 00833 make_directory_records(new_d); 00834 } 00835 else 00836 { 00837 error_exit("Directory is nested too deep"); 00838 } 00839 end_source = old_end_source; 00840 } 00841 } 00842 while (_findnext(findhandle, &f) == 0); 00843 00844 _findclose(findhandle); 00845 } 00846 00847 // sort directory 00848 d->first_record = sort_linked_list(d->first_record, 0, compare_directory_order); 00849 } 00850 00851 #else 00852 00853 /* Linux version */ 00854 static void 00855 make_directory_records (PDIR_RECORD d) 00856 { 00857 PDIR_RECORD new_d; 00858 DIR *dirp; 00859 struct dirent *entry; 00860 char *old_end_source; 00861 struct stat stbuf; 00862 char buf[MAX_PATH]; 00863 00864 d->first_record = NULL; 00865 00866 #ifdef HAVE_D_TYPE 00867 dirp = opendir(source); 00868 if (dirp != NULL) 00869 { 00870 while ((entry = readdir (dirp)) != NULL) 00871 { 00872 if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) 00873 continue; // skip self and parent 00874 00875 if (entry->d_type == DT_REG) // normal file 00876 { 00877 // Check for an absolute path 00878 if (source[0] == DIR_SEPARATOR_CHAR) 00879 { 00880 strcpy(buf, source); 00881 strcat(buf, DIR_SEPARATOR_STRING); 00882 strcat(buf, entry->d_name); 00883 } 00884 else 00885 { 00886 if (!getcwd(buf, sizeof(buf))) 00887 error_exit("Can't get CWD: %s\n", strerror(errno)); 00888 strcat(buf, DIR_SEPARATOR_STRING); 00889 strcat(buf, source); 00890 strcat(buf, entry->d_name); 00891 } 00892 00893 if (stat(buf, &stbuf) == -1) 00894 { 00895 error_exit("Can't access '%s' (%s)\n", buf, strerror(errno)); 00896 return; 00897 } 00898 00899 if (strcmp(entry->d_name, DIRECTORY_TIMESTAMP) == 0) 00900 { 00901 convert_date_and_time(&d->date_and_time, &stbuf.st_ctime); 00902 } 00903 else 00904 { 00905 if (verbosity == VERBOSE) 00906 { 00907 printf("%d: file %s\n", d->level, buf); 00908 } 00909 (void) new_directory_record(entry, &stbuf, d); 00910 } 00911 } 00912 } 00913 closedir(dirp); 00914 } 00915 else 00916 { 00917 error_exit("Can't open %s\n", source); 00918 return; 00919 } 00920 00921 dirp = opendir(source); 00922 if (dirp != NULL) 00923 { 00924 while ((entry = readdir (dirp)) != NULL) 00925 { 00926 if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) 00927 continue; // skip self and parent 00928 00929 if (entry->d_type == DT_DIR) // directory 00930 { 00931 old_end_source = end_source; 00932 append_string_to_source(entry->d_name); 00933 *end_source++ = DIR_SEPARATOR_CHAR; 00934 *end_source = 0; 00935 if (verbosity == VERBOSE) 00936 { 00937 printf("%d: directory %s\n", d->level + 1, source); 00938 } 00939 if (d->level < MAX_LEVEL) 00940 { 00941 // Check for an absolute path 00942 if (source[0] == DIR_SEPARATOR_CHAR) 00943 { 00944 strcpy(buf, source); 00945 } 00946 else 00947 { 00948 if (!getcwd(buf, sizeof(buf))) 00949 error_exit("Can't get CWD: %s\n", strerror(errno)); 00950 strcat(buf, DIR_SEPARATOR_STRING); 00951 strcat(buf, source); 00952 } 00953 00954 if (stat(buf, &stbuf) == -1) 00955 { 00956 error_exit("Can't access '%s' (%s)\n", buf, strerror(errno)); 00957 return; 00958 } 00959 new_d = new_directory_record(entry, &stbuf, d); 00960 new_d->next_in_path_table = root.next_in_path_table; 00961 root.next_in_path_table = new_d; 00962 new_d->level = d->level + 1; 00963 make_directory_records(new_d); 00964 } 00965 else 00966 { 00967 error_exit("Directory is nested too deep"); 00968 } 00969 end_source = old_end_source; 00970 *end_source = 0; 00971 } 00972 } 00973 closedir(dirp); 00974 } 00975 else 00976 { 00977 error_exit("Can't open %s\n", source); 00978 return; 00979 } 00980 00981 #else 00982 00983 dirp = opendir(source); 00984 if (dirp != NULL) 00985 { 00986 while ((entry = readdir (dirp)) != NULL) 00987 { 00988 if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) 00989 continue; // skip self and parent 00990 00991 // Check for an absolute path 00992 if (source[0] == DIR_SEPARATOR_CHAR) 00993 { 00994 strcpy(buf, source); 00995 strcat(buf, DIR_SEPARATOR_STRING); 00996 strcat(buf, entry->d_name); 00997 } 00998 else 00999 { 01000 if (!getcwd(buf, sizeof(buf))) 01001 error_exit("Can't get CWD: %s\n", strerror(errno)); 01002 strcat(buf, DIR_SEPARATOR_STRING); 01003 strcat(buf, source); 01004 strcat(buf, entry->d_name); 01005 } 01006 01007 if (stat(buf, &stbuf) == -1) 01008 { 01009 error_exit("Can't access '%s' (%s)\n", buf, strerror(errno)); 01010 return; 01011 } 01012 01013 if (S_ISDIR(stbuf.st_mode)) 01014 { 01015 old_end_source = end_source; 01016 append_string_to_source(entry->d_name); 01017 *end_source++ = DIR_SEPARATOR_CHAR; 01018 *end_source = 0; 01019 if (verbosity == VERBOSE) 01020 { 01021 printf("%d: directory %s\n", d->level + 1, source); 01022 } 01023 01024 if (d->level < MAX_LEVEL) 01025 { 01026 new_d = new_directory_record(entry, &stbuf, d); 01027 new_d->next_in_path_table = root.next_in_path_table; 01028 root.next_in_path_table = new_d; 01029 new_d->level = d->level + 1; 01030 make_directory_records(new_d); 01031 } 01032 else 01033 { 01034 error_exit("Directory is nested too deep"); 01035 } 01036 01037 end_source = old_end_source; 01038 *end_source = 0; 01039 } 01040 else if (S_ISREG(stbuf.st_mode)) 01041 { 01042 if (strcmp(entry->d_name, DIRECTORY_TIMESTAMP) == 0) 01043 { 01044 convert_date_and_time(&d->date_and_time, &stbuf.st_ctime); 01045 } 01046 else 01047 { 01048 if (verbosity == VERBOSE) 01049 { 01050 printf("%d: file %s\n", d->level, buf); 01051 } 01052 (void) new_directory_record(entry, &stbuf, d); 01053 } 01054 } 01055 } 01056 closedir (dirp); 01057 } 01058 else 01059 { 01060 error_exit("Can't open %s\n", source); 01061 return; 01062 } 01063 01064 #endif 01065 01066 // sort directory 01067 d->first_record = sort_linked_list(d->first_record, 0, compare_directory_order); 01068 } 01069 01070 #endif 01071 01072 /*----------------------------------------------------------------------------- 01073 This function loads the file specifications for the file or directory 01074 corresponding to the specified directory record into the source[] buffer. It 01075 is recursive. 01076 -----------------------------------------------------------------------------*/ 01077 01078 static void get_file_specifications(PDIR_RECORD d) 01079 { 01080 if (d != &root) 01081 { 01082 get_file_specifications(d->parent); 01083 if (d->joliet_name == NULL) 01084 append_string_to_source(d->name); 01085 else 01086 append_string_to_source(d->joliet_name); 01087 01088 if (((d->flags & DIRECTORY_FLAG) == 0 || joliet) && d->extension[0] != 0) 01089 { 01090 if (d->joliet_name == NULL) 01091 { 01092 *end_source++ = '.'; 01093 append_string_to_source(d->extension); 01094 } 01095 } 01096 if (d->flags & DIRECTORY_FLAG) 01097 *end_source++ = DIR_SEPARATOR_CHAR; 01098 } 01099 } 01100 01101 static void pass(void) 01102 { 01103 PDIR_RECORD d; 01104 PDIR_RECORD q; 01105 unsigned int i; 01106 char *t; 01107 unsigned int index; 01108 unsigned int name_length; 01109 DWORD size; 01110 DWORD number_of_sectors; 01111 char *old_end_source; 01112 int n; 01113 FILE *file; 01114 01115 // first 16 sectors are zeros 01116 01117 write_block(16 * SECTOR_SIZE, 0); 01118 01119 // Primary Volume Descriptor 01120 01121 write_string("\1CD001\1"); 01122 write_byte(0); 01123 write_block(32, ' '); // system identifier 01124 01125 t = volume_label; 01126 for (i = 0; i < 32; i++) 01127 write_byte( (BYTE)( (*t != 0) ? toupper(*t++) : ' ' ) ); 01128 01129 write_block(8, 0); 01130 write_both_endian_dword(total_sectors); 01131 write_block(32, 0); 01132 write_both_endian_word((WORD) 1); // volume set size 01133 write_both_endian_word((WORD) 1); // volume sequence number 01134 write_both_endian_word((WORD) 2048); // sector size 01135 write_both_endian_dword(path_table_size); 01136 write_little_endian_dword(little_endian_path_table_sector); 01137 write_little_endian_dword((DWORD) 0); // second little endian path table 01138 write_big_endian_dword(big_endian_path_table_sector); 01139 write_big_endian_dword((DWORD) 0); // second big endian path table 01140 write_directory_record(&root, DOT_RECORD, FALSE); 01141 write_block(128, ' '); // volume set identifier 01142 write_block(128, ' '); // publisher identifier 01143 write_block(128, ' '); // data preparer identifier 01144 write_block(128, ' '); // application identifier 01145 write_block(37, ' '); // copyright file identifier 01146 write_block(37, ' '); // abstract file identifier 01147 write_block(37, ' '); // bibliographic file identifier 01148 write_string("0000000000000000"); // volume creation 01149 write_byte(0); 01150 write_string("0000000000000000"); // most recent modification 01151 write_byte(0); 01152 write_string("0000000000000000"); // volume expires 01153 write_byte(0); 01154 write_string("0000000000000000"); // volume is effective 01155 write_byte(0); 01156 write_byte(1); 01157 write_byte(0); 01158 fill_sector(); 01159 01160 01161 // Boot Volume Descriptor 01162 01163 if (eltorito == TRUE) 01164 { 01165 write_byte(0); 01166 write_string("CD001\1"); 01167 write_string("EL TORITO SPECIFICATION"); // identifier 01168 write_block(9, 0); // padding 01169 write_block(32, 0); // unused 01170 write_little_endian_dword(boot_catalog_sector); // pointer to boot catalog 01171 fill_sector(); 01172 } 01173 01174 // Supplementary Volume Descriptor 01175 01176 if (joliet) 01177 { 01178 write_string("\2CD001\1"); 01179 write_byte(0); 01180 01181 write_word_block(16, L' '); // system identifier 01182 01183 t = volume_label; 01184 for (i = 0; i < 16; i++) 01185 write_big_endian_word( (BYTE)( (*t != 0) ? *t++ : ' ' ) ); 01186 01187 write_block(8, 0); 01188 write_both_endian_dword(total_sectors); 01189 write_string("%/E"); 01190 write_block(29, 0); 01191 write_both_endian_word((WORD) 1); // volume set size 01192 write_both_endian_word((WORD) 1); // volume sequence number 01193 write_both_endian_word((WORD) 2048); // sector size 01194 write_both_endian_dword(joliet_path_table_size); 01195 write_little_endian_dword(joliet_little_endian_path_table_sector); 01196 write_little_endian_dword((DWORD) 0); // second little endian path table 01197 write_big_endian_dword(joliet_big_endian_path_table_sector); 01198 write_big_endian_dword((DWORD) 0); // second big endian path table 01199 write_directory_record(&root, DOT_RECORD, TRUE); 01200 write_word_block(64, ' '); // volume set identifier 01201 write_word_block(64, ' '); // publisher identifier 01202 write_word_block(64, ' '); // data preparer identifier 01203 write_word_block(64, ' '); // application identifier 01204 write_block(37, ' '); // copyright file identifier 01205 write_block(37, ' '); // abstract file identifier 01206 write_block(37, ' '); // bibliographic file identifier 01207 write_string("0000000000000000"); // volume creation 01208 write_byte(0); 01209 write_string("0000000000000000"); // most recent modification 01210 write_byte(0); 01211 write_string("0000000000000000"); // volume expires 01212 write_byte(0); 01213 write_string("0000000000000000"); // volume is effective 01214 write_byte(0); 01215 write_byte(1); 01216 write_byte(0); 01217 fill_sector(); 01218 } 01219 01220 01221 // Volume Descriptor Set Terminator 01222 write_string("\377CD001\1"); 01223 fill_sector(); 01224 01225 // Boot Catalog 01226 if (eltorito == TRUE) 01227 { 01228 boot_catalog_sector = cd.sector; 01229 01230 // Validation entry 01231 write_byte(1); 01232 write_byte(0); // x86 boot code 01233 write_little_endian_word(0); // reserved 01234 write_string("ReactOS Foundation"); 01235 write_block(6, 0); // padding 01236 write_little_endian_word(0x62E); // checksum 01237 write_little_endian_word(0xAA55); // signature 01238 01239 // default entry 01240 write_byte(0x88); // bootable 01241 write_byte(0); // no emulation 01242 write_big_endian_word(0); // load segment = default (0x07c0) 01243 write_byte(0); // partition type 01244 write_byte(0); // unused 01245 write_little_endian_word(boot_image_size); // sector count 01246 write_little_endian_dword(boot_image_sector); // sector 01247 01248 fill_sector(); 01249 } 01250 01251 // Boot Image 01252 if (eltorito == TRUE) 01253 { 01254 boot_image_sector = cd.sector; 01255 01256 file = fopen(bootimage, "rb"); 01257 if (file == NULL) 01258 error_exit("Can't open %s\n", bootimage); 01259 fseek(file, 0, SEEK_END); 01260 size = ftell(file); 01261 fseek(file, 0, SEEK_SET); 01262 if (size == 0 || (size % 2048)) 01263 { 01264 fclose(file); 01265 error_exit("Invalid boot image size (%lu bytes)\n", size); 01266 } 01267 boot_image_size = size / 512; 01268 while (size > 0) 01269 { 01270 n = BUFFER_SIZE - cd.count; 01271 if ((DWORD) n > size) 01272 n = size; 01273 if (fread (cd.buffer + cd.count, n, 1, file) < 1) 01274 { 01275 fclose(file); 01276 error_exit("Read error in file %s\n", bootimage); 01277 } 01278 cd.count += n; 01279 if (cd.count == BUFFER_SIZE) 01280 flush_buffer(); 01281 cd.sector += n / SECTOR_SIZE; 01282 cd.offset += n % SECTOR_SIZE; 01283 size -= n; 01284 } 01285 fclose(file); 01286 // fill_sector(); 01287 } 01288 01289 // Little Endian Path Table 01290 little_endian_path_table_sector = cd.sector; 01291 write_byte(1); 01292 write_byte(0); // number of sectors in extended attribute record 01293 write_little_endian_dword(root.sector); 01294 write_little_endian_word((WORD) 1); 01295 write_byte(0); 01296 write_byte(0); 01297 01298 index = 1; 01299 root.path_table_index = 1; 01300 for (d = root.next_in_path_table; d != NULL; d = d->next_in_path_table) 01301 { 01302 name_length = strlen(d->name_on_cd); 01303 write_byte((BYTE)name_length); 01304 write_byte(0); // number of sectors in extended attribute record 01305 write_little_endian_dword(d->sector); 01306 write_little_endian_word(d->parent->path_table_index); 01307 write_string(d->name_on_cd); 01308 if (name_length & 1) 01309 write_byte(0); 01310 d->path_table_index = ++index; 01311 } 01312 01313 path_table_size = (cd.sector - little_endian_path_table_sector) * 01314 SECTOR_SIZE + cd.offset; 01315 fill_sector(); 01316 01317 // Big Endian Path Table 01318 01319 big_endian_path_table_sector = cd.sector; 01320 write_byte(1); 01321 write_byte(0); // number of sectors in extended attribute record 01322 write_big_endian_dword(root.sector); 01323 write_big_endian_word((WORD) 1); 01324 write_byte(0); 01325 write_byte(0); 01326 01327 for (d = root.next_in_path_table; d != NULL; d = d->next_in_path_table) 01328 { 01329 name_length = strlen(d->name_on_cd); 01330 write_byte((BYTE)name_length); 01331 write_byte(0); // number of sectors in extended attribute record 01332 write_big_endian_dword(d->sector); 01333 write_big_endian_word(d->parent->path_table_index); 01334 write_string(d->name_on_cd); 01335 if (name_length & 1) 01336 write_byte(0); 01337 } 01338 fill_sector(); 01339 01340 if (joliet) 01341 { 01342 // Little Endian Path Table 01343 01344 joliet_little_endian_path_table_sector = cd.sector; 01345 write_byte(1); 01346 write_byte(0); // number of sectors in extended attribute record 01347 write_little_endian_dword(root.joliet_sector); 01348 write_little_endian_word((WORD) 1); 01349 write_byte(0); 01350 write_byte(0); 01351 01352 for (d = root.next_in_path_table; d != NULL; d = d->next_in_path_table) 01353 { 01354 name_length = strlen(d->joliet_name) * 2; 01355 write_byte((BYTE)name_length); 01356 write_byte(0); // number of sectors in extended attribute record 01357 write_little_endian_dword(d->joliet_sector); 01358 write_little_endian_word(d->parent->path_table_index); 01359 write_string_as_big_endian_unicode(d->joliet_name); 01360 } 01361 01362 joliet_path_table_size = (cd.sector - joliet_little_endian_path_table_sector) * 01363 SECTOR_SIZE + cd.offset; 01364 fill_sector(); 01365 01366 // Big Endian Path Table 01367 01368 joliet_big_endian_path_table_sector = cd.sector; 01369 write_byte(1); 01370 write_byte(0); // number of sectors in extended attribute record 01371 write_big_endian_dword(root.joliet_sector); 01372 write_big_endian_word((WORD) 1); 01373 write_byte(0); 01374 write_byte(0); 01375 01376 for (d = root.next_in_path_table; d != NULL; d = d->next_in_path_table) 01377 { 01378 name_length = strlen(d->joliet_name) * 2; 01379 write_byte((BYTE)name_length); 01380 write_byte(0); // number of sectors in extended attribute record 01381 write_big_endian_dword(d->joliet_sector); 01382 write_big_endian_word(d->parent->path_table_index); 01383 write_string_as_big_endian_unicode(d->joliet_name); 01384 } 01385 fill_sector(); 01386 } 01387 01388 // directories and files 01389 for (d = &root; d != NULL; d = d->next_in_path_table) 01390 { 01391 // write directory 01392 d->sector = cd.sector; 01393 write_directory_record(d, DOT_RECORD, FALSE); 01394 write_directory_record(d == &root ? d : d->parent, DOT_DOT_RECORD, FALSE); 01395 for (q = d->first_record; q != NULL; q = q->next_in_directory) 01396 { 01397 write_directory_record(q, 01398 q->flags & DIRECTORY_FLAG ? SUBDIRECTORY_RECORD : FILE_RECORD, 01399 FALSE); 01400 } 01401 fill_sector(); 01402 d->size = (cd.sector - d->sector) * SECTOR_SIZE; 01403 01404 // write directory for joliet 01405 if (joliet) 01406 { 01407 d->joliet_sector = cd.sector; 01408 write_directory_record(d, DOT_RECORD, TRUE); 01409 write_directory_record(d == &root ? d : d->parent, DOT_DOT_RECORD, TRUE); 01410 for (q = d->first_record; q != NULL; q = q->next_in_directory) 01411 { 01412 write_directory_record(q, 01413 q->flags & DIRECTORY_FLAG ? SUBDIRECTORY_RECORD : FILE_RECORD, 01414 TRUE); 01415 } 01416 fill_sector(); 01417 d->joliet_size = (cd.sector - d->joliet_sector) * SECTOR_SIZE; 01418 bytes_in_directories += d->joliet_size; 01419 } 01420 01421 number_of_directories++; 01422 bytes_in_directories += d->size; 01423 01424 // write file data 01425 for (q = d->first_record; q != NULL; q = q->next_in_directory) 01426 { 01427 if ((q->flags & DIRECTORY_FLAG) == 0) 01428 { 01429 q->sector = q->joliet_sector = cd.sector; 01430 size = q->size; 01431 if (cd.file == NULL) 01432 { 01433 number_of_sectors = (size + SECTOR_SIZE - 1) / SECTOR_SIZE; 01434 cd.sector += number_of_sectors; 01435 number_of_files++; 01436 bytes_in_files += size; 01437 unused_bytes_at_ends_of_files += 01438 number_of_sectors * SECTOR_SIZE - size; 01439 } 01440 else 01441 { 01442 old_end_source = end_source; 01443 get_file_specifications(q); 01444 *end_source = 0; 01445 if (verbosity == VERBOSE) 01446 printf("Writing %s\n", source); 01447 file = fopen(source, "rb"); 01448 if (file == NULL) 01449 error_exit("Can't open %s\n", source); 01450 fseek(file, 0, SEEK_SET); 01451 while (size > 0) 01452 { 01453 n = BUFFER_SIZE - cd.count; 01454 if ((DWORD) n > size) 01455 n = size; 01456 if (fread (cd.buffer + cd.count, n, 1, file) < 1) 01457 { 01458 fclose(file); 01459 error_exit("Read error in file %s\n", source); 01460 } 01461 cd.count += n; 01462 if (cd.count == BUFFER_SIZE) 01463 flush_buffer(); 01464 cd.sector += n / SECTOR_SIZE; 01465 cd.offset += n % SECTOR_SIZE; 01466 size -= n; 01467 } 01468 fclose(file); 01469 end_source = old_end_source; 01470 fill_sector(); 01471 } 01472 } 01473 } 01474 } 01475 01476 total_sectors = (DWORD)cd.sector; 01477 } 01478 01479 static char HELP[] = 01480 "CDMAKE [-q] [-v] [-p] [-s N] [-m] [-b bootimage] [-j] source volume image\n" 01481 "\n" 01482 " source specifications of base directory containing all files to\n" 01483 " be written to CD-ROM image\n" 01484 " volume volume label\n" 01485 " image image file or device\n" 01486 " -q quiet mode - display nothing but error messages\n" 01487 " -v verbose mode - display file information as files are\n" 01488 " scanned and written - overrides -p option\n" 01489 " -p show progress while writing\n" 01490 " -s N abort operation before beginning write if image will be\n" 01491 " larger than N megabytes (i.e. 1024*1024*N bytes)\n" 01492 " -m accept punctuation marks other than underscores in\n" 01493 " names and extensions\n" 01494 " -b bootimage create bootable ElTorito CD-ROM using 'no emulation' mode\n" 01495 " -j generate Joliet filename records\n"; 01496 01497 /*----------------------------------------------------------------------------- 01498 Program execution starts here. 01499 -----------------------------------------------------------------------------*/ 01500 01501 int main(int argc, char **argv) 01502 { 01503 BOOL q_option = FALSE; 01504 BOOL v_option = FALSE; 01505 int i; 01506 char *t; 01507 01508 if (argc < 2) 01509 { 01510 puts(HELP); 01511 return 1; 01512 } 01513 01514 if (setjmp(error)) 01515 return 1; 01516 01517 // initialize root directory 01518 01519 cd.buffer = malloc (BUFFER_SIZE); 01520 if (cd.buffer == NULL) 01521 error_exit("Insufficient memory"); 01522 01523 memset(&root, 0, sizeof(root)); 01524 root.level = 1; 01525 root.flags = DIRECTORY_FLAG; 01526 01527 // initialize CD-ROM write buffer 01528 01529 cd.file = NULL; 01530 cd.filespecs[0] = 0; 01531 01532 // initialize parameters 01533 01534 verbosity = NORMAL; 01535 size_limit = 0; 01536 show_progress = FALSE; 01537 accept_punctuation_marks = FALSE; 01538 source[0] = 0; 01539 volume_label[0] = 0; 01540 01541 eltorito = FALSE; 01542 01543 // scan command line arguments 01544 01545 for (i = 1; i < argc; i++) 01546 { 01547 if (memcmp(argv[i], "-s", 2) == 0) 01548 { 01549 t = argv[i] + 2; 01550 if (*t == 0) 01551 { 01552 if (++i < argc) 01553 t = argv[i]; 01554 else 01555 error_exit("Missing size limit parameter"); 01556 } 01557 while (isdigit(*t)) 01558 size_limit = size_limit * 10 + *t++ - '0'; 01559 if (size_limit < 1 || size_limit > 800) 01560 error_exit("Invalid size limit"); 01561 size_limit <<= 9; // convert megabyte to sector count 01562 } 01563 else if (strcmp(argv[i], "-q") == 0) 01564 q_option = TRUE; 01565 else if (strcmp(argv[i], "-v") == 0) 01566 v_option = TRUE; 01567 else if (strcmp(argv[i], "-p") == 0) 01568 show_progress = TRUE; 01569 else if (strcmp(argv[i], "-m") == 0) 01570 accept_punctuation_marks = TRUE; 01571 else if (strcmp(argv[i], "-j") == 0) 01572 joliet = TRUE; 01573 else if (strcmp(argv[i], "-b") == 0) 01574 { 01575 strcpy(bootimage, argv[++i]); 01576 eltorito = TRUE; 01577 } 01578 else if (i + 2 < argc) 01579 { 01580 strcpy(source, argv[i++]); 01581 strncpy(volume_label, argv[i++], sizeof(volume_label) - 1); 01582 strcpy(cd.filespecs, argv[i]); 01583 } 01584 else 01585 error_exit("Missing command line argument"); 01586 } 01587 if (v_option) 01588 { 01589 show_progress = FALSE; 01590 verbosity = VERBOSE; 01591 } 01592 else if (q_option) 01593 { 01594 verbosity = QUIET; 01595 show_progress = FALSE; 01596 } 01597 if (source[0] == 0) 01598 error_exit("Missing source directory"); 01599 if (volume_label[0] == 0) 01600 error_exit("Missing volume label"); 01601 if (cd.filespecs[0] == 0) 01602 error_exit("Missing image file specifications"); 01603 01604 01605 // set source[] and end_source to source directory, with a terminating directory separator 01606 01607 end_source = source + strlen(source); 01608 if (end_source[-1] == ':') 01609 *end_source++ = '.'; 01610 if (end_source[-1] != DIR_SEPARATOR_CHAR) 01611 *end_source++ = DIR_SEPARATOR_CHAR; 01612 01613 // scan all files and create directory structure in memory 01614 01615 make_directory_records(&root); 01616 01617 // sort path table entries 01618 01619 root.next_in_path_table = sort_linked_list(root.next_in_path_table, 1, 01620 compare_path_table_order); 01621 01622 // initialize CD-ROM write buffer 01623 01624 cd.file = NULL; 01625 cd.sector = 0; 01626 cd.offset = 0; 01627 cd.count = 0; 01628 01629 // make non-writing pass over directory structure to obtain the proper 01630 // sector numbers and offsets and to determine the size of the image 01631 01632 number_of_files = bytes_in_files = number_of_directories = 01633 bytes_in_directories = unused_bytes_at_ends_of_files =0; 01634 pass(); 01635 01636 if (verbosity >= NORMAL) 01637 { 01638 printf("%s bytes ", edit_with_commas(bytes_in_files, TRUE)); 01639 printf("in %s files\n", edit_with_commas(number_of_files, FALSE)); 01640 printf("%s unused bytes at ends of files\n", 01641 edit_with_commas(unused_bytes_at_ends_of_files, TRUE)); 01642 printf("%s bytes ", edit_with_commas(bytes_in_directories, TRUE)); 01643 printf("in %s directories\n", 01644 edit_with_commas(number_of_directories, FALSE)); 01645 printf("%s other bytes\n", edit_with_commas(root.sector * SECTOR_SIZE, TRUE)); 01646 puts("-------------"); 01647 printf("%s total bytes\n", 01648 edit_with_commas(total_sectors * SECTOR_SIZE, TRUE)); 01649 puts("============="); 01650 } 01651 01652 if (size_limit != 0 && total_sectors > size_limit) 01653 error_exit("Size limit exceeded"); 01654 01655 // re-initialize CD-ROM write buffer 01656 01657 cd.file = fopen(cd.filespecs, "w+b"); 01658 if (cd.file == NULL) 01659 error_exit("Can't open image file %s", cd.filespecs); 01660 cd.sector = 0; 01661 cd.offset = 0; 01662 cd.count = 0; 01663 01664 01665 // make writing pass over directory structure 01666 01667 pass(); 01668 01669 if (cd.count > 0) 01670 flush_buffer(); 01671 if (show_progress) 01672 printf("\r \n"); 01673 if (fclose(cd.file) != 0) 01674 { 01675 cd.file = NULL; 01676 error_exit("File write error in image file %s", cd.filespecs); 01677 } 01678 01679 if (verbosity >= NORMAL) 01680 puts("CD-ROM image made successfully"); 01681 01682 release_memory(); 01683 return 0; 01684 } 01685 01686 01687 /* EOF */ Generated on Sun May 27 2012 04:37:45 for ReactOS by
1.7.6.1
|