diff --git a/test/testburner.c b/test/testburner.c deleted file mode 100644 index 2558242..0000000 --- a/test/testburner.c +++ /dev/null @@ -1,783 +0,0 @@ - -/* test/testburner.c is an experimental version of test/libburner.c - published for enabling tests of upcoming libburn features or gestures -*/ - -/* This test is about a way to drop unwanted drives without shutting down - and re-initializing libburn. It is expected to do fine on systems with - a single drive because it will do not drop any drive then. - - The experiments will need a system with at least two burner drives. - Load both drives with blank media. The example experiments try to simulate - the burn, but better use CD-RW media. - - The goal is to operate one burner while the other stays still visible to - libburn and can be used too, provided your system is able - mine would do - poorly. With 4x media ... maybe. - - Terminal 1: - echo | \ - test/testburner --test_ticket_62 --drive 0 --stdin_size 681574400 - - - Do not interrupt this run ! Use smaller --stdin_size to pseudo-burn less - than 650 MB. - (Best is to have "cdrecord dev=... -reset" ready in Terminal 3.) - - Terminal 2 (while burn on terminal 1 is running): - test/testburner --drive - - - You should get listed the other drive and the busy one should not appear. - - Terminal 2 (while terminal 1 still burning): - echo | \ - test/testburner --test_ticket_62 --drive 0 --stdin_size 10000000 - - - This should start a burn on your second drive. Wether throughput is - acceptable will depend on your system backbone. - - Yes, if all goes well, both drives will have address 0. Usually i am much - in favor of using persistent addresses (/dev/hdc, /dev/sg0) but this test - is all about bus scan and dropping unneeded drives. - - So taste the oddities of this approach :)) - -*/ -static int test_ticket_62= 0; - - -/* test/libburner.c , API illustration of burning a single data track to CD */ -/* Copyright (C) 2005 - 2006 Thomas Schmitt */ -/* Provided under GPL, see also "License and copyright aspects" at file end */ - - -/** IMPORTANT: By default this program tries to make a simulated burn - on the CD recorder. Some obey, some do not. - If you want to burn really readable CD for sure by default, - then set this macro to 0 . - Explicit options: --burn_for_real and --try_to_simulate -*/ -#define Libburner_try_to_simulatE 1 - -/** Overview - - libburner is a minimal demo application for the library libburn as provided - on http://libburn.pykix.org . It can list the available devices, can - blank a CD-RW and can burn to CD-R or CD-RW. - It's main purpose, nevertheless, is to show you how to use libburn and also - to serve the libburn team as reference application. libburner.c does indeed - define the standard way how above three gestures can be implemented and - stay upward compatible for a good while. - - Before you can do anything, you have to initialize libburn by - burn_initialize() - as it is done in main() at the end of this file. Then you aquire a - drive in an appropriate way conforming to the API. The two main - approaches are shown here in application functions: - libburner_aquire_by_adr() demonstrates usage as of cdrecord traditions - libburner_aquire_by_driveno() demonstrates a scan-and-choose approach - With that aquired drive you blank a CD-RW - libburner_blank_disc() - Between blanking and burning one eventually has to reload the drive status - libburner_regrab() - With the aquired drive you can burn to CD-R or blank CD-RW - libburner_payload() - When everything is done, main() releases the drive and shuts down libburn: - burn_drive_release(); - burn_finish() - -*/ - -/* We shall prepare for times when more than 2 GB of data are to be handled. - This gives POSIX-ly 64 bit off_t */ -#ifndef _LARGEFILE_SOURCE -#define _LARGEFILE_SOURCE 1 -#endif -#ifndef _FILE_OFFSET_BITS -#define _FILE_OFFSET_BITS 64 -#endif - -/** See this for the decisive API specs . libburn.h is The Original */ -#include - -/* libburn is intended for Linux systems with kernel 2.4 or 2.6 for now */ -#include -#include -#include -#include -#include -#include -#include -#include - - -/** For simplicity i use global variables to represent the drives. - Drives are systemwide global, so we do not give away much of good style. -*/ - -/** This list will hold the drives known to libburn. This might be all CD - drives of the system and thus might impose severe impact on the system. -*/ -static struct burn_drive_info *drive_list; - -/** If you start a long lasting operation with drive_count > 1 then you are - not friendly to the users of other drives on those systems. Beware. */ -static unsigned int drive_count; - -/** This variable indicates wether the drive is grabbed and must be - finally released */ -static int drive_is_grabbed = 0; - -/** Wether to burn for real or to *try* to simulate a burn */ -static int simulate_burn = Libburner_try_to_simulatE ; - - -/* Some in-advance definitions to allow a more comprehensive ordering - of the functions and their explanations in here */ -int libburner_aquire_by_adr(char *drive_adr); -int libburner_aquire_by_driveno(int *drive_no); - - -/* ------------------------------- API gestures ---------------------------- */ - -/** You need to aquire a drive before burning. The API offers this as one - compact call and alternatively as application controllable gestures of - whitelisting, scanning for drives and finally grabbing one of them. - - If you have a persistent address of the drive, then the compact call is - to prefer. It avoids a shutdown-init cycle of libburn and thus is more - safe against race conditions between competing users of that drive. - On modern Linux kernels, race conditions are supposed to end up by - having one single winner or by having all losers. On modern Linux - kernels, there should be no fatal disturbance of ongoing burns - of other libburn instances. We use open(O_EXCL) by default. - There are variants of cdrecord which participate in advisory O_EXCL - locking of block devices. Others possibly don't. Some kernels do - nevertheless impose locking on open drives anyway (e.g. SuSE 9.0, 2.4.21). -*/ -int libburner_aquire_drive(char *drive_adr, int *driveno) -{ - int ret; - - if(drive_adr != NULL && drive_adr[0] != 0) - ret = libburner_aquire_by_adr(drive_adr); - else - ret = libburner_aquire_by_driveno(driveno); - return ret; -} - - -/** If the persistent drive address is known, then this approach is much - more un-obtrusive to the systemwide livestock of drives. Only the - given drive device will be opened during this procedure. -*/ -int libburner_aquire_by_adr(char *drive_adr) -{ - int ret; - - printf("Aquiring drive '%s' ...\n",drive_adr); - ret = burn_drive_scan_and_grab(&drive_list,drive_adr,1); - if (ret <= 0) { - fprintf(stderr,"FAILURE with persistent drive address '%s'\n", - drive_adr); - if (strncmp(drive_adr,"/dev/sg",7) != 0 && - strncmp(drive_adr,"/dev/hd",7) != 0) - fprintf(stderr,"\nHINT: Consider addresses like '/dev/hdc' or '/dev/sg0'\n"); - } else { - printf("done\n"); - drive_is_grabbed = 1; - } - return ret; -} - - -/** The upcoming method to drop unwanted drives combined with a workaround - for a drive status flaw in libburn which has to be solved yet. - @param driveno pointer to integer number of drive we want to use - (pointer, because this is to be integrated in - libburner_aquire_by_driveno()) - @return <= 0 indicates failure, 1 is success -*/ -int libburner_drop_unwanted_and_grab(int *driveno) -{ - int i, ret= 1; - - printf("--test_ticket_62: The experiment begins ...\n"); - - /* Drop all drives which you do not want to use */ - for (i = 0; i < drive_count; i++) { - if (i == *driveno) /* the one drive we want to keep */ - continue; - printf("--test_ticket_62: Dropping drive %d\n",i); - ret = burn_drive_info_forget(&(drive_list[i]),0); - if (ret != 1) - break; - } - if (i < drive_count) { - fprintf(stderr, "--test_ticket_62: burn_drive_info_forget() returns %d\n",ret); - fprintf(stderr, "--test_ticket_62: Will follow the better explored ways of finish-initialize\n"); - return 0; - } - printf("--test_ticket_62: Looks good so far ...\n"); - -#ifdef Testburner_release_and_grab_agaiN - /* Load the drive tray and avoid a bug in libburn burn_drive_grab() */ - /* Some systems produce a false status if tray was unloaded */ - /* Therefore the first grab is just for loading */ - ret= burn_drive_grab(drive_list[*driveno].drive, 1); - if (ret != 1) - return 0; - burn_drive_release(drive_list[*driveno].drive, 0); -#else - printf("--test_ticket_62: Skipped extra release and grab cycle\n"); -#endif /* ! Testburner_release_and_grab_agaiN */ - - /* now grab for real */ - ret= burn_drive_grab(drive_list[*driveno].drive, 1); - if (ret != 1) - return 0; - drive_is_grabbed = 1; - - printf("--test_ticket_62: libburner_drop_unwanted_and_grab() successful\n"); - - return 1; -} - -/** This method demonstrates how to use libburn without knowing a persistent - drive address in advance. It has to make sure that after assessing the - list of available drives, all drives get closed again. Only then it is - sysadmin-acceptable to aquire the desired drive for a prolonged time. - This drive closing is enforced here by shutting down libburn and - restarting it again with the much more un-obtrusive approach to use - a persistent address and thus to only touch the one desired drive. - @param driveno the index number in libburn's drive list. This will get - set to 0 on success and will then be the drive index to - use in the further dourse of processing. - @return 1 success , <= 0 failure -*/ -int libburner_aquire_by_driveno(int *driveno) -{ - char adr[BURN_DRIVE_ADR_LEN]; - int ret= 0, i; - - printf("Beginning to scan for devices ...\n"); - while (!burn_drive_scan(&drive_list, &drive_count)) - usleep(1002); - if (drive_count <= 0 && *driveno >= 0) { - printf("FAILED (no drives found)\n"); - return 0; - } - printf("done\n"); - - /* Interactive programs may choose the drive number at this moment. - - drive[0] to drive[drive_count-1] are struct burn_drive_info - as defined in libburn/libburn.h . This structure is part of API - and thus will strive for future compatibility on source level. - Have a look at the info offered. - Caution: do not take .location for drive address. Always use - burn_drive_get_adr() or you might become incompatible - in future. - Note: bugs with struct burn_drive_info - if any - will not be - easy to fix. Please report them but also strive for - workarounds on application level. - */ - printf("\nOverview of accessible drives (%d found) :\n", - drive_count); - printf("-----------------------------------------------------------------------------\n"); - for (i = 0; i < drive_count; i++) { - if (burn_drive_get_adr(&(drive_list[i]), adr) <=0) - strcpy(adr, "-get_adr_failed-"); - printf("%d --drive '%s' : '%s' '%s'\n", - i,adr,drive_list[i].vendor,drive_list[i].product); - } - printf("-----------------------------------------------------------------------------\n\n"); - - if (*driveno < 0) { - printf("Pseudo-drive \"-\" given : bus scanning done.\n"); - return 2; /* only return 1 will cause a burn */ - } - - /* We already made our choice via command line. (default is 0) */ - if (drive_count <= *driveno || *driveno < 0) { - fprintf(stderr, - "Found only %d drives. Number %d not available.\n", - drive_count, *driveno); - return 0; - } - - - /* Now save yourself from sysadmins' revenge */ - - /* If drive_count == 1 this would be not really necessary, though. - You could now call burn_drive_grab() and avoid libburn restart. - We don't try to be smart here and follow the API's strong urge. */ - - if (test_ticket_62) { /* a new strong urge emerging : */ - ret = libburner_drop_unwanted_and_grab(driveno); - if (ret == 1) - return 1; - } - - if (burn_drive_get_adr(&(drive_list[*driveno]), adr) <=0) { - fprintf(stderr, - "Cannot inquire persistent drive address of drive number %d\n", - *driveno); - return 0; - } - printf("Detected '%s' as persistent address of drive number %d\n", - adr,*driveno); - - burn_drive_info_free(drive_list); - burn_finish(); - printf( - "Re-Initializing library to release any unintended drives ...\n"); - if (burn_initialize()) - printf("done\n"); - else { - printf("FAILED\n"); - fprintf(stderr,"\nFailed to re-initialize libburn.\n"); - return 0; - } - ret = libburner_aquire_by_adr(adr); - if (ret > 0) - *driveno = 0; - return ret; -} - - -/** Makes a previously used CD-RW ready for thorough re-usal. - - To our knowledge it is hardly possible to abort an ongoing blank operation - because after start it is entirely handled by the drive. - So expect a blank run to survive the end of the blanking process and be - patient for the usual timespan of a normal blank run. Only after that - time has surely elapsed, only then you should start any rescue attempts - with the drive. If necessary at all. -*/ -int libburner_blank_disc(struct burn_drive *drive, int blank_fast) -{ - enum burn_disc_status disc_state; - struct burn_progress progress; - - while (burn_drive_get_status(drive, NULL)) - usleep(1001); - - while ((disc_state = burn_disc_get_status(drive)) == BURN_DISC_UNREADY) - usleep(1001); - printf( - "Drive media status: %d (see libburn/libburn.h BURN_DISC_*)\n", - disc_state); - if (disc_state == BURN_DISC_BLANK) { - fprintf(stderr, - "IDLE: Blank CD media detected. Will leave it untouched\n"); - return 2; - } else if (disc_state == BURN_DISC_FULL || - disc_state == BURN_DISC_APPENDABLE) { - ; /* this is what libburn is willing to blank */ - } else if (disc_state == BURN_DISC_EMPTY) { - fprintf(stderr,"FATAL: No media detected in drive\n"); - return 0; - } else { - fprintf(stderr, - "FATAL: Cannot recognize drive and media state\n"); - return 0; - } - if(!burn_disc_erasable(drive)) { - fprintf(stderr, - "FATAL : Media is not of erasable type\n"); - return 0; - } - printf( - "Beginning to %s-blank CD media.\n", (blank_fast?"fast":"full")); - printf( - "Expect some garbage sector numbers and some zeros at first.\n"); - burn_disc_erase(drive, blank_fast); - while (burn_drive_get_status(drive, &progress)) { - printf("Blanking sector %d\n", progress.sector); - sleep(1); - } - printf("Done\n"); - return 1; -} - - -/** This gesture is necessary to get the drive info after blanking */ -int libburner_regrab(struct burn_drive *drive) { - int ret; - - printf("Releasing and regrabbing drive ...\n"); - if (drive_is_grabbed) - burn_drive_release(drive, 0); - drive_is_grabbed = 0; - ret = burn_drive_grab(drive, 0); - if (ret != 0) { - drive_is_grabbed = 1; - printf("done\n"); - } else - printf("FAILED\n"); - return !!ret; -} - - -/** Brings the preformatted image (ISO 9660, afio, ext2, whatever) onto media. - - To make sure your image is fully readable on any Linux machine, this - function adds 300 kB of padding to the track. - - Without a signal handler it is quite dangerous to abort the process - while this function is active. See cdrskin/cdrskin.c and its usage - of cdrskin/cleanup.[ch] for an example of application provided - abort handling. It must cope with 2 of 3 threads reporting for - being handled. - - Without signal handler have ready a command line - cdrecord dev=... -reset - with a dev= previously inquired by cdrecord [dev=ATA] -scanbus - in order to get your drive out of shock state after raw abort. - Thanks to Joerg Schilling for helping out unquestioned. :) - - In general, libburn is less prone to system problems than cdrecord, - i believe. But cdrecord had long years of time to complete itself. - We are still practicing. Help us with that. :)) -*/ -int libburner_payload(struct burn_drive *drive, const char *source_adr, - off_t size) -{ - struct burn_source *data_src; - struct burn_disc *target_disc; - struct burn_session *session; - struct burn_write_opts *burn_options; - enum burn_disc_status disc_state; - struct burn_track *track; - struct burn_progress progress; - time_t start_time; - int last_sector = 0; - - target_disc = burn_disc_create(); - session = burn_session_create(); - burn_disc_add_session(target_disc, session, BURN_POS_END); - track = burn_track_create(); - - /* a padding of 300 kB is helpful to avoid the read-ahead bug */ - burn_track_define_data(track, 0, 300*1024, 1, BURN_MODE1); - - if (source_adr[0] == '-' && source_adr[1] == 0) { - data_src = burn_fd_source_new(0, -1, size); - printf("Note: using standard input as source with %.f bytes\n", - (double) size); - } else - data_src = burn_file_source_new(source_adr, NULL); - if (data_src == NULL) { - fprintf(stderr, - "FATAL: Could not open data source '%s'.\n",source_adr); - if(errno!=0) - fprintf(stderr,"(Most recent system error: %s )\n", - strerror(errno)); - return 0; - } - - if (burn_track_set_source(track, data_src) != BURN_SOURCE_OK) { - printf("FATAL: Cannot attach source object to track object\n"); - return 0; - } - burn_session_add_track(session, track, BURN_POS_END); - burn_source_free(data_src); - - while (burn_drive_get_status(drive, NULL)) - usleep(1001); - - /* Evaluate drive and media */ - while ((disc_state = burn_disc_get_status(drive)) == BURN_DISC_UNREADY) - usleep(1001); - if (disc_state != BURN_DISC_BLANK) { - if (disc_state == BURN_DISC_FULL || - disc_state == BURN_DISC_APPENDABLE) { - fprintf(stderr, - "FATAL: Media with data detected. Need blank media.\n"); - if (burn_disc_erasable(drive)) - fprintf(stderr, "HINT: Try --blank_fast\n\n"); - } else if (disc_state == BURN_DISC_EMPTY) - fprintf(stderr,"FATAL: No media detected in drive\n"); - else - fprintf(stderr, - "FATAL: Cannot recognize drive and media state\n"); - return 0; - } - - burn_options = burn_write_opts_new(drive); - burn_write_opts_set_perform_opc(burn_options, 0); - -#ifdef Libburner_raw_mode_which_i_do_not_likE - /* This yields higher CD capacity but hampers my IDE controller - with burning on one drive and reading on another simultaneously. - My burner does not obey the order --try_to_simulate in this mode. - */ - burn_write_opts_set_write_type(burn_options, - BURN_WRITE_RAW, BURN_BLOCK_RAW96R); -#else - - /* This is by what cdrskin competes with cdrecord -sao which - i understand is the mode preferrably advised by Joerg Schilling */ - burn_write_opts_set_write_type(burn_options, - BURN_WRITE_SAO, BURN_BLOCK_SAO); - -#endif - if(simulate_burn) - printf("\n*** Will TRY to SIMULATE burning ***\n\n"); - burn_write_opts_set_simulate(burn_options, simulate_burn); - burn_structure_print_disc(target_disc); - burn_drive_set_speed(drive, 0, 0); - burn_write_opts_set_underrun_proof(burn_options, 1); - - printf("Burning starts. With e.g. 4x media expect up to a minute of zero progress.\n"); - start_time = time(0); - burn_disc_write(burn_options, target_disc); - - burn_write_opts_free(burn_options); - while (burn_drive_get_status(drive, NULL) == BURN_DRIVE_SPAWNING) - usleep(1002); - while (burn_drive_get_status(drive, &progress)) { - if( progress.sectors <= 0 || progress.sector == last_sector) - printf( - "Thank you for being patient since %d seconds.\n", - (int) (time(0) - start_time)); - else - printf("Burning sector %d of %d\n", - progress.sector, progress.sectors); - last_sector = progress.sector; - sleep(1); - } - printf("\n"); - burn_track_free(track); - burn_session_free(session); - burn_disc_free(target_disc); - if(simulate_burn) - printf("\n*** Did TRY to SIMULATE burning ***\n\n"); - return 0; -} - - -/** Converts command line arguments into a few program parameters. - drive_adr[] must provide at least BURN_DRIVE_ADR_LEN bytes. - source_adr[] must provide at least 4096 bytes. -*/ -int libburner_setup(int argc, char **argv, char drive_adr[], int *driveno, - int *do_blank, char source_adr[], off_t *size) -{ - int i, insuffient_parameters = 0; - int print_help = 0; - - drive_adr[0] = 0; - *driveno = 0; - *do_blank = 0; - source_adr[0] = 0; - *size = 650*1024*1024; - - for (i = 1; i < argc; ++i) { - if (!strcmp(argv[i], "--blank_fast")) { - *do_blank = 1; - - } else if (!strcmp(argv[i], "--blank_full")) { - *do_blank = 2; - - } else if (!strcmp(argv[i], "--burn_for_real")) { - simulate_burn = 0; - - } else if (!strcmp(argv[i], "--drive")) { - ++i; - if (i >= argc) { - fprintf(stderr,"--drive requires an argument\n"); - return 1; - } else if (strcmp(argv[i], "-") == 0) { - drive_adr[0] = 0; - *driveno = -1; - } else if (isdigit(argv[i][0])) { - drive_adr[0] = 0; - *driveno = atoi(argv[i]); - } else { - if(strlen(argv[i]) >= BURN_DRIVE_ADR_LEN) { - fprintf(stderr,"--drive address too long (max. %d)\n", - BURN_DRIVE_ADR_LEN-1); - return 2; - } - strcpy(drive_adr, argv[i]); - } - } else if (!strcmp(argv[i], "--stdin_size")) { - ++i; - if (i >= argc) { - fprintf(stderr,"--stdin_size requires an argument\n"); - return 3; - } else - *size = atoi(argv[i]); - if (*size < 600*1024) /* seems to be minimum readable track size */ - *size = 600*1024; - } else if (!strcmp(argv[i], "--try_to_simulate")) { - simulate_burn = 1; - - } else if (!strcmp(argv[i], "--verbose")) { - ++i; - if (i >= argc) { - fprintf(stderr,"--verbose requires an argument\n"); - return 4; - } else - burn_set_verbosity(atoi(argv[i])); - } else if (!strcmp(argv[i], "--help")) { - print_help = 1; - - } else if (!strcmp(argv[i], "--test_ticket_62")) { - test_ticket_62= 1; - - } else { - if(strlen(argv[i]) >= 4096) { - fprintf(stderr, "Source address too long (max. %d)\n", 4096-1); - return 5; - } - strcpy(source_adr, argv[i]); - } - } - insuffient_parameters = 1; - if (*driveno < 0) - insuffient_parameters = 0; - if (source_adr[0] != 0) - insuffient_parameters = 0; - if (*do_blank) - insuffient_parameters = 0; - if (print_help || insuffient_parameters ) { - printf("Usage: %s\n", argv[0]); - printf(" [--drive
||\"-\"]\n"); - printf(" [--verbose ] [--blank_fast|--blank_full]\n"); - printf(" [--burn_for_real|--try_to_simulate] [--stdin_size ]\n"); - printf(" [|\"-\"]\n"); - printf(" [--test_ticket_62]\n"); - printf("--test_ticket_62 enables a novel way to drop unwanted drives.\n"); - printf("Examples\n"); - printf("A bus scan (needs rw-permissions to see a drive):\n"); - printf(" %s --drive -\n",argv[0]); - printf("Burn a file to drive chosen by number:\n"); - printf(" %s --drive 0 --burn_for_real my_image_file\n", - argv[0]); - printf("Burn a file to drive chosen by persistent address:\n"); - printf(" %s --drive /dev/hdc --burn_for_real my_image_file\n", argv[0]); - printf("Blank a used CD-RW (is combinable with burning in one run):\n"); - printf(" %s --drive 0 --blank_fast\n",argv[0]); - printf("Burn a compressed afio archive on-the-fly, pad up to 700 MB:\n"); - printf(" ( cd my_directory ; find . -print | afio -oZ - ) | \\\n"); - printf(" %s --drive /dev/hdc --burn_for_real --stdin_size 734003200 -\n", argv[0]); - printf("To be read from *not mounted* CD via:\n"); - printf(" afio -tvZ /dev/hdc\n"); - printf("Program tar would need a clean EOF which our padded CD cannot deliver.\n"); - if (insuffient_parameters) - return 6; - } - return 0; -} - - -int main(int argc, char **argv) -{ - int driveno, ret, do_blank; - char source_adr[4096], drive_adr[BURN_DRIVE_ADR_LEN]; - off_t stdin_size; - - ret = libburner_setup(argc, argv, drive_adr, &driveno, &do_blank, - source_adr, &stdin_size); - if (ret) - exit(ret); - - printf("Initializing library ...\n"); - if (burn_initialize()) - printf("done\n"); - else { - printf("FAILED\n"); - fprintf(stderr,"\nFATAL: Failed to initialize libburn.\n"); - exit(33); - } - - /** Note: driveno might change its value in this call */ - ret = libburner_aquire_drive(drive_adr, &driveno); - if (ret<=0) { - fprintf(stderr,"\nFATAL: Failed to aquire drive.\n"); - { ret = 34; goto finish_libburn; } - } - if (ret == 2) - { ret = 0; goto release_drive; } - if (do_blank) { - ret = libburner_blank_disc(drive_list[driveno].drive, - do_blank == 1); - if (ret<=0) - { ret = 36; goto release_drive; } - if (ret != 2 && source_adr[0] != 0) - ret = libburner_regrab(drive_list[driveno].drive); - if (ret<=0) { - fprintf(stderr, - "FATAL: Cannot release and grab again drive after blanking\n"); - { ret = 37; goto finish_libburn; } - } - } - if (source_adr[0] != 0) { - ret = libburner_payload(drive_list[driveno].drive, source_adr, - stdin_size); - if (ret<=0) - { ret = 38; goto release_drive; } - } - ret = 0; -release_drive:; - if (drive_is_grabbed) - burn_drive_release(drive_list[driveno].drive, 0); - -finish_libburn:; - /* This app does not bother to know about exact scan state. - Better to accept a memory leak here. We are done anyway. */ - /* burn_drive_info_free(drive_list); */ - - burn_finish(); - return ret; -} - - -/* License and copyright aspects: - -This all is provided under GPL. -Read. Try. Think. Play. Write yourself some code. Be free of my copyright. - -Be also invited to study the code of cdrskin/cdrskin.c et al. - - -Clarification in my name and in the name of Mario Danic, copyright holder -on toplevel of libburn. To be fully in effect after the remaining other -copyrighted code has been replaced by ours and by copyright-free contributions -of our friends: - -We, the copyright holders, agree on the interpretation that -dynamical linking of our libraries constitutes "use of" and -not "derivation from" our work in the sense of GPL, provided -those libraries are compiled from our unaltered code. - -Thus you may link our libraries dynamically with applications -which are not under GPL. You may distribute our libraries and -application tools in binary form, if you fulfill the usual -condition of GPL to offer a copy of the source code -altered -or unaltered- under GPL. - -We ask you politely to use our work in open source spirit -and with the due reference to the entire open source community. - -If there should really arise the case where above clarification -does not suffice to fulfill a clear and neat request in open source -spirit that would otherwise be declined for mere formal reasons, -only in that case we will duely consider to issue a special license -covering only that special case. -It is the open source idea of responsible freedom which will be -decisive and you will have to prove that you exhausted all own -means to qualify for GPL. - -For now we are firmly committed to maintain one single license: GPL. - -History: -libburner is a compilation of my own contributions to test/burniso.c and -fresh code which replaced the remaining parts under copyright of -Derek Foreman. -My respect and my thanks to Derek for providing me a start back in 2005. - -*/ -