4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 * Copyright 2012 Marcel Telka <marcel@telka.sk>
32 #include <sys/types.h>
35 #include <sys/statvfs.h>
45 #include "byteorder.h"
51 str_errno_to_string(int serrno
)
55 return (gettext("No error"));
56 case STR_ERR_NO_REG_FILE
:
57 return (gettext("Not a regular file"));
58 case STR_ERR_NO_READ_STDIN
:
59 return (gettext("Stdin not open for reading"));
60 case STR_ERR_AU_READ_ERR
:
61 return (gettext("Unable to read au header"));
62 case STR_ERR_AU_UNSUPPORTED_FORMAT
:
63 return (gettext("Unsupported au format"));
64 case STR_ERR_AU_BAD_HEADER
:
65 return (gettext("Bad au header"));
66 case STR_ERR_WAV_READ_ERR
:
67 return (gettext("Unable to read wav header"));
68 case STR_ERR_WAV_UNSUPPORTED_FORMAT
:
69 return (gettext("Unsupported wav format"));
70 case STR_ERR_WAV_BAD_HEADER
:
71 return (gettext("Bad wav header"));
72 case STR_ERR_ISO_READ_ERR
:
73 return (gettext("Unable to read ISO header"));
74 case STR_ERR_ISO_BAD_HEADER
:
75 return (gettext("Invalid ISO header or not an ISO"));
77 return (gettext("unknown error"));
82 file_stream_size(bstreamhandle h
, off_t
*size
)
88 if (fstat(h
->bstr_fd
, &st
) < 0)
90 if ((st
.st_mode
& S_IFMT
) != S_IFREG
) {
91 str_errno
= STR_ERR_NO_REG_FILE
;
99 audio_stream_size(bstreamhandle h
, off_t
*size
)
102 *size
= (off_t
)(uintptr_t)(h
->bstr_private
);
107 file_stream_read(bstreamhandle h
, uchar_t
*buf
, off_t size
)
110 return (read(h
->bstr_fd
, buf
, size
));
114 file_stream_write(bstreamhandle h
, uchar_t
*buf
, off_t size
)
117 return (write(h
->bstr_fd
, buf
, size
));
121 * with reverse byteorder
124 file_stream_read_wrbo(bstreamhandle h
, uchar_t
*buf
, off_t size
)
129 cnt
= read(h
->bstr_fd
, buf
, size
);
134 for (i
= 0; i
< cnt
; i
+= 2) {
144 * This will change the byteorder in the buffer but that is fine with us.
147 file_stream_write_wrbo(bstreamhandle h
, uchar_t
*buf
, off_t size
)
154 for (i
= 0; i
< size
; i
+= 2) {
160 return (write(h
->bstr_fd
, buf
, size
));
164 file_stream_close(bstreamhandle h
)
175 stdin_stream_close(bstreamhandle h
)
183 wav_write_stream_close(bstreamhandle h
)
189 (void) memset(&wav
, 0, sizeof (wav
));
190 sz
= lseek(h
->bstr_fd
, 0L, SEEK_END
);
191 (void) lseek(h
->bstr_fd
, 0L, SEEK_SET
);
192 if (read(h
->bstr_fd
, &wav
, sizeof (wav
)) != sizeof (wav
)) {
195 wav
.total_chunk_size
= CPU_TO_LE32(sz
- 8);
196 wav
.data_size
= CPU_TO_LE32(sz
- 44);
197 (void) lseek(h
->bstr_fd
, 0L, SEEK_SET
);
198 if (write(h
->bstr_fd
, &wav
, sizeof (wav
)) != sizeof (wav
)) {
201 (void) close(h
->bstr_fd
);
207 au_write_stream_close(bstreamhandle h
)
212 sz
= lseek(h
->bstr_fd
, 0L, SEEK_END
);
213 sz
-= PRE_DEF_AU_HDR_LEN
;
214 sz
= CPU_TO_BE32(sz
);
215 if (lseek(h
->bstr_fd
, 8L, SEEK_SET
) < 0)
218 if (write(h
->bstr_fd
, &sz
, 4) < 0)
221 (void) close(h
->bstr_fd
);
228 stdin_stream_rewind(bstreamhandle h
)
233 file_stream_rewind(bstreamhandle h
)
235 (void) lseek(h
->bstr_fd
, 0L, SEEK_SET
);
239 au_stream_rewind(bstreamhandle h
)
243 (void) lseek(h
->bstr_fd
, 0L, SEEK_SET
);
244 if (read(h
->bstr_fd
, &au
, sizeof (au
)) != sizeof (au
)) {
248 if (lseek(h
->bstr_fd
, (long)(BE32_TO_CPU(au
.au_offset
)),
255 wav_stream_rewind(bstreamhandle h
)
257 (void) lseek(h
->bstr_fd
, (long)(sizeof (Wave_filehdr
)), SEEK_SET
);
261 open_file_read_stream(char *file
)
268 if (stat(file
, &st
) < 0)
270 if ((st
.st_mode
& S_IFMT
) == S_IFDIR
) {
271 str_errno
= STR_ERR_NO_REG_FILE
;
274 fd
= open(file
, O_RDONLY
);
277 h
= (bstreamhandle
)my_zalloc(sizeof (*h
));
279 h
->bstr_read
= file_stream_read
;
280 h
->bstr_close
= file_stream_close
;
281 h
->bstr_size
= file_stream_size
;
282 h
->bstr_rewind
= file_stream_rewind
;
288 open_iso_read_stream(char *fname
)
292 char iso_desc
[ISO9660_PRIMARY_DESC_SIZE
];
294 h
= open_file_read_stream(fname
);
296 /* If we don't have a valid handle immediately return NULL */
301 (void) printf("Checking the ISO file header\n");
303 /* Check to see if we have a valid sized ISO image */
304 h
->bstr_size(h
, &iso_size
);
305 if (iso_size
< ISO9660_HEADER_SIZE
) {
307 (void) printf("ISO header size not sane.\n");
309 str_errno
= STR_ERR_ISO_BAD_HEADER
;
314 (void) printf("ISO header size is sane.\n");
316 /* Skip over the boot block sector of the ISO. */
317 (void) lseek(h
->bstr_fd
, ISO9660_BOOT_BLOCK_SIZE
, SEEK_SET
);
320 * Try to read in the ISO Descriptor and validate this
321 * is in fact an ISO image.
323 if (read(h
->bstr_fd
, iso_desc
, ISO9660_PRIMARY_DESC_SIZE
) ==
324 ISO9660_PRIMARY_DESC_SIZE
) {
326 * Bytes one through five of a valid image should contain:
327 * - BEA01 (ISO 13490 image)
328 * - CD001 (ISO 9660 or ISO 13490 image)
329 * - CDROM (High Sierra format, the ISO 9660 predecessor)
330 * If neither is the case then we should close the stream,
331 * set str_errno, and return NULL.
333 if (strncmp(iso_desc
+ ISO9660_STD_IDENT_OFFSET
, "BEA01",
334 5) != 0 && strncmp(iso_desc
+ ISO9660_STD_IDENT_OFFSET
,
335 "CD001", 5) != 0 && strncmp(iso_desc
+
336 ISO9660_STD_IDENT_OFFSET
, "CDROM", 5) != 0) {
338 (void) printf("Invalid ISO identifier.\n");
340 str_errno
= STR_ERR_ISO_BAD_HEADER
;
345 str_errno
= STR_ERR_ISO_READ_ERR
;
350 * Our ISO image is valid rewind the stream
351 * and return the handle.
354 (void) printf("ISO header is sane.\n");
360 open_stdin_read_stream(void)
366 if ((mode
= fcntl(0, F_GETFD
, NULL
)) < 0) {
367 str_errno
= STR_ERR_NO_READ_STDIN
;
371 if ((mode
!= O_RDONLY
) && (mode
!= O_RDWR
)) {
372 str_errno
= STR_ERR_NO_READ_STDIN
;
375 h
= (bstreamhandle
)my_zalloc(sizeof (*h
));
377 h
->bstr_read
= file_stream_read
;
378 h
->bstr_close
= stdin_stream_close
;
379 h
->bstr_size
= file_stream_size
;
380 h
->bstr_rewind
= stdin_stream_rewind
;
386 open_au_read_stream(char *fname
)
396 fd
= open(fname
, O_RDONLY
);
400 if (fstat(fd
, &st
) < 0) {
403 if ((st
.st_mode
& S_IFMT
) != S_IFREG
) {
404 str_errno
= STR_ERR_NO_REG_FILE
;
407 au
= (au_filehdr_t
*)my_zalloc(sizeof (*au
));
408 if (read(fd
, au
, sizeof (*au
)) != sizeof (*au
)) {
409 str_errno
= STR_ERR_AU_READ_ERR
;
412 au
->au_magic
= BE32_TO_CPU(au
->au_magic
);
413 au
->au_offset
= BE32_TO_CPU(au
->au_offset
);
414 au
->au_data_size
= BE32_TO_CPU(au
->au_data_size
);
415 au
->au_encoding
= BE32_TO_CPU(au
->au_encoding
);
416 au
->au_sample_rate
= BE32_TO_CPU(au
->au_sample_rate
);
417 au
->au_channels
= BE32_TO_CPU(au
->au_channels
);
419 if (au
->au_magic
!= AUDIO_AU_FILE_MAGIC
) {
420 str_errno
= STR_ERR_AU_BAD_HEADER
;
423 if ((au
->au_encoding
!= AUDIO_AU_ENCODING_LINEAR_16
) ||
424 (au
->au_sample_rate
!= 44100) || (au
->au_channels
!= 2)) {
426 str_errno
= STR_ERR_AU_UNSUPPORTED_FORMAT
;
429 if (au
->au_data_size
!= AUDIO_AU_UNKNOWN_SIZE
) {
430 if ((au
->au_offset
+ au
->au_data_size
) != st
.st_size
) {
431 str_errno
= STR_ERR_AU_BAD_HEADER
;
434 data_size
= au
->au_data_size
;
436 data_size
= st
.st_size
- au
->au_offset
;
438 if (data_size
== 0) {
439 str_errno
= STR_ERR_AU_UNSUPPORTED_FORMAT
;
442 if (lseek(fd
, au
->au_offset
, SEEK_SET
) < 0) {
447 h
= (bstreamhandle
)my_zalloc(sizeof (*h
));
449 h
->bstr_read
= file_stream_read_wrbo
;
450 h
->bstr_close
= file_stream_close
;
451 h
->bstr_size
= audio_stream_size
;
452 h
->bstr_rewind
= au_stream_rewind
;
453 h
->bstr_private
= (void *)data_size
;
467 open_wav_read_stream(char *fname
)
477 fd
= open(fname
, O_RDONLY
);
481 if (fstat(fd
, &st
) < 0) {
482 goto wav_open_failed
;
484 if ((st
.st_mode
& S_IFMT
) != S_IFREG
) {
485 str_errno
= STR_ERR_NO_REG_FILE
;
486 goto wav_open_failed
;
488 wav
= (Wave_filehdr
*)my_zalloc(sizeof (*wav
));
489 if (read(fd
, wav
, sizeof (*wav
)) != sizeof (*wav
)) {
490 str_errno
= STR_ERR_WAV_READ_ERR
;
491 goto wav_open_failed
;
493 if ((strncmp(wav
->riff
, "RIFF", 4) != 0) ||
494 (strncmp(wav
->wave
, "WAVE", 4) != 0)) {
495 str_errno
= STR_ERR_WAV_BAD_HEADER
;
496 goto wav_open_failed
;
498 if (((CPU_TO_LE32(wav
->total_chunk_size
) + 8) != st
.st_size
) ||
499 (strncmp(wav
->fmt
, "fmt ", 4) != 0) ||
500 (CPU_TO_LE16(wav
->fmt_tag
) != 1) ||
501 (CPU_TO_LE16(wav
->n_channels
) != 2) ||
502 (CPU_TO_LE32(wav
->sample_rate
) != 44100) ||
503 (CPU_TO_LE16(wav
->bits_per_sample
) != 16) ||
504 (strncmp(wav
->data
, "data", 4) != 0) ||
505 ((CPU_TO_LE32(wav
->data_size
) + 44) != st
.st_size
)) {
507 str_errno
= STR_ERR_WAV_UNSUPPORTED_FORMAT
;
508 goto wav_open_failed
;
510 data_size
= CPU_TO_LE32(wav
->data_size
);
511 if (lseek(fd
, sizeof (*wav
), SEEK_SET
) < 0) {
512 goto wav_open_failed
;
516 h
= (bstreamhandle
)my_zalloc(sizeof (*h
));
518 h
->bstr_read
= file_stream_read
;
519 h
->bstr_close
= file_stream_close
;
520 h
->bstr_size
= audio_stream_size
;
521 h
->bstr_rewind
= wav_stream_rewind
;
522 h
->bstr_private
= (void *)data_size
;
536 open_aur_read_stream(char *fname
)
540 h
= open_file_read_stream(fname
);
542 h
->bstr_read
= file_stream_read_wrbo
;
548 open_au_write_stream(char *fname
)
552 uchar_t head
[] = PRE_DEF_AU_HDR
;
556 /* O_RDWR because we need to read while closing */
557 fd
= open(fname
, O_RDWR
|O_CREAT
|O_TRUNC
, 0666);
559 goto open_au_write_stream_failed
;
560 if (write(fd
, head
, PRE_DEF_AU_HDR_LEN
) != PRE_DEF_AU_HDR_LEN
) {
561 goto open_au_write_stream_failed
;
563 h
= (bstreamhandle
)my_zalloc(sizeof (*h
));
565 h
->bstr_write
= file_stream_write_wrbo
;
566 h
->bstr_close
= au_write_stream_close
;
569 open_au_write_stream_failed
:
578 open_wav_write_stream(char *fname
)
582 uchar_t head
[] = PRE_DEF_WAV_HDR
;
586 fd
= open(fname
, O_RDWR
|O_CREAT
|O_TRUNC
, 0666);
588 goto open_wav_write_stream_failed
;
589 if (write(fd
, head
, PRE_DEF_WAV_HDR_LEN
) != PRE_DEF_WAV_HDR_LEN
) {
590 goto open_wav_write_stream_failed
;
592 h
= (bstreamhandle
)my_zalloc(sizeof (*h
));
594 h
->bstr_write
= file_stream_write
;
595 h
->bstr_close
= wav_write_stream_close
;
598 open_wav_write_stream_failed
:
607 open_aur_write_stream(char *fname
)
613 fd
= open(fname
, O_WRONLY
|O_CREAT
|O_TRUNC
, 0666);
616 h
= (bstreamhandle
)my_zalloc(sizeof (*h
));
618 h
->bstr_write
= file_stream_write_wrbo
;
619 h
->bstr_close
= file_stream_close
;
624 open_file_write_stream(char *fname
)
630 fd
= open(fname
, O_WRONLY
|O_CREAT
|O_TRUNC
, 0666);
633 h
= (bstreamhandle
)my_zalloc(sizeof (*h
));
635 h
->bstr_write
= file_stream_write
;
636 h
->bstr_close
= file_stream_close
;
641 open_temp_file_stream(void)
649 t
= (char *)get_tmp_name();
651 if (strlcat(t
, "/cdXXXXXX", PATH_MAX
) >= PATH_MAX
)
657 (void) printf("temp is: %s length: %d\n", t
, strlen(t
));
663 h
= (bstreamhandle
)my_zalloc(sizeof (*h
));
665 h
->bstr_read
= file_stream_read
;
666 h
->bstr_write
= file_stream_write
;
667 h
->bstr_close
= file_stream_close
;
668 h
->bstr_size
= file_stream_size
;
669 h
->bstr_rewind
= file_stream_rewind
;
675 * check_avail_temp_space returns 0 if there is adequate space
676 * in the temporary directory, or a non-zero error code if
677 * something goes wrong
680 check_avail_temp_space(size_t req_size
)
683 u_longlong_t free_size
= 0;
685 if (statvfs(get_tmp_name(), &buf
) < 0) {
689 free_size
= buf
.f_bfree
* buf
.f_frsize
;
691 if (free_size
<= req_size
)
704 t
= (char *)my_zalloc(PATH_MAX
);
707 * generate temp directory path based on this order:
708 * user specified (-m option), temp env variable,
709 * and finally /tmp if nothing is found.
714 /* copy and leave room for temp filename */
716 (void) strlcpy(t
, alt_tmp_dir
, PATH_MAX
- 10);
718 envptr
= getenv("TMPDIR");
719 if (envptr
!= NULL
) {
720 (void) strlcpy(t
, envptr
, PATH_MAX
- 10);
722 (void) strlcpy(t
, "/tmp", 5);
727 * no need to check if path is valid. statvfs will catch
728 * it later and fail with a proper error message.