From 0f0a2e4bb59b34e109019a7eb2ee963cd3e80268 Mon Sep 17 00:00:00 2001 From: Thomas Schmitt Date: Sat, 9 Aug 2008 16:14:16 +0000 Subject: [PATCH] Evaluating readability of media --- xorriso/xorriso.c | 276 +++++++++++++++++++++++++++++++++++- xorriso/xorriso_private.h | 28 ++++ xorriso/xorriso_timestamp.h | 2 +- xorriso/xorrisoburn.c | 185 ++++++++++++++++++++++++ xorriso/xorrisoburn.h | 23 +++ 5 files changed, 512 insertions(+), 2 deletions(-) diff --git a/xorriso/xorriso.c b/xorriso/xorriso.c index fd36b6aa..ba125db3 100644 --- a/xorriso/xorriso.c +++ b/xorriso/xorriso.c @@ -2800,6 +2800,198 @@ int Permstack_pop(struct PermiteM **o, struct PermiteM *stopper, /* ---------------------------- End PermstacK ----------------------------- */ +/* ------------------------------ SpotlisT -------------------------------- */ + +struct SpotlistiteM { + int start_lba; + int blocks; + int quality; + struct SpotlistiteM *next; +}; + + +int Spotlistitem_new(struct SpotlistiteM **o, int start_lba, int blocks, + int quality, int flag) +{ + struct SpotlistiteM *m; + + m= TSOB_FELD(struct SpotlistiteM,1); + if(m==NULL) + return(-1); + *o= m; + m->start_lba= start_lba; + m->blocks= blocks; + m->quality= quality; + m->next= NULL; + return(1); +} + + +int Spotlistitem_destroy(struct SpotlistiteM **o, int flag) +{ + if((*o) == NULL) + return(0); + free((char *) *o); + *o= NULL; + return(1); +} + + +struct SpotlisT { + struct SpotlistiteM *list_start; + struct SpotlistiteM *list_end; + int list_count; + struct SpotlistiteM *current_item; + int current_idx; +}; + + +int Spotlist_new(struct SpotlisT **o, int flag) +{ + struct SpotlisT *m; + + m= TSOB_FELD(struct SpotlisT,1); + if(m==NULL) + return(-1); + *o= m; + m->list_start= NULL; + m->list_end= NULL; + m->list_count= 0; + m->current_item= NULL; + m->current_idx= -1; + return(1); +} + + +int Spotlist_destroy(struct SpotlisT **o, int flag) +{ + struct SpotlisT *m; + struct SpotlistiteM *li, *next_li; + + if((*o) == NULL) + return(0); + m= *o; + for(li= m->list_start; li != NULL; li= next_li) { + next_li= li->next; + Spotlistitem_destroy(&li, 0); + } + free((char *) *o); + *o= NULL; + return(1); +} + + +int Spotlist_add_item(struct SpotlisT *o, int start_lba, int blocks, + int quality, int flag) +{ + int ret; + struct SpotlistiteM *li; + + ret= Spotlistitem_new(&li, start_lba, blocks, quality, 0); + if(ret <= 0) + return(ret); + if(o->list_end != NULL) + o->list_end->next= li; + o->list_end= li; + if(o->list_start == NULL) + o->list_start= li; + (o->list_count)++; + + /* <<< */ +{char quality_name[80]; + fprintf(stderr, "debug: lba %10d , size %10d , quality %s\n", + start_lba, blocks, Spotlist__quality_name(quality, quality_name, 0)); +} + + return(1); +} + + +int Spotlist_count(struct SpotlisT *o, int flag) +{ + return o->list_count; +} + + +int Spotlist_get_item(struct SpotlisT *o, int idx, + int *start_lba, int *blocks, int *quality, int flag) +{ + int i; + struct SpotlistiteM *li; + + if(idx < 0 || idx > o->list_count) + return(0); + if(idx == o->current_idx) + li= o->current_item; + else if(idx == o->current_idx) { + li= o->current_item->next; + } else { + li= o->list_start; + for(i= 0; i < idx; i++) + li= li->next; + } + o->current_item= li; + o->current_idx= idx; + *start_lba= li->start_lba; + *blocks= li->blocks; + *quality= li->quality; + return(1); +} + + +char *Spotlist__quality_name(int quality, char name[80], int flag) +{ + if(quality == Xorriso_read_quality_gooD) + strcpy(name, "good"); + else if(quality == Xorriso_read_quality_sloW) + strcpy(name, "slow"); + else if(quality == Xorriso_read_quality_off_tracK) + strcpy(name, "off track"); + else if(quality == Xorriso_read_quality_untesteD) + strcpy(name, "untested"); + else if(quality == Xorriso_read_quality_unreadablE) + strcpy(name, "unreadable"); + else + sprintf(name, "0x%8.8X\n", (unsigned) quality); + return(name); +} + + +/* ---------------------------- End SpotlisT ------------------------------ */ + +/* ---------------------------- CheckmediajoB ----------------------------- */ + +int Checkmediajob_new(struct CheckmediajoB **o, int flag) +{ + struct CheckmediajoB *m; + + m= TSOB_FELD(struct CheckmediajoB,1); + if(m==NULL) + return(-1); + *o= m; + m->min_lba= -1; + m->max_lba= -1; + m->min_block_size= 16; + m->mode= 1; + m->start_time= time(NULL); + m->time_limit= -1; + m->item_limit= -1; + return(1); +} + + +int Checkmediajob_destroy(struct CheckmediajoB **o, int flag) +{ + if((*o) == NULL) + return(0); + free((char *) *o); + *o= NULL; + return(1); +} + + +/* -------------------------- End CheckmediajoB --------------------------- */ + /* ------------------------------- Xorriso -------------------------------- */ @@ -8684,6 +8876,78 @@ int Xorriso_option_cdx(struct XorrisO *xorriso, char *disk_path, int flag) } +/* Option -check_media */ +int Xorriso_option_check_media(struct XorrisO *xorriso, + int argc, char **argv, int *idx, int flag) +{ + int ret, i, count, lba, blocks, quality; + int end_idx, old_idx; + char quality_name[80]; + double num; + struct SpotlisT *spotlist= NULL; + struct CheckmediajoB *job= NULL; + + old_idx= *idx; + end_idx= Xorriso_end_idx(xorriso, argc, argv, *idx, 1); + (*idx)= end_idx; + + ret= Checkmediajob_new(&job, 0); + if(ret <= 0) + goto ex; + + for(i= old_idx; i < end_idx; i++) { + if(strncmp(argv[i], "max_lba=", 8) == 0 || + strncmp(argv[i], "min_lba=", 8) == 0) { + num= -1; + sscanf(argv[i] + 8, "%lf", &num); + if(num > 0x7fffffff || num < 0) + num= -1; + if(strncmp(argv[i], "max_lba=", 8) == 0) + job->max_lba= num; + else + job->min_lba= num; + } else if(strncmp(argv[i], "time_limit=", 11) == 0 || + strncmp(argv[i], "item_limit=", 11) == 0 ) { + num= -1; + sscanf(argv[i] + 11, "%lf", &num); + if(num > 0x7fffffff || num < 0) + num= -1; + if(strncmp(argv[i], "time_limit=", 11) == 0) + job->time_limit= num; + else + job->item_limit= num; + } else { + sprintf(xorriso->info_text, "-check_media: Unknown option %s", argv[i]); + Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0); + ret= 0; goto ex; + } + } + + ret= Xorriso_check_media(xorriso, &spotlist, job, 0); + if(ret <= 0) + goto ex; + + sprintf(xorriso->result_line, + "MCL layout : lba , size , quality\n"); + Xorriso_result(xorriso,0); + count= Spotlist_count(spotlist, 0); + for(i= 0; i < count; i++) { + ret= Spotlist_get_item(spotlist, i, &lba, &blocks, &quality, 0); + if(ret <= 0) + continue; + sprintf(xorriso->result_line, "MCL item : %10d , %10d , %s\n", + lba, blocks, Spotlist__quality_name(quality, quality_name, 0)); + Xorriso_result(xorriso,0); + } + + ret= 1; +ex:; + Spotlist_destroy(&spotlist, 0); + Checkmediajob_destroy(&job, 0); + return(ret); +} + + /* Option -chgrp alias -chgrpi , chgrp_r alias chgrpi */ /* @param flag bit0=recursive (-chgrp_r) */ @@ -10181,6 +10445,12 @@ int Xorriso_option_help(struct XorrisO *xorriso, int flag) " -paste_in iso_rr_path disk_path byte_offset byte_count", " Copy ISO file content into a byte interval of a disk file.", "", +"Evaluation of readability:", +" -check_media [options] --", +" Try to read data blocks from media and report about the", +" outcome. Several options modify the behavior:", +" min_lba= , max_lba= , time_limit= , item_limit=", +"", "Compatibility emulation (argument list may be ended by --):", " -as mkisofs [-help|-version|-o|-R|-J|-V|-P|-f|-m|-exclude-list|-no-pad|", " -M|-C|-graft-points|-path-list|pathspecs]", @@ -12233,7 +12503,8 @@ int Xorriso_count_args(struct XorrisO *xorriso, int argc, char **argv, "" }; static char argn_commands[][40]= { - "add","as","chgrp","chgrpi","chgrp_r","chgrp_ri","chmod","chmodi", + "add","as", + "check_media","chgrp","chgrpi","chgrp_r","chgrp_ri","chmod","chmodi", "chmod_r","chmod_ri","chown","chowni","chown_r","chown_ri", "compare_l","cpr","cpri","cp_rax","cp_rx","cpax","cpx", "du","dui","dus","dusi","dux","dusx","extract_l","find","findi","findx", @@ -12398,6 +12669,9 @@ next_command:; (*idx)++; ret= Xorriso_option_cdx(xorriso, arg1, 0); + } else if(strcmp(cmd,"check_media")==0) { + ret= Xorriso_option_check_media(xorriso, argc, argv, idx, 0); + } else if(strcmp(cmd,"chgrp")==0 || strcmp(cmd,"chgrpi")==0) { (*idx)+= 1; ret= Xorriso_option_chgrpi(xorriso, arg1, argc, argv, idx, 0); diff --git a/xorriso/xorriso_private.h b/xorriso/xorriso_private.h index 2d1d44e9..19325370 100644 --- a/xorriso/xorriso_private.h +++ b/xorriso/xorriso_private.h @@ -48,6 +48,8 @@ struct LinkiteM; /* Trace of hops during symbolic link resolution */ struct ExclusionS; /* List of -not_* conditions */ struct PermiteM; /* Stack of temporarily altered access permissions */ +struct SpotlisT; /* List of intervals with different read qualities */ +struct CheckmediajoB; /* Parameters for Xorriso_check_media() */ /* maximum number of history lines to be reported with -status:long_history */ @@ -614,5 +616,31 @@ int Permstack_pop(struct PermiteM **o, struct PermiteM *stopper, struct XorrisO *xorriso, int flag); +int Spotlist_new(struct SpotlisT **o, int flag); + +int Spotlist_destroy(struct SpotlisT **o, int flag); + +int Spotlist_add_item(struct SpotlisT *o, int start_lba, int blocks, + int quality, int flag); + +int Spotlist_count(struct SpotlisT *o, int flag); + +int Spotlist_get_item(struct SpotlisT *o, int idx, + int *start_lba, int *blocks, int *quality, int flag); + +char *Spotlist__quality_name(int quality, char name[80], int flag); + + +#define Xorriso_read_quality_gooD 0x7fffffff +#define Xorriso_read_quality_sloW 0x40000000 +#define Xorriso_read_quality_off_tracK 0x08000000 +#define Xorriso_read_quality_untesteD 0x04000000 +#define Xorriso_read_quality_unreadablE 0x00000000 + + +int Checkmediajob_new(struct CheckmediajoB **o, int flag); + +int Checkmediajob_destroy(struct CheckmediajoB **o, int flag); + #endif /* Xorriso_private_includeD */ diff --git a/xorriso/xorriso_timestamp.h b/xorriso/xorriso_timestamp.h index 2ea4ae8e..629db2f0 100644 --- a/xorriso/xorriso_timestamp.h +++ b/xorriso/xorriso_timestamp.h @@ -1 +1 @@ -#define Xorriso_timestamP "2008.08.09.160947" +#define Xorriso_timestamP "2008.08.09.161311" diff --git a/xorriso/xorrisoburn.c b/xorriso/xorrisoburn.c index 0ab05465..25f54713 100644 --- a/xorriso/xorrisoburn.c +++ b/xorriso/xorrisoburn.c @@ -6557,3 +6557,188 @@ int Xorriso_msinfo(struct XorrisO *xorriso, int *msc1, int *msc2, int flag) return(1); } + +int Xorriso_check_interval(struct XorrisO *xorriso, struct SpotlisT *spotlist, + struct CheckmediajoB *job, + int from_lba, int block_count, + int read_chunk, int min_block_size, int flag) +{ + int i, ret, total_count= 0; + int prev_quality= -1, quality= -1; + int start_lba= 0; + struct burn_drive *drive; + struct burn_drive_info *dinfo; + char data[64*1024]; + off_t data_count, to_read; + double pre_read_time, post_read_time, time_diff, total_time_diff= 0; + + ret= Xorriso_get_drive_handles(xorriso, &dinfo, &drive, + "on attempt to check media readability", 0); + if(ret<=0) + goto ex; + + start_lba= from_lba; + for(i= 0; i < block_count; i+= read_chunk) { + if(job->item_limit > 0 && + Spotlist_count(spotlist, 0) + 2 >= job->item_limit) { + sprintf(xorriso->info_text, "-check_media: Reached item_limit=%d", + job->item_limit); + Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "NOTE", 0); + goto abort_check; + } + pre_read_time= Sfile_microtime(0); + if(job->time_limit > 0 + && job->start_time + job->time_limit < pre_read_time) { + sprintf(xorriso->info_text, "-check_media: Reached time_limit=%d", + job->time_limit); + Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "NOTE", 0); +abort_check:; + if(prev_quality >= 0) { + ret= Spotlist_add_item(spotlist, start_lba, i + from_lba - start_lba, + prev_quality, 0); + if(ret <= 0) + goto ex; + } + ret= Spotlist_add_item(spotlist, i + from_lba, block_count - 1, + Xorriso_read_quality_untesteD, 0); + if(ret > 0) + ret= 2; + goto ex; + } + to_read= read_chunk; + if(i + to_read > block_count) + to_read= block_count - i; + ret= burn_read_data(drive, ((off_t) (i + from_lba)) * (off_t) 2048, data, + to_read * (off_t) 2048, &data_count, 4); + post_read_time= Sfile_microtime(0); + time_diff= post_read_time - pre_read_time; + total_time_diff+= time_diff; + total_count++; + if(ret <= 0) { + Xorriso_process_msg_queues(xorriso,0); + quality= Xorriso_read_quality_unreadablE; + if(read_chunk > min_block_size) { + + /* >>> evaluate min blocks */; + + } + } else { + quality= Xorriso_read_quality_gooD; + + /* >>> find better threshold than 1.0 */ + + if(time_diff > 1.0 && i > 0) + quality= Xorriso_read_quality_sloW; + } + if(quality != prev_quality) { + if(prev_quality >= 0) { + ret= Spotlist_add_item(spotlist, start_lba, i + from_lba - start_lba, + prev_quality, 0); + if(ret <= 0) + goto ex; + } + start_lba= i + from_lba; + prev_quality= quality; + } + xorriso->pacifier_count+= to_read; + if(post_read_time - xorriso->last_update_time >= xorriso->pacifier_interval) + Xorriso_pacifier_callback(xorriso, "sectors examined", + xorriso->pacifier_count, xorriso->pacifier_total, "", 0); + } + if(prev_quality >= 0) { + ret= Spotlist_add_item(spotlist, start_lba, + block_count + from_lba - start_lba, prev_quality, 0); + if(ret <= 0) + goto ex; + } + + /* <<< for calibration of quality */ + if(total_count > 0) { + sprintf(xorriso->info_text, "Xorriso_check_interval: %.1f s / %d = %f", + total_time_diff, total_count, total_time_diff / total_count); + Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "DEBUG", 0); + } + + ret= 1; +ex: + return(ret); +} + + +int Xorriso_check_media(struct XorrisO *xorriso, struct SpotlisT **spotlist, + struct CheckmediajoB *job, int flag) +{ + int media_blocks= 0, read_chunk= 16, ret, mode, min_block_size, start_lba= 0; + int blocks; + struct burn_drive *drive; + struct burn_drive_info *dinfo; + struct isoburn_toc_disc *isoburn_disc= NULL; + + *spotlist= NULL; + + ret= Xorriso_get_drive_handles(xorriso, &dinfo, &drive, + "on attempt to check media readability", 0); + if(ret<=0) + goto ex; + + /* >>> determine media type dependent blocking factor: + 2 kB for CD and disk , 32 kB for DVD, 64 kB for BD + eventually adjust min_block_size and read_chunk + */; + /* <<< */ + min_block_size= read_chunk; + + ret= Spotlist_new(spotlist, 0); + if(ret <= 0) + {ret= -1; goto ex;} + + Xorriso_pacifier_reset(xorriso, 0); + job->start_time= time(NULL); + mode= job->mode; + if(job->min_lba >= 0) + start_lba= job->min_lba; + if(job->max_lba >= 0) { + blocks= job->max_lba - start_lba; + xorriso->pacifier_total= blocks; + ret= Xorriso_check_interval(xorriso, *spotlist, job, start_lba, blocks, + read_chunk, min_block_size, 0); + if(ret <= 0) + goto ex; + + } else if(mode == 0) { + + /* >>> track by track */; + + } else if(mode == 1) { + isoburn_disc= isoburn_toc_drive_get_disc(drive); + if(isoburn_disc == NULL) { +no_content_visible:; + Xorriso_process_msg_queues(xorriso,0); + sprintf(xorriso->info_text, "No content detected on media"); + Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0); + {ret= 0; goto ex;} + } + blocks= media_blocks= isoburn_toc_disc_get_sectors(isoburn_disc); + if(start_lba >= 0) + blocks-= start_lba; + if(media_blocks <= 0) + goto no_content_visible; + xorriso->pacifier_total= blocks; + ret= Xorriso_check_interval(xorriso, *spotlist, job, start_lba, blocks, + read_chunk, min_block_size, 0); + if(ret <= 0) + goto ex; + } else if(mode == 2) { + + /* >>> single sweep over libburn media capacity */; + + } + + Xorriso_pacifier_callback(xorriso, "sectors examined", + xorriso->pacifier_count, xorriso->pacifier_total, "", 1); + ret= 1; +ex:; + if(ret < 0) + Spotlist_destroy(spotlist, 0); + return(ret); +} diff --git a/xorriso/xorrisoburn.h b/xorriso/xorrisoburn.h index c910d6bc..3a12171a 100644 --- a/xorriso/xorrisoburn.h +++ b/xorriso/xorrisoburn.h @@ -16,6 +16,7 @@ struct XorrisO; struct FindjoB; +struct SpotlisT; /* The minimum version of libisoburn to be used with this version of xorriso */ @@ -280,5 +281,27 @@ int Xorriso_libburn_adr(struct XorrisO *xorriso, char *address_string, int Xorriso_msinfo(struct XorrisO *xorriso, int *msc1, int *msc2, int flag); +struct CheckmediajoB { + int min_lba; /* if >=0 : begin checking at this address */ + int max_lba; /* if >=0 : read up to this address, else use mode */ + + int min_block_size; /* >>> not yet implemented: + granularity desired by user + */ + int mode; /* >>> 0= track by track + 1= single sweep over libisoburn media capacity + >>> 2= single sweep over libburn media capacity + */ + time_t start_time; + int time_limit; /* Number of seconds after which to abort */ + + int item_limit; /* Maximum number of media check list items as result */ + +}; + +int Xorriso_check_media(struct XorrisO *xorriso, struct SpotlisT **spotlist, + struct CheckmediajoB *job, int flag); + + #endif /* Xorrisoburn_includeD */