1 /* 2 * CDDL HEADER START 3 * 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. 7 * 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. 12 * 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] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 /* 26 * Copyright 2012 Marcel Telka <marcel@telka.sk> 27 */ 28 29 #include <fcntl.h> 30 #include <string.h> 31 #include <errno.h> 32 #include <sys/types.h> 33 #include <unistd.h> 34 #include <sys/stat.h> 35 #include <sys/statvfs.h> 36 #include <stdio.h> 37 #include <stdlib.h> 38 #include <libintl.h> 39 #include <limits.h> 40 #include <audio/au.h> 41 42 #include "bstream.h" 43 #include "util.h" 44 #include "audio.h" 45 #include "byteorder.h" 46 #include "main.h" 47 48 int str_errno; 49 50 char * 51 str_errno_to_string(int serrno) 52 { 53 switch (serrno) { 54 case STR_ERR_NO_ERR: 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")); 76 default: 77 return (gettext("unknown error")); 78 } 79 } 80 81 static int 82 file_stream_size(bstreamhandle h, off_t *size) 83 { 84 struct stat st; 85 86 str_errno = 0; 87 88 if (fstat(h->bstr_fd, &st) < 0) 89 return (0); 90 if ((st.st_mode & S_IFMT) != S_IFREG) { 91 str_errno = STR_ERR_NO_REG_FILE; 92 return (0); 93 } 94 *size = st.st_size; 95 return (1); 96 } 97 98 static int 99 audio_stream_size(bstreamhandle h, off_t *size) 100 { 101 str_errno = 0; 102 *size = (off_t)(uintptr_t)(h->bstr_private); 103 return (1); 104 } 105 106 static int 107 file_stream_read(bstreamhandle h, uchar_t *buf, off_t size) 108 { 109 str_errno = 0; 110 return (read(h->bstr_fd, buf, size)); 111 } 112 113 static int 114 file_stream_write(bstreamhandle h, uchar_t *buf, off_t size) 115 { 116 str_errno = 0; 117 return (write(h->bstr_fd, buf, size)); 118 } 119 120 /* 121 * with reverse byteorder 122 */ 123 static int 124 file_stream_read_wrbo(bstreamhandle h, uchar_t *buf, off_t size) 125 { 126 int cnt; 127 128 str_errno = 0; 129 cnt = read(h->bstr_fd, buf, size); 130 if (cnt > 0) { 131 int i; 132 uchar_t ch; 133 134 for (i = 0; i < cnt; i += 2) { 135 ch = buf[i]; 136 buf[i] = buf[i+1]; 137 buf[i+1] = ch; 138 } 139 } 140 return (cnt); 141 } 142 143 /* 144 * This will change the byteorder in the buffer but that is fine with us. 145 */ 146 static int 147 file_stream_write_wrbo(bstreamhandle h, uchar_t *buf, off_t size) 148 { 149 int i; 150 uchar_t ch; 151 152 str_errno = 0; 153 if (size > 0) { 154 for (i = 0; i < size; i += 2) { 155 ch = buf[i]; 156 buf[i] = buf[i+1]; 157 buf[i+1] = ch; 158 } 159 } 160 return (write(h->bstr_fd, buf, size)); 161 } 162 163 static int 164 file_stream_close(bstreamhandle h) 165 { 166 int fd; 167 168 str_errno = 0; 169 fd = h->bstr_fd; 170 free(h); 171 return (close(fd)); 172 } 173 174 static int 175 stdin_stream_close(bstreamhandle h) 176 { 177 str_errno = 0; 178 free(h); 179 return (0); 180 } 181 182 static int 183 wav_write_stream_close(bstreamhandle h) 184 { 185 uint32_t sz; 186 Wave_filehdr wav; 187 188 str_errno = 0; 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)) { 193 return (1); 194 } 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)) { 199 return (1); 200 } 201 (void) close(h->bstr_fd); 202 free(h); 203 return (0); 204 } 205 206 static int 207 au_write_stream_close(bstreamhandle h) 208 { 209 uint32_t sz; 210 211 str_errno = 0; 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) 216 return (1); 217 218 if (write(h->bstr_fd, &sz, 4) < 0) 219 return (1); 220 221 (void) close(h->bstr_fd); 222 free(h); 223 return (0); 224 } 225 226 /* ARGSUSED */ 227 static void 228 stdin_stream_rewind(bstreamhandle h) 229 { 230 } 231 232 static void 233 file_stream_rewind(bstreamhandle h) 234 { 235 (void) lseek(h->bstr_fd, 0L, SEEK_SET); 236 } 237 238 static void 239 au_stream_rewind(bstreamhandle h) 240 { 241 au_filehdr_t au; 242 243 (void) lseek(h->bstr_fd, 0L, SEEK_SET); 244 if (read(h->bstr_fd, &au, sizeof (au)) != sizeof (au)) { 245 return; 246 } 247 248 if (lseek(h->bstr_fd, (long)(BE32_TO_CPU(au.au_offset)), 249 SEEK_SET) < 0) { 250 return; 251 } 252 } 253 254 static void 255 wav_stream_rewind(bstreamhandle h) 256 { 257 (void) lseek(h->bstr_fd, (long)(sizeof (Wave_filehdr)), SEEK_SET); 258 } 259 260 bstreamhandle 261 open_file_read_stream(char *file) 262 { 263 bstreamhandle h; 264 int fd; 265 struct stat st; 266 267 str_errno = 0; 268 if (stat(file, &st) < 0) 269 return (NULL); 270 if ((st.st_mode & S_IFMT) == S_IFDIR) { 271 str_errno = STR_ERR_NO_REG_FILE; 272 return (NULL); 273 } 274 fd = open(file, O_RDONLY); 275 if (fd < 0) 276 return (NULL); 277 h = (bstreamhandle)my_zalloc(sizeof (*h)); 278 h->bstr_fd = fd; 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; 283 284 return (h); 285 } 286 287 bstreamhandle 288 open_iso_read_stream(char *fname) 289 { 290 bstreamhandle h; 291 off_t iso_size = 0; 292 char iso_desc[ISO9660_PRIMARY_DESC_SIZE]; 293 294 h = open_file_read_stream(fname); 295 296 /* If we don't have a valid handle immediately return NULL */ 297 if (h == NULL) 298 return (NULL); 299 300 if (debug) 301 (void) printf("Checking the ISO file header\n"); 302 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) { 306 if (debug) 307 (void) printf("ISO header size not sane.\n"); 308 h->bstr_close(h); 309 str_errno = STR_ERR_ISO_BAD_HEADER; 310 return (NULL); 311 } 312 313 if (debug) 314 (void) printf("ISO header size is sane.\n"); 315 316 /* Skip over the boot block sector of the ISO. */ 317 (void) lseek(h->bstr_fd, ISO9660_BOOT_BLOCK_SIZE, SEEK_SET); 318 319 /* 320 * Try to read in the ISO Descriptor and validate this 321 * is in fact an ISO image. 322 */ 323 if (read(h->bstr_fd, iso_desc, ISO9660_PRIMARY_DESC_SIZE) == 324 ISO9660_PRIMARY_DESC_SIZE) { 325 /* 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. 332 */ 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) { 337 if (debug) 338 (void) printf("Invalid ISO identifier.\n"); 339 h->bstr_close(h); 340 str_errno = STR_ERR_ISO_BAD_HEADER; 341 return (NULL); 342 } 343 } else { 344 h->bstr_close(h); 345 str_errno = STR_ERR_ISO_READ_ERR; 346 return (NULL); 347 } 348 349 /* 350 * Our ISO image is valid rewind the stream 351 * and return the handle. 352 */ 353 if (debug) 354 (void) printf("ISO header is sane.\n"); 355 h->bstr_rewind(h); 356 return (h); 357 } 358 359 bstreamhandle 360 open_stdin_read_stream(void) 361 { 362 bstreamhandle h; 363 int mode; 364 365 str_errno = 0; 366 if ((mode = fcntl(0, F_GETFD, NULL)) < 0) { 367 str_errno = STR_ERR_NO_READ_STDIN; 368 return (NULL); 369 } 370 mode &= 3; 371 if ((mode != O_RDONLY) && (mode != O_RDWR)) { 372 str_errno = STR_ERR_NO_READ_STDIN; 373 return (NULL); 374 } 375 h = (bstreamhandle)my_zalloc(sizeof (*h)); 376 h->bstr_fd = 0; 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; 381 382 return (h); 383 } 384 385 bstreamhandle 386 open_au_read_stream(char *fname) 387 { 388 bstreamhandle h; 389 int fd, sav; 390 au_filehdr_t *au; 391 struct stat st; 392 uint32_t data_size; 393 394 au = NULL; 395 str_errno = 0; 396 fd = open(fname, O_RDONLY); 397 if (fd < 0) 398 return (NULL); 399 400 if (fstat(fd, &st) < 0) { 401 goto au_open_failed; 402 } 403 if ((st.st_mode & S_IFMT) != S_IFREG) { 404 str_errno = STR_ERR_NO_REG_FILE; 405 goto au_open_failed; 406 } 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; 410 goto au_open_failed; 411 } 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); 418 419 if (au->au_magic != AUDIO_AU_FILE_MAGIC) { 420 str_errno = STR_ERR_AU_BAD_HEADER; 421 goto au_open_failed; 422 } 423 if ((au->au_encoding != AUDIO_AU_ENCODING_LINEAR_16) || 424 (au->au_sample_rate != 44100) || (au->au_channels != 2)) { 425 426 str_errno = STR_ERR_AU_UNSUPPORTED_FORMAT; 427 goto au_open_failed; 428 } 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; 432 goto au_open_failed; 433 } 434 data_size = au->au_data_size; 435 } else { 436 data_size = st.st_size - au->au_offset; 437 } 438 if (data_size == 0) { 439 str_errno = STR_ERR_AU_UNSUPPORTED_FORMAT; 440 goto au_open_failed; 441 } 442 if (lseek(fd, au->au_offset, SEEK_SET) < 0) { 443 goto au_open_failed; 444 } 445 446 free(au); 447 h = (bstreamhandle)my_zalloc(sizeof (*h)); 448 h->bstr_fd = fd; 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; 454 455 return (h); 456 457 au_open_failed: 458 sav = errno; 459 (void) close(fd); 460 if (au != NULL) 461 free(au); 462 errno = sav; 463 return (NULL); 464 } 465 466 bstreamhandle 467 open_wav_read_stream(char *fname) 468 { 469 bstreamhandle h; 470 int fd, sav; 471 Wave_filehdr *wav; 472 struct stat st; 473 uint32_t data_size; 474 475 wav = NULL; 476 str_errno = 0; 477 fd = open(fname, O_RDONLY); 478 if (fd < 0) 479 return (NULL); 480 481 if (fstat(fd, &st) < 0) { 482 goto wav_open_failed; 483 } 484 if ((st.st_mode & S_IFMT) != S_IFREG) { 485 str_errno = STR_ERR_NO_REG_FILE; 486 goto wav_open_failed; 487 } 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; 492 } 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; 497 } 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)) { 506 507 str_errno = STR_ERR_WAV_UNSUPPORTED_FORMAT; 508 goto wav_open_failed; 509 } 510 data_size = CPU_TO_LE32(wav->data_size); 511 if (lseek(fd, sizeof (*wav), SEEK_SET) < 0) { 512 goto wav_open_failed; 513 } 514 515 free(wav); 516 h = (bstreamhandle)my_zalloc(sizeof (*h)); 517 h->bstr_fd = fd; 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; 523 524 return (h); 525 526 wav_open_failed: 527 sav = errno; 528 (void) close(fd); 529 if (wav != NULL) 530 free(wav); 531 errno = sav; 532 return (NULL); 533 } 534 535 bstreamhandle 536 open_aur_read_stream(char *fname) 537 { 538 bstreamhandle h; 539 540 h = open_file_read_stream(fname); 541 if (h != NULL) { 542 h->bstr_read = file_stream_read_wrbo; 543 } 544 return (h); 545 } 546 547 bstreamhandle 548 open_au_write_stream(char *fname) 549 { 550 bstreamhandle h; 551 int esav, fd; 552 uchar_t head[] = PRE_DEF_AU_HDR; 553 554 str_errno = 0; 555 fd = -1; 556 /* O_RDWR because we need to read while closing */ 557 fd = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666); 558 if (fd < 0) 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; 562 } 563 h = (bstreamhandle)my_zalloc(sizeof (*h)); 564 h->bstr_fd = fd; 565 h->bstr_write = file_stream_write_wrbo; 566 h->bstr_close = au_write_stream_close; 567 return (h); 568 569 open_au_write_stream_failed: 570 esav = errno; 571 if (fd != -1) 572 (void) close(fd); 573 errno = esav; 574 return (NULL); 575 } 576 577 bstreamhandle 578 open_wav_write_stream(char *fname) 579 { 580 bstreamhandle h; 581 int esav, fd; 582 uchar_t head[] = PRE_DEF_WAV_HDR; 583 584 str_errno = 0; 585 fd = -1; 586 fd = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666); 587 if (fd < 0) 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; 591 } 592 h = (bstreamhandle)my_zalloc(sizeof (*h)); 593 h->bstr_fd = fd; 594 h->bstr_write = file_stream_write; 595 h->bstr_close = wav_write_stream_close; 596 return (h); 597 598 open_wav_write_stream_failed: 599 esav = errno; 600 if (fd != -1) 601 (void) close(fd); 602 errno = esav; 603 return (NULL); 604 } 605 606 bstreamhandle 607 open_aur_write_stream(char *fname) 608 { 609 bstreamhandle h; 610 int fd; 611 612 str_errno = 0; 613 fd = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666); 614 if (fd < 0) 615 return (NULL); 616 h = (bstreamhandle)my_zalloc(sizeof (*h)); 617 h->bstr_fd = fd; 618 h->bstr_write = file_stream_write_wrbo; 619 h->bstr_close = file_stream_close; 620 return (h); 621 } 622 623 bstreamhandle 624 open_file_write_stream(char *fname) 625 { 626 bstreamhandle h; 627 int fd; 628 629 str_errno = 0; 630 fd = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666); 631 if (fd < 0) 632 return (NULL); 633 h = (bstreamhandle)my_zalloc(sizeof (*h)); 634 h->bstr_fd = fd; 635 h->bstr_write = file_stream_write; 636 h->bstr_close = file_stream_close; 637 return (h); 638 } 639 640 bstreamhandle 641 open_temp_file_stream(void) 642 { 643 bstreamhandle h; 644 char *t; 645 int fd; 646 647 str_errno = 0; 648 649 t = (char *)get_tmp_name(); 650 651 if (strlcat(t, "/cdXXXXXX", PATH_MAX) >= PATH_MAX) 652 return (NULL); 653 654 fd = mkstemp(t); 655 656 if (debug) 657 (void) printf("temp is: %s length: %d\n", t, strlen(t)); 658 659 if (fd < 0) 660 return (NULL); 661 (void) unlink(t); 662 663 h = (bstreamhandle)my_zalloc(sizeof (*h)); 664 h->bstr_fd = fd; 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; 670 671 return (h); 672 } 673 674 /* 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 678 */ 679 int 680 check_avail_temp_space(size_t req_size) 681 { 682 struct statvfs buf; 683 u_longlong_t free_size = 0; 684 685 if (statvfs(get_tmp_name(), &buf) < 0) { 686 return (errno); 687 } 688 689 free_size = buf.f_bfree * buf.f_frsize; 690 691 if (free_size <= req_size) 692 return (ENOMEM); 693 694 return (0); 695 } 696 697 698 char * 699 get_tmp_name(void) 700 { 701 char *t; 702 char *envptr; 703 704 t = (char *)my_zalloc(PATH_MAX); 705 706 /* 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. 710 */ 711 712 if (alt_tmp_dir) { 713 714 /* copy and leave room for temp filename */ 715 716 (void) strlcpy(t, alt_tmp_dir, PATH_MAX - 10); 717 } else { 718 envptr = getenv("TMPDIR"); 719 if (envptr != NULL) { 720 (void) strlcpy(t, envptr, PATH_MAX - 10); 721 } else { 722 (void) strlcpy(t, "/tmp", 5); 723 } 724 } 725 726 /* 727 * no need to check if path is valid. statvfs will catch 728 * it later and fail with a proper error message. 729 */ 730 731 return (t); 732 } 733