"Fossies" - the Fresh Open Source Software Archive

Member "xorriso-1.5.4/libburn/file.c" (30 Jan 2021, 28421 Bytes) of package /linux/misc/xorriso-1.5.4.pl02.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "file.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 1.5.2_vs_1.5.4.

    1 /* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
    2 
    3 /* Copyright (c) 2004 - 2006 Derek Foreman, Ben Jansens
    4    Copyright (c) 2006 - 2017 Thomas Schmitt <scdbackup@gmx.net>
    5    Provided under GPL version 2 or later.
    6 */
    7 
    8 
    9 #ifdef HAVE_CONFIG_H
   10 #include "../config.h"
   11 #endif
   12 
   13 
   14 #include <stdlib.h>
   15 #include <sys/types.h>
   16 #include <stdio.h>
   17 #include <errno.h>
   18 #include <string.h>
   19 #include <sys/stat.h>
   20 #include <unistd.h>
   21 #include <fcntl.h>
   22 #include <time.h>
   23 #include <pthread.h>
   24 
   25 /* ts B41126 : O_BINARY is needed for Cygwin but undefined elsewhere */
   26 #ifndef O_BINARY
   27 #define O_BINARY 0
   28 #endif
   29 
   30 #include "source.h"
   31 #include "libburn.h"
   32 #include "file.h"
   33 #include "async.h"
   34 #include "init.h"
   35 #include "util.h"
   36 
   37 #include "libdax_msgs.h"
   38 extern struct libdax_msgs *libdax_messenger;
   39 
   40 
   41 /* main channel data can be padded on read, but 0 padding the subs will make
   42 an unreadable disc */
   43 
   44 
   45 /* This is a generic OS oriented function wrapper which compensates
   46    shortcomings of read() in respect to a guaranteed amount of return data.
   47    See  man 2 read , paragraph "RETURN VALUE".
   48 */
   49 static int read_full_buffer(int fd, unsigned char *buffer, int size)
   50 {
   51     int ret,summed_ret = 0;
   52 
   53     /* make safe against partial buffer returns */
   54     while (1) {
   55         ret = read(fd, buffer + summed_ret, size - summed_ret);
   56         if (ret <= 0)
   57     break;
   58         summed_ret += ret;
   59         if (summed_ret >= size)
   60     break;
   61     }
   62     if (ret < 0)         /* error encountered. abort immediately */
   63         return ret;
   64     return summed_ret;
   65 }
   66 
   67 
   68 static int file_read(struct burn_source *source,
   69              unsigned char *buffer,
   70              int size)
   71 {
   72     struct burn_source_file *fs = source->data;
   73 
   74     return read_full_buffer(fs->datafd, buffer, size);
   75 }
   76 
   77 static int file_read_sub(struct burn_source *source,
   78              unsigned char *buffer,
   79              int size)
   80 {
   81     struct burn_source_file *fs = source->data;
   82 
   83     return read_full_buffer(fs->subfd, buffer, size);
   84 }
   85 
   86 static void file_free(struct burn_source *source)
   87 {
   88     struct burn_source_file *fs = source->data;
   89 
   90     close(fs->datafd);
   91     if (source->read_sub)
   92         close(fs->subfd);
   93     free(fs);
   94 }
   95 
   96 static off_t file_size(struct burn_source *source)
   97 {
   98     struct stat buf;
   99     struct burn_source_file *fs = source->data;
  100 
  101     if (fs->fixed_size > 0)
  102         return fs->fixed_size;
  103     if (fstat(fs->datafd, &buf) != 0)
  104         return (off_t) 0;
  105     if ((buf.st_mode & S_IFMT) != S_IFREG)
  106         return (off_t) 0;
  107     return (off_t) buf.st_size;
  108 }
  109 
  110 
  111 /* ts A70125 */
  112 static int file_set_size(struct burn_source *source, off_t size)
  113 {
  114     struct burn_source_file *fs = source->data;
  115 
  116     fs->fixed_size = size;
  117     return 1;
  118 }
  119 
  120 
  121 struct burn_source *burn_file_source_new(const char *path, const char *subpath)
  122 {
  123     struct burn_source_file *fs;
  124     struct burn_source *src;
  125     int fd1 = -1, fd2 = -1;
  126 
  127     if (!path)
  128         return NULL;
  129     fd1 = open(path, O_RDONLY | O_BINARY);
  130     if (fd1 == -1)
  131         return NULL;
  132     if (subpath != NULL) {
  133         fd2 = open(subpath, O_RDONLY | O_BINARY);
  134         if (fd2 == -1) {
  135             close(fd1);
  136             return NULL;
  137         }
  138     }
  139     fs = calloc(1, sizeof(struct burn_source_file));
  140 
  141     /* ts A70825 */
  142     if (fs == NULL) {
  143 failure:;
  144         close(fd1);
  145         if (fd2 >= 0)
  146             close(fd2);
  147         return NULL;
  148     }
  149 
  150     fs->datafd = fd1;
  151     fs->subfd = fd2;
  152 
  153     /* ts A70125 */
  154     fs->fixed_size = 0;
  155 
  156     src = burn_source_new();
  157 
  158     /* ts A70825 */
  159     if (src == NULL) {
  160         free((char *) fs);
  161         goto failure;
  162     }
  163 
  164     src->read = file_read;
  165     if (subpath)
  166         src->read_sub = file_read_sub;
  167 
  168     src->get_size = file_size;
  169     src->set_size = file_set_size;
  170     src->free_data = file_free;
  171     src->data = fs;
  172     return src;
  173 }
  174 
  175 
  176 /* ts A70126 : removed class burn_source_fd in favor of burn_source_file */
  177 
  178 struct burn_source *burn_fd_source_new(int datafd, int subfd, off_t size)
  179 {
  180     struct burn_source_file *fs;
  181     struct burn_source *src;
  182 
  183     if (datafd == -1)
  184         return NULL;
  185     fs = burn_alloc_mem(sizeof(struct burn_source_file), 1, 0);
  186     if (fs == NULL) /* ts A70825 */
  187         return NULL;
  188     fs->datafd = datafd;
  189     fs->subfd = subfd;
  190     fs->fixed_size = size;
  191 
  192     src = burn_source_new();
  193 
  194     /* ts A70825 */
  195     if (src == NULL) {
  196         free((char *) fs);
  197         return NULL;
  198     }
  199 
  200     src->read = file_read;
  201     if(subfd != -1)
  202         src->read_sub = file_read_sub;
  203     src->get_size = file_size;
  204     src->set_size = file_set_size;
  205     src->free_data = file_free;
  206     src->data = fs;
  207     return src;
  208 }
  209 
  210 
  211 /* ts A71003 */
  212 /* ------------------------------ fifo --------------------------- */
  213 
  214 /* The fifo mechanism consists of a burn_source proxy which is here,
  215    a thread management team which is located in async.c,
  216    and a synchronous shoveller which is here.
  217 */
  218 
  219 static int fifo_sleep(int flag)
  220 {
  221     static unsigned long sleeptime = 50000; /* 50 ms */
  222 
  223     usleep(sleeptime);
  224     return 0;
  225 }
  226 
  227 
  228 static int fifo_read(struct burn_source *source,
  229              unsigned char *buffer,
  230              int size)
  231 {
  232     struct burn_source_fifo *fs = source->data;
  233     int ret, todo, rpos, bufsize, diff, counted = 0;
  234 
  235     if (fs->end_of_consumption) {
  236         /* ??? msg: reading has been ended already */;
  237         return 0;
  238     }
  239         if (fs->is_started == 0) {
  240         ret = burn_fifo_start(source, 0);
  241         if (ret <= 0) {
  242             libdax_msgs_submit(libdax_messenger, -1, 0x00020152,
  243                  LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
  244                 "Cannot start fifo thread", 0, 0);
  245             fs->end_of_consumption = 1;
  246             return -1;
  247         }
  248         fs->is_started = 1;
  249     }
  250     if (size == 0)
  251         return 0;
  252 
  253     /* Reading from the ring buffer */
  254 
  255     /* This needs no mutex because each volatile variable has one thread
  256        which may write and the other which only reads and is aware of
  257        volatility.
  258        The feeder of the ringbuffer is in burn_fifo_source_shoveller().
  259     */
  260     todo = size;
  261     bufsize = fs->chunksize * fs->chunks;
  262     while (todo > 0) {
  263         /* readpos is not volatile here , writepos is volatile */
  264         rpos = fs->buf_readpos;
  265         while (rpos == fs->buf_writepos) {
  266             if (fs->end_of_input)
  267         break;
  268             if (fs->input_error) {
  269                 if (todo < size) /* deliver partial buffer */
  270         break;
  271                 fs->end_of_consumption = 1;
  272                 libdax_msgs_submit(libdax_messenger, -1,
  273                    0x00020154,
  274                    LIBDAX_MSGS_SEV_NOTE, LIBDAX_MSGS_PRIO_HIGH,
  275                    "Forwarded input error ends output", 0, 0);
  276                 return -1;
  277             }
  278             if (!counted)
  279                 fs->empty_counter++;
  280             counted = 1;
  281             fifo_sleep(0);
  282         }
  283         diff = fs->buf_writepos - rpos; /* read volatile only once */
  284         if (diff == 0)
  285     break;
  286         if (diff > 0)
  287             /* diff bytes are available */;
  288         else 
  289             /* at least (bufsize - rpos) bytes are available */
  290             diff =  bufsize - rpos;
  291         if (diff > todo)
  292             diff = todo;
  293         memcpy(buffer, fs->buf+(size-todo)+rpos, diff);
  294         fs->buf_readpos += diff;
  295         if (fs->buf_readpos >= bufsize)
  296             fs->buf_readpos = 0;
  297         todo -= diff;
  298     }
  299     if (size - todo <= 0)
  300         fs->end_of_consumption = 1;
  301     else
  302         fs->out_counter += size - todo;
  303 
  304 /*
  305     fprintf(stderr,
  306         "libburn_EXPERIMENTAL: read= %d , pos= %d , out_count= %.f\n",
  307         (size - todo), fs->buf_readpos, (double) fs->out_counter);
  308 */
  309 
  310     fs->get_counter++;
  311     return (size - todo);
  312 }
  313 
  314 
  315 static off_t fifo_get_size(struct burn_source *source)
  316 {
  317     struct burn_source_fifo *fs = source->data;
  318 
  319     return fs->inp->get_size(fs->inp);
  320 }
  321 
  322 
  323 static int fifo_set_size(struct burn_source *source, off_t size)
  324 {
  325     struct burn_source_fifo *fs = source->data;
  326 
  327     return fs->inp->set_size(fs->inp, size);
  328 }
  329 
  330 
  331 static void fifo_free(struct burn_source *source)
  332 {
  333     struct burn_source_fifo *fs = source->data;
  334     int wait_count;
  335     static int wait_max = 30, wait_usleep = 100000;
  336 
  337     burn_fifo_abort(fs, 0);
  338     for (wait_count = 0; wait_count <= wait_max; wait_count++) {
  339         if (fs->thread_is_valid <= 0)
  340     break;
  341         if (wait_count < wait_max)
  342             usleep(wait_usleep);
  343     }
  344     if (wait_count > wait_max) {
  345         /* The shoveler thread might still be active. If so, it would
  346            use invalid or inappropriate memory if the fifo would be
  347            disposed now. A memory and resource leak is the better
  348            option here.
  349         */
  350         libdax_msgs_submit(libdax_messenger, -1,
  351                    0x000201ab,
  352                    LIBDAX_MSGS_SEV_WARNING,
  353                    LIBDAX_MSGS_PRIO_HIGH,
  354                    "Leaving burn_source_fifo object undisposed because it is possibly stuck but alive",
  355                    0, 0);
  356         return;
  357     }
  358 
  359     if (fs->inp != NULL)
  360         burn_source_free(fs->inp);
  361 
  362     if (fs->buf != NULL)
  363         burn_os_free_buffer(fs->buf,
  364             ((size_t) fs->chunksize) * (size_t) fs->chunks, 0);
  365     free((char *) fs);
  366 }
  367 
  368 
  369 int burn_fifo_source_shoveller(struct burn_source *source, int flag)
  370 {
  371     struct burn_source_fifo *fs = source->data;
  372     int ret, bufsize, diff, wpos, rpos, trans_end, free_bytes, fill;
  373     int counted;
  374     char *bufpt;
  375     pthread_t thread_handle_storage;
  376 
  377     fs->thread_handle= &thread_handle_storage;
  378     *((pthread_t *) fs->thread_handle)= pthread_self();
  379     fs->thread_pid = getpid();
  380     fs->thread_is_valid = 1;
  381 
  382     /* Lock was obtained by async.c:add_worker() */
  383     burn_async_manage_lock(BURN_ASYNC_LOCK_RELEASE);
  384 
  385     bufsize = fs->chunksize * fs->chunks;
  386     while (!fs->end_of_consumption) {
  387         if (fs->do_abort)
  388             goto emergency_exit;
  389 
  390         /* wait for enough buffer space available */
  391         wpos = fs->buf_writepos;
  392         counted = 0;
  393         while (1) {
  394             if (fs->do_abort)
  395                 goto emergency_exit;
  396             rpos = fs->buf_readpos;
  397             diff = rpos - wpos;
  398             trans_end = 0;
  399             if (diff == 0)
  400                 free_bytes = bufsize - 1;
  401             else if (diff > 0)
  402                 free_bytes = diff - 1;
  403             else {
  404                 free_bytes = (bufsize - wpos) + rpos - 1;
  405                 if (bufsize - wpos < fs->inp_read_size)
  406                     trans_end = 1;
  407             }
  408             if (free_bytes >= fs->inp_read_size)
  409         break;
  410             if (!counted)
  411                 fs->full_counter++;
  412             counted = 1;
  413             fifo_sleep(0);
  414         }
  415 
  416         fill = bufsize - free_bytes - 1;
  417         if (fill < fs->total_min_fill)
  418             fs->total_min_fill = fill;
  419         if (fill < fs->interval_min_fill)
  420             fs->interval_min_fill = fill;
  421 
  422         /* prepare the receiving memory */
  423         bufpt = fs->buf + wpos;
  424         if (trans_end) {
  425             bufpt = burn_os_alloc_buffer(
  426                     (size_t) fs->inp_read_size, 0);
  427             if (bufpt == NULL) {
  428                 libdax_msgs_submit(libdax_messenger, -1,
  429                   0x00000003,
  430                   LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
  431                   "Out of virtual memory", 0, 0);
  432                 fs->input_error = ENOMEM;
  433     break;
  434             }
  435         }
  436 
  437         /* Obtain next chunk */
  438         if (fs->do_abort)
  439             goto emergency_exit;
  440         if (fs->inp->read != NULL)
  441             ret = fs->inp->read(fs->inp,
  442                  (unsigned char *) bufpt, fs->inp_read_size);
  443         else
  444             ret = fs->inp->read_xt( fs->inp,
  445                  (unsigned char *) bufpt, fs->inp_read_size);
  446         if (ret == 0) {
  447 
  448             /* >>> ??? ts B00326 */
  449             /* >>> report EOF of fifo input and fs->in_counter */;
  450 
  451     break; /* EOF */
  452         } else if (ret < 0) {
  453             libdax_msgs_submit(libdax_messenger, -1, 0x00020153,
  454                  LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
  455                 "Read error on fifo input", errno, 0);
  456             fs->input_error = errno;
  457             if(errno == 0)
  458                 fs->input_error = EIO;
  459     break;
  460         }
  461         fs->in_counter += ret;
  462         fs->put_counter++;
  463 
  464         /* activate read chunk */
  465         if (fs->do_abort)
  466             goto emergency_exit;
  467         if (ret > fs->inp_read_size)
  468                     /* beware of ill custom burn_source */
  469             ret = fs->inp_read_size;
  470         if (trans_end) {
  471             /* copy to end of buffer */
  472             memcpy(fs->buf + wpos, bufpt, bufsize - wpos);
  473             /* copy to start of buffer */
  474             memcpy(fs->buf, bufpt + (bufsize - wpos),
  475                 fs->inp_read_size - (bufsize - wpos));
  476             burn_os_free_buffer(bufpt, (size_t) fs->inp_read_size,
  477                         0);
  478             if (ret >= bufsize - wpos)
  479                 fs->buf_writepos = ret - (bufsize - wpos);
  480             else
  481                 fs->buf_writepos += ret;
  482         } else if (fs->buf_writepos + ret == bufsize)
  483             fs->buf_writepos = 0;
  484         else
  485             fs->buf_writepos += ret;
  486 
  487 /*
  488         fprintf(stderr, "[%2.2d%%] ",
  489              (int) (100.0 - 100.0 * ((double) free_bytes) /
  490                          (double) bufsize));
  491         fprintf(stderr,
  492             "libburn_EXPERIMENTAL: writepos= %d ,in_count = %.f\n",
  493             fs->buf_writepos, (double) fs->in_counter);
  494 */
  495     }
  496     if (!fs->end_of_consumption)
  497         fs->end_of_input = 1;
  498 
  499     /* wait for end of reading by consumer */;
  500     while (fs->buf_readpos != fs->buf_writepos && !fs->end_of_consumption) {
  501         if (fs->do_abort)
  502             goto emergency_exit;
  503         fifo_sleep(0);
  504     }
  505 
  506     /* destroy ring buffer */;
  507     if (!fs->end_of_consumption)
  508         fs->end_of_consumption = 2; /* Claim stop of consumption */
  509 
  510     /* This is not prone to race conditions because either the consumer
  511        indicated hangup by fs->end_of_consumption = 1 or the consumer set
  512        fs->buf_readpos to a value indicating the buffer is empty.
  513        So in both cases the consumer is aware that reading is futile
  514        or even fatal.
  515     */
  516     if(fs->buf != NULL)
  517         burn_os_free_buffer(fs->buf,
  518             ((size_t) fs->chunksize) * (size_t) fs->chunks, 0);
  519     fs->buf = NULL;
  520 
  521 emergency_exit:;
  522     burn_async_manage_lock(BURN_ASYNC_LOCK_OBTAIN);
  523     fs->thread_handle= NULL;
  524     fs->thread_is_valid = 0;
  525     burn_async_manage_lock(BURN_ASYNC_LOCK_RELEASE);
  526     return (fs->input_error == 0);
  527 }
  528 
  529 
  530 int burn_fifo_cancel(struct burn_source *source)
  531 {
  532     int ret;
  533     struct burn_source_fifo *fs = source->data;
  534 
  535     ret = burn_source_cancel(fs->inp);
  536     return ret;
  537 }
  538 
  539 /*
  540    @param flag bit0= allow larger read chunks
  541 */
  542 struct burn_source *burn_fifo_source_new(struct burn_source *inp,
  543                 int chunksize, int chunks, int flag)
  544 {
  545     struct burn_source_fifo *fs;
  546     struct burn_source *src;
  547 
  548     if (((double) chunksize) * ((double) chunks) > 1024.0*1024.0*1024.0) {
  549         libdax_msgs_submit(libdax_messenger, -1, 0x00020155,
  550                  LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
  551                 "Desired fifo buffer too large (> 1GB)", 0, 0);
  552         return NULL;
  553     }
  554     if (chunksize < 1 || chunks < 2) {
  555         libdax_msgs_submit(libdax_messenger, -1, 0x00020156,
  556                  LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
  557                 "Desired fifo buffer too small", 0, 0);
  558         return NULL;
  559     }
  560     fs = burn_alloc_mem(sizeof(struct burn_source_fifo), 1, 0);
  561     if (fs == NULL)
  562         return NULL;
  563     fs->is_started = 0;
  564     fs->thread_handle = NULL;
  565     fs->thread_pid = 0;
  566     fs->thread_is_valid = 0;
  567     fs->do_abort = 0;
  568     fs->inp = NULL; /* set later */
  569     if (flag & 1)
  570         fs->inp_read_size = 32 * 1024;
  571     else
  572         fs->inp_read_size = chunksize;
  573     fs->chunksize = chunksize;
  574     fs->chunks = chunks;
  575     fs->buf = NULL;
  576     fs->buf_writepos = fs->buf_readpos = 0;
  577     fs->end_of_input = 0;
  578     fs->input_error = 0;
  579     fs->end_of_consumption = 0;
  580     fs->in_counter = fs->out_counter = 0;
  581     fs->total_min_fill = fs->interval_min_fill = 0;
  582     fs->put_counter = fs->get_counter = 0;
  583     fs->empty_counter = fs->full_counter = 0;
  584 
  585     src = burn_source_new();
  586     if (src == NULL) {
  587         free((char *) fs);
  588         return NULL;
  589     }
  590     src->read = NULL;
  591     src->read_sub = NULL;
  592     src->get_size = fifo_get_size;
  593     src->set_size = fifo_set_size;
  594     src->free_data = fifo_free;
  595     src->data = fs;
  596     src->version= 1;
  597     src->read_xt = fifo_read;
  598     src->cancel= burn_fifo_cancel;
  599     fs->inp = inp;
  600     inp->refcount++; /* make sure inp lives longer than src */
  601 
  602     return src;
  603 }
  604 
  605 
  606 /* ts A71003 : API */
  607 int burn_fifo_inquire_status(struct burn_source *source,
  608          int *size, int *free_bytes, char **status_text)
  609 {
  610     struct burn_source_fifo *fs = source->data;
  611     int ret = 0, diff, wpos, rpos;
  612     static char *(states[8]) = {
  613             "standby", "active", "ending", "failing",
  614             "unused", "abandoned", "ended", "aborted"};
  615 
  616     *status_text = NULL;
  617     *size = 0;
  618 
  619     if (source->free_data != fifo_free) {
  620         libdax_msgs_submit(libdax_messenger, -1, 0x00020157,
  621                  LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
  622           "burn_source is not a fifo object", 0, 0);
  623         return -1;
  624     }
  625     *size = fs->chunksize * fs->chunks;
  626     rpos = fs->buf_readpos;
  627     wpos = fs->buf_writepos;
  628     diff = rpos - wpos;
  629     if (diff == 0)
  630         *free_bytes = *size - 1;
  631     else if (diff > 0)
  632         *free_bytes = diff - 1;
  633     else
  634         *free_bytes = (*size - wpos) + rpos - 1;
  635     ret = 0;
  636     if (fs->end_of_consumption > 0)
  637         ret |= 4;
  638     if (fs->input_error)
  639         ret |= 3;
  640     else if (fs->end_of_input)
  641         ret |= 2;
  642     else if(fs->buf != NULL)
  643         ret |= 1;
  644     *status_text = states[ret];
  645     return ret;
  646 }
  647 
  648 
  649 /* ts A91125 : API */
  650 void burn_fifo_get_statistics(struct burn_source *source,
  651                              int *total_min_fill, int *interval_min_fill,
  652                              int *put_counter, int *get_counter,
  653                              int *empty_counter, int *full_counter)
  654 {
  655     struct burn_source_fifo *fs = source->data;
  656 
  657     *total_min_fill = fs->total_min_fill;
  658     *interval_min_fill = fs->interval_min_fill;
  659     *put_counter = fs->put_counter;
  660     *get_counter = fs->get_counter;
  661     *empty_counter = fs->empty_counter;
  662     *full_counter = fs->full_counter;
  663 }
  664 
  665 
  666 /* ts A91125 : API */
  667 void burn_fifo_next_interval(struct burn_source *source,
  668                             int *interval_min_fill)
  669 { 
  670     struct burn_source_fifo *fs = source->data;
  671     int size, free_bytes, ret;
  672     char *status_text;
  673 
  674     *interval_min_fill = fs->interval_min_fill;
  675     ret = burn_fifo_inquire_status(source,
  676                      &size, &free_bytes, &status_text);
  677     if (ret < 0)
  678         return;
  679     fs->interval_min_fill = size - free_bytes - 1;
  680 }
  681 
  682 
  683 /* @param flag bit0= do not copy to buf but only wait until the fifo has read
  684                      bufsize or input ended.
  685                      The same happens if buf is NULL.
  686                bit1= fill to max fifo size
  687 */
  688 int burn_fifo_fill_data(struct burn_source *source, char *buf, int bufsize,
  689                         int flag)
  690 {
  691     int size, free_bytes, ret, wait_count= 0;
  692     char *status_text;
  693     struct burn_source_fifo *fs = source->data;
  694 
  695     if (buf == NULL)
  696         flag |= 1;
  697 
  698     /* Eventually start fifo thread by reading 0 bytes */
  699     ret = fifo_read(source, (unsigned char *) NULL, 0);
  700     if (ret<0)
  701         {ret = 0; goto ex;}
  702 
  703     /* wait for at least bufsize bytes being ready */
  704     while (1) {
  705         ret= burn_fifo_inquire_status(source,
  706                      &size, &free_bytes, &status_text);
  707         if (flag & 2) {
  708             bufsize = size - (size % fs->inp_read_size) -
  709                     fs->inp_read_size;
  710             if (bufsize <= 0)
  711                 {ret = 0; goto ex;}
  712         }
  713         if (size - fs->inp_read_size < bufsize) {
  714             if (flag & 1) {
  715                 bufsize = size - (size % fs->inp_read_size) -
  716                         fs->inp_read_size;
  717                 if (bufsize <= 0)
  718                     {ret = 0; goto ex;}
  719             } else {
  720                 libdax_msgs_submit(libdax_messenger, -1,
  721                     0x0002015c, LIBDAX_MSGS_SEV_FAILURE,
  722                      LIBDAX_MSGS_PRIO_HIGH,
  723                 "Fifo size too small for desired peek buffer",
  724                      0, 0);
  725                 {ret = -1; goto ex;}
  726             }
  727         }
  728         if (fs->out_counter > 0 || (ret & 4) || fs->buf == NULL) {
  729             libdax_msgs_submit(libdax_messenger, -1, 0x0002015e,
  730             LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
  731         "Fifo is already under consumption when peeking is desired",
  732             0, 0);
  733             {ret = -1; goto ex;}
  734         }
  735         if(size - free_bytes >= bufsize) {
  736 
  737             /* <<<
  738             fprintf(stderr,
  739         "libburn_DEBUG: after waiting cycle %d : fifo %s , %d bytes\n",
  740              wait_count, status_text, size - free_bytes);
  741             */
  742             if(!(flag & 1))
  743                 memcpy(buf, fs->buf, bufsize);
  744             {ret = 1; goto ex;}
  745         }
  746 
  747         if (ret & 2) {
  748             /* input has ended, not enough data arrived */
  749             if (flag & 1)
  750                 {ret = 0; goto ex;}
  751             libdax_msgs_submit(libdax_messenger, -1, 0x0002015d,
  752             LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
  753             "Fifo input ended short of desired peek buffer size",
  754             0, 0);
  755             {ret = 0; goto ex;}
  756         }
  757 
  758         if (free_bytes < fs->inp_read_size) {
  759             /* Usable fifo size filled, not enough data arrived */
  760             if (flag & 1)
  761                 {ret = 0; goto ex;}
  762             libdax_msgs_submit(libdax_messenger, -1, 0x00020174,
  763             LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
  764             "Fifo alignment does not allow desired read size",
  765             0, 0);
  766             {ret = 0; goto ex;}
  767         }
  768 
  769         usleep(100000);
  770         wait_count++;
  771 
  772         /* <<<
  773         if(wait_count%10==0)
  774             fprintf(stderr,
  775          "libburn_DEBUG: waiting cycle %d : fifo %s , %d bytes\n",
  776              wait_count, status_text, size - free_bytes);
  777         */
  778 
  779     }
  780     ret = 0;
  781 ex:;
  782     fs->total_min_fill = fs->interval_min_fill = fs->buf_writepos;
  783     return(ret);
  784 }
  785 
  786 
  787 /* ts A80713 : API */
  788 int burn_fifo_peek_data(struct burn_source *source, char *buf, int bufsize,
  789                         int flag)
  790 {
  791     return burn_fifo_fill_data(source, buf, bufsize, 0);
  792 }
  793 
  794 
  795 /* ts A91125 : API */
  796 int burn_fifo_fill(struct burn_source *source, int bufsize, int flag)
  797 {
  798     return burn_fifo_fill_data(source, NULL, bufsize,
  799                     1 | ((flag & 1) << 1));
  800 }
  801 
  802 
  803 /* ----------------------------- Offset source ----------------------------- */
  804 /* ts B00922 */
  805 
  806 static void offst_free(struct burn_source *source);
  807 
  808 /* @param flag bit0 = do not check for burn_source_offst, do not return NULL
  809 */
  810 static struct burn_source_offst *offst_auth(struct burn_source *source,
  811                                 int flag)
  812 {
  813     if (source->free_data != offst_free && !(flag & 1)) {
  814         libdax_msgs_submit(libdax_messenger, -1, 0x0002017a,
  815             LIBDAX_MSGS_SEV_FAILURE, LIBDAX_MSGS_PRIO_HIGH,
  816             "Expected offset source object as parameter",
  817             0, 0);
  818         return NULL;
  819     }
  820     return (struct burn_source_offst *) source->data;
  821 }
  822 
  823 static off_t offst_get_size(struct burn_source *source)
  824 {
  825         struct burn_source_offst *fs;
  826 
  827     if ((fs = offst_auth(source, 0)) == NULL)
  828         return (off_t) 0;
  829         return fs->nominal_size;
  830 }
  831 
  832 static int offst_set_size(struct burn_source *source, off_t size)
  833 {
  834     struct burn_source_offst *fs;
  835 
  836     if ((fs = offst_auth(source, 0)) == NULL)
  837         return 0;
  838 
  839     fs->nominal_size = size;
  840     if (fs->size <= 0 || fs->size_adjustable)
  841         fs->size = size;
  842     return 1;
  843 }
  844 
  845 static void offst_free(struct burn_source *source)
  846 {
  847     struct burn_source_offst *fs;
  848 
  849     if ((fs = offst_auth(source, 0)) == NULL)
  850         return;
  851     if (fs->prev != NULL)
  852         offst_auth(fs->prev, 1)->next = fs->next;
  853     if (fs->next != NULL)
  854         offst_auth(fs->next, 1)->prev = fs->prev;
  855     if (fs->inp != NULL)
  856         burn_source_free(fs->inp); /* i.e. decrement refcount */
  857     free(source->data);
  858 }
  859 
  860 static int offst_read(struct burn_source *source, unsigned char *buffer,
  861             int size)
  862 {
  863     int ret, to_read, todo;
  864     struct burn_source_offst *fs;
  865 
  866     if ((fs = offst_auth(source, 0)) == NULL)
  867         return -1;
  868 
  869     /* Eventually skip bytes up to start position */;
  870     if (!fs->running) {
  871         if (fs->prev != NULL)
  872             fs->pos = offst_auth(fs->prev, 1)->pos;
  873         fs->running= 1;
  874     }
  875     if(fs->pos < fs->start) {
  876         todo = fs->start - fs->pos;
  877         while (todo > 0) {
  878             to_read = todo;
  879             if (to_read > size)
  880                 to_read = size;
  881             ret = burn_source_read(fs->inp, buffer, to_read);
  882             if (ret <= 0)
  883                 return ret;
  884             todo -= ret;
  885             fs->pos += ret;
  886         }
  887     }
  888 
  889     /* Produce EOF if source size is exhausted.
  890        burn_source delivers no incomplete sector buffers.
  891     */
  892     if (fs->pos + size > fs->start + fs->size)
  893         return 0;
  894 
  895     /* Read payload */
  896     ret = burn_source_read(fs->inp, buffer, size);
  897     if (ret > 0)
  898         fs->pos += ret;
  899     return ret;
  900 }
  901 
  902 static int offst_cancel(struct burn_source *source)
  903 {
  904     int ret;
  905     struct burn_source_offst *fs;
  906 
  907     if ((fs = offst_auth(source, 0)) == NULL)
  908         return -1;
  909     ret = burn_source_cancel(fs->inp);
  910     return ret;
  911 }
  912 
  913 struct burn_source *burn_offst_source_new(
  914         struct burn_source *inp, struct burn_source *prev,
  915         off_t start, off_t size, int flag)
  916 {
  917     struct burn_source *src;
  918     struct burn_source_offst *fs, *prev_fs = NULL;
  919 
  920     if (prev != NULL)
  921         if ((prev_fs = offst_auth(prev, 0)) == NULL)
  922             return NULL; /* Not type burn_source_offst */
  923 
  924     fs = calloc(1, sizeof(struct burn_source_offst));
  925     if (fs == NULL)
  926         return NULL;
  927         src = burn_source_new();
  928         if (src == NULL) {
  929                 free((char *) fs);
  930                 return NULL;
  931         }
  932         src->read = NULL;
  933         src->read_sub = NULL;
  934         src->get_size = offst_get_size;
  935         src->set_size = offst_set_size;
  936         src->free_data = offst_free;
  937         src->data = fs;
  938         src->version= 1;
  939         src->read_xt = offst_read;
  940         src->cancel= offst_cancel;
  941         fs->inp = inp;
  942     fs->prev = prev;
  943     fs->next = NULL;
  944     if (prev != NULL) {
  945         if (prev_fs->next != NULL) {
  946             offst_auth(prev_fs->next, 1)->prev = src;
  947             fs->next = prev_fs->next;
  948         }
  949         prev_fs->next = src;
  950         if (prev_fs->start + prev_fs->size > start) {
  951             libdax_msgs_submit(libdax_messenger, -1, 0x00020179,
  952             LIBDAX_MSGS_SEV_FAILURE, LIBDAX_MSGS_PRIO_HIGH,
  953         "Offset source start address is before end of previous source",
  954             0, 0);
  955             return NULL;
  956         }
  957     }
  958     fs->start = start;
  959     fs->size = size;
  960     fs->size_adjustable = !(flag & 1);
  961     fs->nominal_size = size;
  962     fs->running = 0;
  963     fs->pos = 0;
  964         inp->refcount++; /* make sure inp lives longer than src */
  965 
  966         return src;
  967 }
  968 
  969 
  970 /* -------------------- WAVE file extractor ------------------- */
  971 
  972 
  973 /* ts B30522 */
  974 /* API
  975     @param flag         Bitfield for control purposes:
  976                         bit0= Report about progress by UPDATE message
  977                         bit3= Enable DAP : "flaw obscuring mechanisms like
  978                                             audio data mute and interpolate"
  979 
  980 */
  981 int burn_drive_extract_audio(struct burn_drive *drive,
  982                              int start_sector, int sector_count,
  983                              char *target_path, int flag)
  984 {
  985     int fd = -1, ret, todo, sector_no, val, min, sec, fr;
  986     int sectors_done= 0;
  987     off_t data_size, data_count = 0;
  988     time_t last_pacified = 0, now;
  989     char *msg = NULL, *buf = NULL;
  990 
  991     BURN_ALLOC_MEM(msg, char, 4096);
  992     BURN_ALLOC_MEM(buf, char, 24 * 2352);
  993 
  994     fd = open(target_path, O_WRONLY | O_CREAT | O_BINARY,
  995                   S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
  996     if (fd == -1) {
  997         sprintf(msg, "Cannot open disk file for writing: %.4000s",
  998                 target_path);
  999         libdax_msgs_submit(libdax_messenger, -1, 0x000201a1,
 1000                 LIBDAX_MSGS_SEV_FAILURE, LIBDAX_MSGS_PRIO_HIGH,
 1001                 msg, errno, 0);
 1002         ret = 0; goto ex;
 1003     }
 1004 
 1005     /* WAV header */
 1006     strcpy(buf, "RIFF");
 1007     val = 4 + 8 + 16 + 8 + sector_count * 2352; /* ChunkSize */
 1008     burn_int_to_lsb(val, buf + 4);
 1009     strcpy(buf + 8, "WAVE");
 1010     strcpy(buf + 12, "fmt ");
 1011     burn_int_to_lsb(16, buf + 16);     /* Subchunk1Size */
 1012     buf[20] = 1;                       /* AudioFormat */
 1013     buf[21] = 0;
 1014     buf[22] = 2;                       /* NumChannels */
 1015     buf[23] = 0;
 1016     burn_int_to_lsb(44100, buf + 24);  /* SampleRate */
 1017     burn_int_to_lsb(176400, buf + 28); /* ByteRate */
 1018     buf[32] = 4;                       /* BlockAlign */
 1019     buf[33] = 0;
 1020     buf[34] = 16;                      /* BitsPerSample */
 1021     buf[35] = 0;
 1022     strcpy(buf + 36, "data");
 1023     burn_int_to_lsb(sector_count * 2352, buf + 40); /* Subchunk2Size */
 1024 
 1025     ret = write(fd, buf, 44);
 1026     if (ret == -1)
 1027         goto write_error;
 1028 
 1029     /* Audio data */
 1030     todo = sector_count;
 1031     sector_no = start_sector;
 1032     while (todo > 0) {
 1033         if (todo > 24)
 1034             data_size = 24 * 2352;
 1035         else
 1036             data_size = todo * 2352;
 1037         ret = burn_read_audio(drive, sector_no, buf, data_size,
 1038                         &data_count, flag & 8);
 1039         if (ret <= 0) {
 1040             sprintf(msg, "Failure to read audio sectors");
 1041             libdax_msgs_submit(libdax_messenger, -1, 0x000201a4,
 1042                 LIBDAX_MSGS_SEV_FAILURE, LIBDAX_MSGS_PRIO_HIGH,
 1043                 msg, 0, 0);
 1044             goto ex;
 1045         }
 1046         ret = write(fd, buf, data_count);
 1047         if (ret == -1) {
 1048 write_error:;
 1049             sprintf(msg,
 1050                 "Error while writing to disk file: %.4000s",
 1051                 target_path);
 1052             libdax_msgs_submit(libdax_messenger, -1, 0x000201a2,
 1053                         LIBDAX_MSGS_SEV_FAILURE,
 1054                         LIBDAX_MSGS_PRIO_HIGH,
 1055                         msg, errno, 0);
 1056             ret = 0; goto ex;
 1057         }
 1058         todo -= data_count / 2352;
 1059         sectors_done += data_count / 2352;
 1060         sector_no += data_count / 2352;
 1061         if ((flag & 1) && (now = time(NULL)) - last_pacified >= 1) {
 1062             last_pacified = now;
 1063             burn_lba_to_msf(sectors_done, &min, &sec, &fr);
 1064             sprintf(msg,
 1065            "Minutes:seconds of audio data read: %2d:%2.2d  (%6.2f MB)",
 1066                min, sec,
 1067                ((double) sectors_done) * 2352.0 / 1048576.0);
 1068             libdax_msgs_submit(libdax_messenger, -1, 0x000201a3,
 1069                         LIBDAX_MSGS_SEV_UPDATE,
 1070                         LIBDAX_MSGS_PRIO_HIGH,
 1071                         msg, 0, 1);
 1072         }
 1073     }
 1074     if ((flag & 1)) {
 1075         burn_lba_to_msf(sectors_done, &min, &sec, &fr);
 1076         sprintf(msg,
 1077           "Minutes:seconds of audio data read: %2d:%2.2d  (%6.2f MB)",
 1078            min, sec, ((double) sectors_done) * 2352.0 / 1048576.0);
 1079         libdax_msgs_submit(libdax_messenger, -1, 0x000201a3,
 1080                     LIBDAX_MSGS_SEV_UPDATE,
 1081                     LIBDAX_MSGS_PRIO_HIGH,
 1082                     msg, 0, 0);
 1083     }
 1084     ret = 1;
 1085 ex:;
 1086     BURN_FREE_MEM(buf);
 1087     BURN_FREE_MEM(msg);
 1088     if (fd != -1)
 1089         close(fd);
 1090     return ret;
 1091 }
 1092 
 1093 
 1094 /* ts B30522 */
 1095 /* API
 1096     @param flag         Bitfield for control purposes:
 1097                         bit0= Report about progress by UPDATE message
 1098                         bit3= Enable DAP : "flaw obscuring mechanisms like
 1099                                             audio data mute and interpolate"
 1100 */
 1101 int burn_drive_extract_audio_track(struct burn_drive *drive,
 1102                                    struct burn_track *track,
 1103                                    char *target_path, int flag)
 1104 {
 1105     int ret;
 1106     struct burn_toc_entry toc_entry;
 1107 
 1108     burn_track_get_entry(track, &toc_entry);
 1109     if (!(toc_entry.extensions_valid & 1)) {
 1110         /* Can only happen if burn_disc_cd_toc_extensions() is skipped
 1111            in mmc_read_toc_al().
 1112         */
 1113         libdax_msgs_submit(libdax_messenger, -1, 0x00000004,
 1114                 LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
 1115       "Internal libburn error: Outdated burn_toc_entry format encountered",
 1116                 errno, 0);
 1117         return -1;
 1118     }
 1119     ret = burn_drive_extract_audio(drive, toc_entry.start_lba,
 1120                     toc_entry.track_blocks,
 1121                     target_path, flag & (1 | 8));
 1122     return ret;
 1123 }
 1124