diff --git a/src/isotoserial.d b/src/isotoserial.d index 3fe3021..8e9ab4e 100644 --- a/src/isotoserial.d +++ b/src/isotoserial.d @@ -6,229 +6,17 @@ import std.exception; import std.conv : to; import std.stdint; -private const int MAX_ISONAME_V2 = 207; /*254 - 33 - 14 (XA Record)*/ -private const int MAX_ISONAME = MAX_ISONAME_V2; -private const int ISO_MULTIEXTENT = 128; /*Not final entry of a mult. ext. file*/ -private const SECTOR_SIZE = 2048; -/* - * Use sector_offset != 0 (-N #) if we have an image file - * of a single session and we need to list the directory contents. - * This is the session block (sector) number of the start - * of the session when it would be on disk. - */ -private uint sector_offset = 0; - -private int ISODCL(int from, int to) pure { - return to - from + 1; -} -private int ISO_BLOCKS(size_t X) pure { - return (cast(int)X / SECTOR_SIZE + ((cast(int)X % SECTOR_SIZE) ? 1 : 0)); -} -private alias off_t = long; - extern(C) { - struct iso_volume_descriptor { - char[ISODCL(1, 1)] type; /* 711 */ - char[ISODCL(2, 6)] id; - char[ISODCL(7, 7)] version_; - char[ISODCL(8, 2048)] data; - } + alias iso_listing_callback = int function(void*,const(char)*,int); + int scan_iso (const(char)* filename, iso_listing_callback callback, void* user_data); - struct iso_directory_record { - byte [ISODCL(1, 1)] length; /* 711 */ - char [ISODCL(2, 2)] ext_attr_length; /* 711 */ - char [ISODCL(3, 10)] extent; /* 733 */ - char [ISODCL(11, 18)] size; /* 733 */ - char [ISODCL(19, 25)] date; /* 7 by 711 */ - byte [ISODCL(26, 26)] flags; - char [ISODCL(27, 27)] file_unit_size; /* 711 */ - char [ISODCL(28, 28)] interleave; /* 711 */ - char [ISODCL(29, 32)] volume_sequence_number; /* 723 */ - byte [ISODCL(33, 33)] name_len; /* 711 */ - char [MAX_ISONAME+1] name; /* Not really, but we need something here */ - }; - - version(USE_SCG) { - int readsecs (uint32_t startsecno, void* buffer, int sectorcount); - } -} - -private struct todo { - todo* next; - todo* prev; - string name; - int extent; - int length; -} - -//int extent; /* Directory extent */ -//int len; /* Directory size */ -private void parse_dir(todo* dp, string rootname, int extent, int len) { - todo td; - int i; - iso_directory_record* idr; - iso_directory_record didr; - //stat dstat; - byte[2048] cl_buffer; - byte flags = 0; - long size = 0; - int sextent = 0; - int rlen; - int blen; - int rr_flags = 0; - static char* n = null; - static int nlen = 0; - byte[2048] buffer; - - while (len > 0) { -version(USE_SCG) { - readsecs(extent - sector_offset, buffer.ptr, ISO_BLOCKS(buffer.length)); -} -else { - lseek(fileno(infile), (cast(off_t)(extent - sector_offset)) << 11, SEEK_SET); - read(fileno(infile), buffer, sizeof (buffer)); -} - len -= typeof(buffer).sizeof; - extent++; - i = 0; - /* - while (true) { - idr = cast(iso_directory_record*)&buffer[i]; - if (idr->length[0] == 0) - break; - parse_de(idr); - if (use_rock) { - rr_flags = dump_rr(idr); - - if (rr_flags & RR_FLAG_CL) { - // Need to reparse the child link - // but note that we parse "CL/." - // so we get no usable file name. - idr = (struct iso_directory_record *) cl_buffer; - parse_cl_dir(idr, cl_extent); - } else if (rr_flags & RR_FLAG_RE) - goto cont; // skip rr_moved - } - if (Xtract && - (idr->flags[0] & 2) != 0 && - idr->name_len[0] == 1 && - idr->name[0] == 0) { - // The '.' entry. - didr = *idr; - dstat = fstat_buf; - } - blen = strlen(name_buf); - - blen = rlen + blen + 1; - if (nlen < blen) { - n = ___realloc(n, blen, _("find_stat name")); - nlen = blen; - } - strcatl(n, rootname, name_buf, (char *)0); - if (name_buf[0] == '.' && name_buf[1] == '\0') - n[rlen] = '\0'; - - if ((idr->flags[0] & 2) != 0 && - ((rr_flags & RR_FLAG_CL) || - (idr->name_len[0] != 1 || - (idr->name[0] != 0 && idr->name[0] != 1)))) { - // This is a plain directory (neither "xxx/." - // nor "xxx/.."). - // Add this directory to the todo list. - int dir_loop = 0; - int nextent; - struct todo *tp = dp; - - nextent = isonum_733((unsigned char *)idr->extent); - while (tp) { - if (tp->extent == nextent) { - dir_loop = 1; - break; - } - tp = tp->prev; - } - if (dir_loop == 0) { - td = (struct todo *) malloc(sizeof (*td)); - if (td == NULL) - comerr(_("No memory.\n")); - td->next = NULL; - td->prev = dp; - td->extent = isonum_733((unsigned char *)idr->extent); - td->length = isonum_733((unsigned char *)idr->size); - td->name = (char *) malloc(strlen(rootname) - + strlen(name_buf) + 2); - if (td->name == NULL) - comerr(_("No memory.\n")); - strcpy(td->name, rootname); - strcat(td->name, name_buf); - strcat(td->name, "/"); - - *todo_pp = td; - todo_pp = &td->next; - } - } else { - if (xtract && strcmp(xtract, n) == 0) { - extract_file(STDOUT_FILENO, idr, "stdout"); - } - } - if (do_f && - (idr->name_len[0] != 1 || - (idr->name[0] != 0 && idr->name[0] != 1))) { - printf("%s\n", n); - } - if (do_listing || Xtract || do_find) { - // In case if a multi-extent file, remember the - // start extent number. - if ((idr->flags[0] & ISO_MULTIEXTENT) && size == 0) - sextent = isonum_733((unsigned char *)idr->extent); - - if (debug || - ((idr->flags[0] & ISO_MULTIEXTENT) == 0 && size == 0)) { - if (dump_stat(rootname, idr, n, - isonum_733((unsigned char *)idr->extent))) { - if (Xtract) { - if ((idr->flags[0] & 2) != 0 && - idr->name_len[0] != 1 && - idr->name[0] != 1) { - char *p = n; - if (*p == '/') - p++; - makedirs(p, - S_IRUSR|S_IWUSR|S_IXUSR| - S_IRGRP|S_IWGRP|S_IXGRP| - S_IROTH|S_IWOTH|S_IXOTH, - FALSE); - } else { - if (myuid != 0 && - S_ISDIR(fstat_buf.st_mode)) { - fstat_buf.st_mode |= S_IWUSR; - } - extract(rootname, idr, n); - } - } - } - } else if (Xtract && find_stat(rootname, idr, n, sextent)) { - // Extract all multi extent files here... - extract(rootname, idr, n); - } - size += fstat_buf.st_size; - if ((flags & ISO_MULTIEXTENT) && - (idr->flags[0] & ISO_MULTIEXTENT) == 0) { - fstat_buf.st_size = size; - if (!debug) - idr->flags[0] |= ISO_MULTIEXTENT; - dump_stat(rootname, idr, n, sextent); - if (!debug) - idr->flags[0] &= ~ISO_MULTIEXTENT; - } - flags = idr->flags[0]; - if ((idr->flags[0] & ISO_MULTIEXTENT) == 0) - size = 0; - } - cont: - i += buffer[i]; - if (i > 2048 - offsetof(struct iso_directory_record, name[0])) break; - } */ + private int printer(void*, const(char)* path, int is_dir) { + writef("Entry \"%s\"", path.fromStringz); + if (is_dir != 0) { + write(" (directory)"); + } + write("\n"); + return 0; } } @@ -239,6 +27,8 @@ public string iso_to_serial (string path) { // NPJH-50465|0D506D389F2AA444|0001|G // ULJM-05530|5A2E0CF722EF6299|0001|G + scan_iso(path.toStringz, &printer, null); + return "UCES-00356"; //Tekken Dark Resurrection //return "NPJH-50465"; //Hatsune Miku (missing from redump list) //return "ULJM-05530"; //Undead Knights (missing from redump list) diff --git a/subprojects/isoinfo/meson.build b/subprojects/isoinfo/meson.build index 6827a0b..9f72f93 100644 --- a/subprojects/isoinfo/meson.build +++ b/subprojects/isoinfo/meson.build @@ -24,12 +24,16 @@ add_project_arguments( c_compiler = meson.get_compiler('c') cdrdeflt_dep = c_compiler.find_library('cdrdeflt') +scgcmd_dep = c_compiler.find_library('scgcmd') +schily_dep = c_compiler.find_library('schily') +scg_dep = c_compiler.find_library('scg') +siconv_dep = c_compiler.find_library('siconv') public_inc = include_directories('include') libisoinfo = static_library(meson.project_name(), 'src/isoinfo.c', 'src/scsi.c', - dependencies: [cdrdeflt_dep], + dependencies: [cdrdeflt_dep, scgcmd_dep, schily_dep, scg_dep, siconv_dep], install: false, ) diff --git a/subprojects/isoinfo/src/isoinfo.c b/subprojects/isoinfo/src/isoinfo.c index 5e9417a..a3128b6 100644 --- a/subprojects/isoinfo/src/isoinfo.c +++ b/subprojects/isoinfo/src/isoinfo.c @@ -119,8 +119,14 @@ #define GET_UBYTE(a) a_to_u_byte(a) -#define infile in_image -EXPORT FILE *infile = NULL; +typedef int(*iso_listing_callback)(void*,const char*,int is_dir); + +enum ScanRetCode { + ScanRetCode_Ok = 100, + ScanRetCode_Disabled, + ScanRetCode_BadInput +}; + EXPORT BOOL ignerr = FALSE; LOCAL int use_rock = 0; LOCAL int use_joliet = 0; @@ -174,30 +180,35 @@ LOCAL struct todo **todo_pp = &todo_idr; LOCAL int isonum_731 __PR((char * p)); LOCAL int isonum_733 __PR((unsigned char * p)); -LOCAL int parse_rr __PR((unsigned char * pnt, int len, - int cont_flag)); +LOCAL int parse_rr __PR((struct scsi_dev *dev, unsigned char * pnt, + int len, int cont_flag)); LOCAL void find_rr __PR((struct iso_directory_record * idr, Uchar **pntp, int *lenp)); -LOCAL int dump_rr __PR((struct iso_directory_record * idr)); +LOCAL int dump_rr __PR((struct scsi_dev *dev, + struct iso_directory_record * idr)); LOCAL BOOL dump_stat __PR((char *rootname, struct iso_directory_record * idr, char *fname, int extent)); -LOCAL void extract __PR((char *rootname, +LOCAL void extract __PR((struct scsi_dev *dev, + char *rootname, struct iso_directory_record * idr, + char *fname)); +LOCAL void extract_file __PR((struct scsi_dev *dev, int f, struct iso_directory_record * idr, char *fname)); -LOCAL void extract_file __PR((int f, - struct iso_directory_record * idr, - char *fname)); -LOCAL void parse_cl_dir __PR((struct iso_directory_record *idr, - int extent)); +LOCAL void parse_cl_dir __PR((struct scsi_dev *dev, + struct iso_directory_record *idr, int extent)); LOCAL BOOL parse_de __PR((struct iso_directory_record *idr)); -LOCAL void parse_dir __PR((struct todo *dp, - char * rootname, int extent, int len)); +LOCAL void parse_dir __PR((struct scsi_dev *dev, struct todo *dp, + char * rootname, int extent, int len, + iso_listing_callback callback, void* user_data)); LOCAL void list_locales __PR((void)); LOCAL int time_cvt __PR((unsigned char *dp, int len)); LOCAL time_t iso9660_time __PR((unsigned char *date, int *hsecp, BOOL longfmt)); +LOCAL int run_scanning __PR((struct scsi_dev *dev, + iso_listing_callback callback, void *user_data)); +LOCAL char* default_charset __PR((void)); LOCAL int isonum_731(p) @@ -225,7 +236,8 @@ isonum_733(p) #endif LOCAL int -parse_rr(pnt, len, cont_flag) +parse_rr(dev, pnt, len, cont_flag) + struct scsi_dev *dev; unsigned char *pnt; int len; int cont_flag; @@ -409,12 +421,12 @@ parse_rr(pnt, len, cont_flag) unsigned char sector[2048]; #ifdef USE_SCG - readsecs(cont_extent - sector_offset, sector, ISO_BLOCKS(sizeof (sector))); + readsecs(dev, cont_extent - sector_offset, sector, ISO_BLOCKS(sizeof (sector))); #else lseek(fileno(infile), ((off_t)(cont_extent - sector_offset)) << 11, SEEK_SET); read(fileno(infile), sector, sizeof (sector)); #endif - flag2 |= parse_rr(§or[cont_offset], cont_size, 1); + flag2 |= parse_rr(dev, §or[cont_offset], cont_size, 1); } /* * for symbolic links, strip out the last '/' @@ -461,14 +473,15 @@ find_rr(idr, pntp, lenp) } LOCAL int -dump_rr(idr) +dump_rr(dev, idr) + struct scsi_dev *dev; struct iso_directory_record *idr; { int len; unsigned char * pnt; find_rr(idr, &pnt, &len); - return (parse_rr(pnt, len, 0)); + return (parse_rr(dev, pnt, len, 0)); } LOCAL char *months[12] = {"Jan", "Feb", "Mar", "Apr", @@ -572,7 +585,8 @@ dump_stat(rootname, idr, fname, extent) } LOCAL void -extract(rootname, idr, fname) +extract(dev, rootname, idr, fname) + struct scsi_dev *dev; char *rootname; struct iso_directory_record *idr; char *fname; @@ -682,7 +696,7 @@ static BOOL isfirst = TRUE; return; } lseek(f, 0, SEEK_END); - extract_file(f, idr, fname); + extract_file(dev, f, idr, fname); if ((idr->flags[0] & ISO_MULTIEXTENT) == 0) { #ifdef HAVE_FCHOWN fchown(f, fstat_buf.st_uid, fstat_buf.st_gid); @@ -720,7 +734,8 @@ setmode: } LOCAL void -extract_file(f, idr, fname) +extract_file(dev, f, idr, fname) + struct scsi_dev *dev; int f; struct iso_directory_record *idr; char *fname; @@ -737,7 +752,7 @@ extract_file(f, idr, fname) while (len > 0) { tlen = (len > sizeof (buff) ? sizeof (buff) : len); #ifdef USE_SCG - readsecs(extent - sector_offset, buff, ISO_BLOCKS(tlen)); + readsecs(dev, extent - sector_offset, buff, ISO_BLOCKS(tlen)); #else lseek(fileno(infile), ((off_t)(extent - sector_offset)) << 11, SEEK_SET); read(fileno(infile), buff, tlen); @@ -751,7 +766,8 @@ extract_file(f, idr, fname) LOCAL void -parse_cl_dir(idr, extent) +parse_cl_dir(dev, idr, extent) + struct scsi_dev *dev; struct iso_directory_record *idr; int extent; { @@ -759,14 +775,14 @@ parse_cl_dir(idr, extent) strlcpy(cl_name_buf, name_buf, sizeof (cl_name_buf)); #ifdef USE_SCG - readsecs(extent - sector_offset, idr, 1); + readsecs(dev, extent - sector_offset, idr, 1); #else lseek(fileno(infile), ((off_t)(extent - sector_offset)) << 11, SEEK_SET); read(fileno(infile), idr, 2048); #endif if (parse_de(idr) && use_rock) - dump_rr(idr); + dump_rr(dev, idr); strlcpy(name_buf, cl_name_buf, sizeof (name_buf)); } @@ -887,11 +903,14 @@ parse_de(idr) } LOCAL void -parse_dir(dp, rootname, extent, len) +parse_dir(dev, dp, rootname, extent, len, callback, user_data) + struct scsi_dev *dev; struct todo *dp; char *rootname; int extent; /* Directory extent */ int len; /* Directory size */ + iso_listing_callback callback; + void *user_data; { struct todo *td; int i; @@ -910,7 +929,7 @@ static int nlen = 0; while (len > 0) { #ifdef USE_SCG - readsecs(extent - sector_offset, buffer, ISO_BLOCKS(sizeof (buffer))); + readsecs(dev, extent - sector_offset, buffer, ISO_BLOCKS(sizeof (buffer))); #else lseek(fileno(infile), ((off_t)(extent - sector_offset)) << 11, SEEK_SET); read(fileno(infile), buffer, sizeof (buffer)); @@ -924,7 +943,7 @@ static int nlen = 0; break; parse_de(idr); if (use_rock) { - rr_flags = dump_rr(idr); + rr_flags = dump_rr(dev, idr); if (rr_flags & RR_FLAG_CL) { /* @@ -933,7 +952,7 @@ static int nlen = 0; * so we get no usable file name. */ idr = (struct iso_directory_record *) cl_buffer; - parse_cl_dir(idr, cl_extent); + parse_cl_dir(dev, idr, cl_extent); } else if (rr_flags & RR_FLAG_RE) goto cont; /* skip rr_moved */ } @@ -969,6 +988,8 @@ static int nlen = 0; int nextent; struct todo *tp = dp; + (*callback)(user_data, n, 1); + nextent = isonum_733((unsigned char *)idr->extent); while (tp) { if (tp->extent == nextent) { @@ -996,9 +1017,13 @@ static int nlen = 0; *todo_pp = td; todo_pp = &td->next; } + } else if ((idr->flags[0] & 2) && + (idr->name[0] != 0 || idr->name[0] != 1)) { + /* this is . or .. */ } else { + callback(user_data, n, 0); if (xtract && strcmp(xtract, n) == 0) { - extract_file(STDOUT_FILENO, idr, "stdout"); + extract_file(dev, STDOUT_FILENO, idr, "stdout"); } } if (do_f && @@ -1035,7 +1060,7 @@ static int nlen = 0; S_ISDIR(fstat_buf.st_mode)) { fstat_buf.st_mode |= S_IWUSR; } - extract(rootname, idr, n); + extract(dev, rootname, idr, n); } } } @@ -1043,7 +1068,7 @@ static int nlen = 0; /* * Extract all multi extent files here... */ - extract(rootname, idr, n); + extract(dev, rootname, idr, n); } size += fstat_buf.st_size; if ((flags & ISO_MULTIEXTENT) && @@ -1073,14 +1098,66 @@ static int nlen = 0; } EXPORT int -main(argc, argv) - int argc; - char *argv[]; +scan_iso (filename, callback, user_data) + const char* filename; + iso_listing_callback callback; + void* user_data; +{ + struct scsi_dev *dev; + int retval; + + if (NULL == filename || NULL == callback) + return ScanRetCode_BadInput; + + dev = scsidev_file_open(filename); + retval = run_scanning(dev, callback, user_data); + scsidev_close(dev); + return retval; +} + +EXPORT int +scan_device (sdevname, callback, user_data) + const char* sdevname; + iso_listing_callback callback; + void* user_data; +{ +#ifndef USE_SCG + return ScanRetCode_Disabled; +#else + struct scsi_dev *dev; + int retval; + char* devname; + + if (NULL == callback) + return ScanRetCode_BadInput; + + if (sdevname == NULL) + cdr_defaults(&devname, NULL, NULL, NULL, NULL); + if (devname == NULL) + return ScanRetCode_BadInput; + + dev = scsidev_open(devname); + if (scsidev_has_error(dev)) { + retval = scsidev_error_code(dev); + scsidev_close(dev); + return retval; + } + + retval = run_scanning(dev, callback, user_data); + scsidev_close(dev); + return retval; +#endif +} + + +LOCAL int +run_scanning(dev, callback, user_data) + struct scsi_dev *dev; + iso_listing_callback callback; + void *user_data; { int c; int ret = 0; - char *filename = NULL; - char *sdevname = NULL; #if defined(USE_NLS) char *dir; #endif @@ -1120,63 +1197,7 @@ main(argc, argv) myuid = getuid(); -#if defined(USE_NLS) && defined(HAVE_NL_LANGINFO) && defined(CODESET) - /* - * If the locale has not been set up, nl_langinfo() returns the - * name of the default codeset. This should be either "646", - * "ISO-646", "ASCII", or something similar. Unfortunately, the - * POSIX standard does not include a list of valid locale names, - * so ne need to find all values in use. - * - * Observed: - * Solaris "646" - * Linux "ANSI_X3.4-1968" strange value from Linux... - */ - if (charset == NULL) { - char *codeset = nl_langinfo(CODESET); - Uchar *p; - - if (codeset != NULL) - codeset = strdup(codeset); - if (codeset == NULL) /* Should not happen */ - goto setcharset; - if (*codeset == '\0') /* Invalid locale */ - goto setcharset; - - for (p = (Uchar *)codeset; *p != '\0'; p++) { - if (islower(*p)) - *p = toupper(*p); - } - p = (Uchar *)strstr(codeset, "ISO"); - if (p != NULL) { - if (*p == '_' || *p == '-') - p++; - codeset = (char *)p; - } - if (strcmp("646", codeset) != 0 && - strcmp("ASCII", codeset) != 0 && - strcmp("US-ASCII", codeset) != 0 && - strcmp("US_ASCII", codeset) != 0 && - strcmp("USASCII", codeset) != 0 && - strcmp("ANSI_X3.4-1968", codeset) != 0) - charset = nl_langinfo(CODESET); - - if (codeset != NULL) - free(codeset); - -#define verbose 1 - if (verbose > 0 && charset != NULL) { - error(_("Setting input-charset to '%s' from locale.\n"), - charset); - } - } -setcharset: - /* - * Allow to switch off locale with -input-charset "". - */ - if (charset != NULL && *charset == '\0') - charset = NULL; -#endif + charset = default_charset(); if (charset == NULL) { #if (defined(__CYGWIN32__) || defined(__CYGWIN__) || defined(__DJGPP__) || defined(__MINGW32__)) && !defined(IS_CYGWIN_1) @@ -1197,38 +1218,11 @@ setcharset: exit(1); } - if (filename != NULL && sdevname != NULL) { - errmsgno(EX_BAD, _("Only one of -i or dev= allowed\n")); - } -#ifdef USE_SCG - if (filename == NULL && sdevname == NULL) - cdr_defaults(&sdevname, NULL, NULL, NULL, NULL); -#endif - if (filename == NULL && sdevname == NULL) { - fprintf(stderr, _("ISO-9660 image not specified\n")); - } - - if (filename != NULL) - infile = fopen(filename, "rb"); - else - filename = sdevname; - - if (infile != NULL) { - /* EMPTY */; -#ifdef USE_SCG - } else if (scsidev_open(filename) < 0) { -#else - } else { -#endif - fprintf(stderr, _("Unable to open %s\n"), filename); - exit(1); - } - /* * Absolute sector offset, so don't subtract sector_offset here. */ #ifdef USE_SCG - readsecs(16 + toc_offset, &ipd, ISO_BLOCKS(sizeof (ipd))); + readsecs(dev, 16 + toc_offset, &ipd, ISO_BLOCKS(sizeof (ipd))); #else lseek(fileno(infile), ((off_t)(16 + toc_offset)) <<11, SEEK_SET); read(fileno(infile), &ipd, sizeof (ipd)); @@ -1240,7 +1234,7 @@ setcharset: c = 17; do { #ifdef USE_SCG - readsecs(c + toc_offset, &jpd, ISO_BLOCKS(sizeof (jpd))); + readsecs(dev, c + toc_offset, &jpd, ISO_BLOCKS(sizeof (jpd))); #else lseek(fileno(infile), ((off_t)(c + toc_offset)) <<11, SEEK_SET); read(fileno(infile), &jpd, sizeof (jpd)); @@ -1248,7 +1242,7 @@ setcharset: } while (++c < 32 && GET_UBYTE(jpd.type) != ISO_VD_END); if (GET_UBYTE(jpd.type) == ISO_VD_END) do { #ifdef USE_SCG - readsecs(c + toc_offset, &jpd, ISO_BLOCKS(sizeof (jpd))); + readsecs(dev, c + toc_offset, &jpd, ISO_BLOCKS(sizeof (jpd))); #else lseek(fileno(infile), ((off_t)(c + toc_offset)) <<11, SEEK_SET); read(fileno(infile), &jpd, sizeof (jpd)); @@ -1274,12 +1268,12 @@ setcharset: */ extent = isonum_733((unsigned char *)idr->extent); #ifdef USE_SCG - readsecs(extent - sector_offset, buffer, ISO_BLOCKS(sizeof (buffer))); + readsecs(dev, extent - sector_offset, buffer, ISO_BLOCKS(sizeof (buffer))); #else lseek(fileno(infile), ((off_t)(extent - sector_offset)) <<11, SEEK_SET); read(fileno(infile), buffer, sizeof (buffer)); #endif - c = dump_rr((struct iso_directory_record *) buffer); + c = dump_rr(dev, (struct iso_directory_record *) buffer); if (c == 0 || (c & (RR_FLAG_SP | RR_FLAG_ER)) == 0 || su_version < 1 || rr_version < 1) { if (!debug) @@ -1324,7 +1318,7 @@ setcharset: block++; #ifdef USE_SCG - readsecs(block + toc_offset, &jpd, ISO_BLOCKS(sizeof (jpd))); + readsecs(dev, block + toc_offset, &jpd, ISO_BLOCKS(sizeof (jpd))); #else lseek(fileno(infile), ((off_t)(block + toc_offset)) <<11, SEEK_SET); @@ -1363,17 +1357,15 @@ setcharset: if (use_joliet) idr = (struct iso_directory_record *)jpd.root_directory_record; - parse_dir(todo_idr, "/", isonum_733((unsigned char *)idr->extent), - isonum_733((unsigned char *)idr->size)); + parse_dir(dev, todo_idr, "/", isonum_733((unsigned char *)idr->extent), + isonum_733((unsigned char *)idr->size), callback, user_data); td = todo_idr; while (td) { - parse_dir(td, td->name, td->extent, td->length); + parse_dir(dev, td, td->name, td->extent, td->length, callback, user_data); free(td->name); td = td->next; } - if (infile != NULL) - fclose(infile); return (ret); } @@ -1468,3 +1460,68 @@ iso9660_time(date, hsecp, longfmt) t -= gmtoff * 15 * 60; return (t); } + +LOCAL char* +default_charset(void) +{ + char *charset = NULL; + +#if defined(USE_NLS) && defined(HAVE_NL_LANGINFO) && defined(CODESET) + /* + * If the locale has not been set up, nl_langinfo() returns the + * name of the default codeset. This should be either "646", + * "ISO-646", "ASCII", or something similar. Unfortunately, the + * POSIX standard does not include a list of valid locale names, + * so ne need to find all values in use. + * + * Observed: + * Solaris "646" + * Linux "ANSI_X3.4-1968" strange value from Linux... + */ + if (charset == NULL) { + char *codeset = nl_langinfo(CODESET); + Uchar *p; + + if (codeset != NULL) + codeset = strdup(codeset); + if (codeset == NULL) /* Should not happen */ + goto setcharset; + if (*codeset == '\0') /* Invalid locale */ + goto setcharset; + + for (p = (Uchar *)codeset; *p != '\0'; p++) { + if (islower(*p)) + *p = toupper(*p); + } + p = (Uchar *)strstr(codeset, "ISO"); + if (p != NULL) { + if (*p == '_' || *p == '-') + p++; + codeset = (char *)p; + } + if (strcmp("646", codeset) != 0 && + strcmp("ASCII", codeset) != 0 && + strcmp("US-ASCII", codeset) != 0 && + strcmp("US_ASCII", codeset) != 0 && + strcmp("USASCII", codeset) != 0 && + strcmp("ANSI_X3.4-1968", codeset) != 0) + charset = nl_langinfo(CODESET); + + if (codeset != NULL) + free(codeset); + +#define verbose 1 + if (verbose > 0 && charset != NULL) { + error(_("Setting input-charset to '%s' from locale.\n"), + charset); + } + } +setcharset: + /* + * Allow to switch off locale with -input-charset "". + */ + if (charset != NULL && *charset == '\0') + charset = NULL; +#endif + return charset; +} diff --git a/subprojects/isoinfo/src/scgcmd/libscgcmd.h b/subprojects/isoinfo/src/scgcmd/libscgcmd.h new file mode 100644 index 0000000..d4529d0 --- /dev/null +++ b/subprojects/isoinfo/src/scgcmd/libscgcmd.h @@ -0,0 +1,63 @@ +/* @(#)libscgcmd.h 1.1 08/10/26 Copyright 1986-2008 J. Schilling */ + +#ifndef _LIBSCGCMD_H +#define _LIBSCGCMD_H + +/* + * buffer.c + */ +extern int read_buffer __PR((SCSI *scgp, caddr_t bp, int cnt, int mode)); +extern int write_buffer __PR((SCSI *scgp, char *buffer, long length, int mode, int bufferid, long offset)); + +/* + * inquiry.c + */ +extern int inquiry __PR((SCSI *scgp, caddr_t, int)); + +/* + * modes.c + */ +extern BOOL get_mode_params __PR((SCSI *scgp, int page, char *pagename, + Uchar *modep, Uchar *cmodep, + Uchar *dmodep, Uchar *smodep, + int *lenp)); +extern BOOL set_mode_params __PR((SCSI *scgp, char *pagename, Uchar *modep, + int len, int save, int secsize)); + +/* + * modesense.c + */ +extern BOOL __is_atapi __PR((void)); +extern BOOL allow_atapi __PR((SCSI *scgp, BOOL new)); +extern int mode_select __PR((SCSI *scgp, Uchar *, int, int, int)); +extern int mode_sense __PR((SCSI *scgp, Uchar *dp, int cnt, int page, int pcf)); +extern int mode_select_sg0 __PR((SCSI *scgp, Uchar *, int, int, int)); +extern int mode_sense_sg0 __PR((SCSI *scgp, Uchar *dp, int cnt, int page, int pcf)); +extern int mode_select_g0 __PR((SCSI *scgp, Uchar *, int, int, int)); +extern int mode_select_g1 __PR((SCSI *scgp, Uchar *, int, int, int)); +extern int mode_sense_g0 __PR((SCSI *scgp, Uchar *dp, int cnt, int page, int pcf)); +extern int mode_sense_g1 __PR((SCSI *scgp, Uchar *dp, int cnt, int page, int pcf)); + +/* + * read.c + */ +extern int read_scsi __PR((SCSI *scgp, caddr_t, long, int)); +extern int read_g0 __PR((SCSI *scgp, caddr_t, long, int)); +extern int read_g1 __PR((SCSI *scgp, caddr_t, long, int)); + +/* + * readcap.c + */ +extern int read_capacity __PR((SCSI *scgp)); +#ifdef EOF /* stdio.h has been included */ +extern void print_capacity __PR((SCSI *scgp, FILE *f)); +#endif + +/* + * ready.c + */ +extern BOOL unit_ready __PR((SCSI *scgp)); +extern BOOL wait_unit_ready __PR((SCSI *scgp, int secs)); +extern int test_unit_ready __PR((SCSI *scgp)); + +#endif /* _LIBSCGCMD_H */ diff --git a/subprojects/isoinfo/src/scsi.c b/subprojects/isoinfo/src/scsi.c index 32666e6..cf12434 100644 --- a/subprojects/isoinfo/src/scsi.c +++ b/subprojects/isoinfo/src/scsi.c @@ -29,13 +29,18 @@ static UConst char sccsid[] = #include #include #include +#include +#include + +//#include "mkisofs.h" +#define SECTOR_SIZE (2048) +BOOL ignerr; -#include "mkisofs.h" #include #include -#include "libscgcmd.h" -#include "cdrdeflt.h" +#include "scgcmd/libscgcmd.h" +#include "cdrdeflt/cdrdeflt.h" /* * NOTICE: You should not make BUF_SIZE more than @@ -48,15 +53,36 @@ static UConst char sccsid[] = */ #define BUF_SIZE (62*1024) /* Must be a multiple of 2048 */ -LOCAL SCSI *scgp; +enum ScsiOpenErr { + ScsiOpenErr_Ok = 0, + ScsiOpenErr_CantOpen, /*Cannot open SCSI driver*/ + ScsiOpenErr_CantIO, /*Cannot get SCSI I/O buffer*/ + ScsiOpenErr_Timeout, + ScsiOpenErr_Invalid +}; + +struct scsi_dev { + FILE *file; + SCSI *scgp; + int err; +}; + LOCAL long bufsize; /* The size of the transfer buffer */ -EXPORT int readsecs __PR((UInt32_t startsecno, void *buffer, int sectorcount)); -EXPORT int scsidev_open __PR((char *path)); -EXPORT int scsidev_close __PR((void)); +EXPORT int readsecs __PR((struct scsi_dev* src, UInt32_t startsecno, void *buffer, int sectorcount)); +EXPORT BOOL scsidev_has_error __PR((struct scsi_dev *dev)); +EXPORT int scsidev_error_code __PR((struct scsi_dev *dev)); +EXPORT const char* scsidev_error_desc __PR((int code)); + +#ifdef USE_SCG +EXPORT struct scsi_dev* scsidev_open __PR((char *path)); +EXPORT int scsidev_close __PR((struct scsi_dev *f)); +#endif +EXPORT struct scsi_dev* scsidev_file_open __PR((const char *path)); EXPORT int -readsecs(startsecno, buffer, sectorcount) +readsecs(src, startsecno, buffer, sectorcount) + struct scsi_dev *src; UInt32_t startsecno; void *buffer; int sectorcount; @@ -69,7 +95,7 @@ readsecs(startsecno, buffer, sectorcount) char *bp; long amt; - if (in_image == NULL) { + if (src->file == NULL) { /* * We are using the standard CD-ROM sectorsize of 2048 bytes * while the drive may be switched to 512 bytes per sector. @@ -77,7 +103,7 @@ readsecs(startsecno, buffer, sectorcount) * XXX We assume that secsize is no more than SECTOR_SIZE * XXX and that SECTOR_SIZE / secsize is not a fraction. */ - secsize = scgp->cap->c_bsize; + secsize = src->scgp->cap->c_bsize; amount = sectorcount * SECTOR_SIZE; secno = startsecno * (SECTOR_SIZE / secsize); bp = buffer; @@ -88,8 +114,8 @@ readsecs(startsecno, buffer, sectorcount) amt = bufsize; secnum = amt / secsize; - if (read_scsi(scgp, bp, secno, secnum) < 0 || - scg_getresid(scgp) != 0) { + if (read_scsi(src->scgp, bp, secno, secnum) < 0 || + scg_getresid(src->scgp) != 0) { #ifdef OLD return (-1); #else @@ -104,7 +130,7 @@ readsecs(startsecno, buffer, sectorcount) return (SECTOR_SIZE * sectorcount); } - f = fileno(in_image); + f = fileno(src->file); if (lseek(f, (off_t)startsecno * SECTOR_SIZE, SEEK_SET) == (off_t)-1) { comerr(_("Seek error on old image\n")); @@ -125,13 +151,61 @@ readsecs(startsecno, buffer, sectorcount) return (sectorcount * SECTOR_SIZE); } -EXPORT int +EXPORT BOOL scsidev_has_error (src) + struct scsi_dev *src; +{ + if (NULL == src || ScsiOpenErr_Ok != src->err) + return TRUE; + else + return FALSE; +} + +EXPORT int scsidev_error_code (src) + struct scsi_dev *src; +{ + if (NULL == src) + return ScsiOpenErr_Invalid; + else + return src->err; +} + +EXPORT const char* scsidev_error_desc (code) + int code; +{ + switch (code) { + case ScsiOpenErr_Timeout: + return "Timeout waiting for device"; + case ScsiOpenErr_CantIO: + return "Cannot get SCSI I/O buffer"; + case ScsiOpenErr_CantOpen: + return "Cannot open SCSI driver"; + case ScsiOpenErr_Invalid: + return "Invalid device handle"; + default: + return ""; + } +} + +EXPORT struct scsi_dev* +scsidev_file_open (path) + const char* path; +{ + struct scsi_dev *retval; + + retval = (struct scsi_dev*)malloc(sizeof(*retval)); + memset(retval, 0, sizeof(*retval)); + retval->file = fopen(path, "rb"); + return retval; +} + +EXPORT struct scsi_dev* scsidev_open(path) char *path; { char errstr[80]; char *buf; /* ignored, bit OS/2 ASPI layer needs memory which */ /* has been allocated by scsi_getbuf() */ + struct scsi_dev *retval; /* * Call scg_remote() to force loading the remote SCSI transport library @@ -142,42 +216,56 @@ scsidev_open(path) cdr_defaults(&path, NULL, NULL, NULL, NULL); /* path, debug, verboseopen */ - scgp = scg_open(path, errstr, sizeof (errstr), 0, 0); - if (scgp == 0) { - errmsg(_("%s%sCannot open SCSI driver.\n"), errstr, errstr[0]?". ":""); - return (-1); + retval = (struct scsi_dev*)malloc(sizeof(*retval)); + memset(retval, 0, sizeof(*retval)); + + retval->scgp = scg_open(path, errstr, sizeof (errstr), 0, 0); + if (retval->scgp == 0) { + retval->err = ScsiOpenErr_CantOpen; + return retval; } - bufsize = scg_bufsize(scgp, BUF_SIZE); - if ((buf = scg_getbuf(scgp, bufsize)) == NULL) { - errmsg(_("Cannot get SCSI I/O buffer.\n")); - scg_close(scgp); - return (-1); + bufsize = scg_bufsize(retval->scgp, BUF_SIZE); + if ((buf = scg_getbuf(retval->scgp, bufsize)) == NULL) { + retval->err = ScsiOpenErr_CantIO; + scg_close(retval->scgp); + retval->scgp = NULL; + return retval; } bufsize = (bufsize / SECTOR_SIZE) * SECTOR_SIZE; - allow_atapi(scgp, TRUE); + allow_atapi(retval->scgp, TRUE); - if (!wait_unit_ready(scgp, 60)) { /* Eat Unit att / Wait for drive */ - return (-1); + if (!wait_unit_ready(retval->scgp, 60)) { /* Eat Unit att / Wait for drive */ + retval->err = ScsiOpenErr_Timeout; + return retval; } - scgp->silent++; - read_capacity(scgp); /* Set Capacity/Sectorsize for I/O */ - scgp->silent--; + retval->scgp->silent++; + read_capacity(retval->scgp); /* Set Capacity/Sectorsize for I/O */ + retval->scgp->silent--; - return (1); + return retval; } EXPORT int -scsidev_close() +scsidev_close(struct scsi_dev *f) { - if (in_image == NULL) { - return (scg_close(scgp)); - } else { - return (fclose(in_image)); + int retval; + + if (NULL == f) + return 0; + + retval = 0; + if (f->scgp != NULL) { + retval = scg_close(f->scgp); } + if (f->file != NULL) { + retval = fclose(f->file); + } + free(f); + return (retval); } #endif /* USE_SCG */ diff --git a/subprojects/isoinfo/src/scsi.h b/subprojects/isoinfo/src/scsi.h index a242bf8..09d49c6 100644 --- a/subprojects/isoinfo/src/scsi.h +++ b/subprojects/isoinfo/src/scsi.h @@ -10,11 +10,17 @@ /* * Implemented inside multi.c in case that USE_SCG has not been defined. */ -extern int readsecs __PR((UInt32_t startsecno, void *buffer, int sectorcount)); +struct scsi_dev; + +extern int readsecs __PR((struct scsi_dev* src, UInt32_t startsecno, void *buffer, int sectorcount)); +extern BOOL scsidev_has_error __PR((struct scsi_dev *dev)); +extern int scsidev_error_code __PR((struct scsi_dev *dev)); +extern const char* scsidev_error_desc __PR((int code)); #ifdef USE_SCG -extern int scsidev_open __PR((char *path)); -extern int scsidev_close __PR((void)); +extern struct scsi_dev* scsidev_open __PR((char *path)); +extern struct scsi_dev* scsidev_file_open __PR((const char *path)); +extern int scsidev_close __PR((struct scsi_dev *f)); #endif #endif /* _SCSI_H */