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 */
read_full_buffer(int fd,unsigned char * buffer,int size)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
file_read(struct burn_source * source,unsigned char * buffer,int size)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
file_read_sub(struct burn_source * source,unsigned char * buffer,int size)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
file_free(struct burn_source * source)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
file_size(struct burn_source * source)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 */
file_set_size(struct burn_source * source,off_t size)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
burn_file_source_new(const char * path,const char * subpath)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
burn_fd_source_new(int datafd,int subfd,off_t size)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
fifo_sleep(int flag)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
fifo_read(struct burn_source * source,unsigned char * buffer,int size)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
fifo_get_size(struct burn_source * source)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
fifo_set_size(struct burn_source * source,off_t size)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
fifo_free(struct burn_source * source)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
burn_fifo_source_shoveller(struct burn_source * source,int flag)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
burn_fifo_cancel(struct burn_source * source)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 */
burn_fifo_source_new(struct burn_source * inp,int chunksize,int chunks,int flag)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 */
burn_fifo_inquire_status(struct burn_source * source,int * size,int * free_bytes,char ** status_text)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 */
burn_fifo_get_statistics(struct burn_source * source,int * total_min_fill,int * interval_min_fill,int * put_counter,int * get_counter,int * empty_counter,int * full_counter)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 */
burn_fifo_next_interval(struct burn_source * source,int * interval_min_fill)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 */
burn_fifo_fill_data(struct burn_source * source,char * buf,int bufsize,int flag)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 */
burn_fifo_peek_data(struct burn_source * source,char * buf,int bufsize,int flag)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 */
burn_fifo_fill(struct burn_source * source,int bufsize,int flag)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 */
offst_auth(struct burn_source * source,int flag)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
offst_get_size(struct burn_source * source)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
offst_set_size(struct burn_source * source,off_t size)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
offst_free(struct burn_source * source)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
offst_read(struct burn_source * source,unsigned char * buffer,int size)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
offst_cancel(struct burn_source * source)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
burn_offst_source_new(struct burn_source * inp,struct burn_source * prev,off_t start,off_t size,int flag)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 */
burn_drive_extract_audio(struct burn_drive * drive,int start_sector,int sector_count,char * target_path,int flag)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 */
burn_drive_extract_audio_track(struct burn_drive * drive,struct burn_track * track,char * target_path,int flag)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
1125