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