Home | History | Annotate | Download | only in cdrw
      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 #pragma ident	"%Z%%M%	%I%	%E% SMI"
     27 
     28 #include <fcntl.h>
     29 #include <string.h>
     30 #include <errno.h>
     31 #include <sys/types.h>
     32 #include <unistd.h>
     33 #include <sys/stat.h>
     34 #include <sys/statvfs.h>
     35 #include <stdio.h>
     36 #include <stdlib.h>
     37 #include <libintl.h>
     38 #include <limits.h>
     39 #include <audio/au.h>
     40 
     41 #include "bstream.h"
     42 #include "util.h"
     43 #include "audio.h"
     44 #include "byteorder.h"
     45 #include "main.h"
     46 
     47 int str_errno;
     48 
     49 char *
     50 str_errno_to_string(int serrno)
     51 {
     52 	switch (serrno) {
     53 	case STR_ERR_NO_ERR:
     54 		return (gettext("No error"));
     55 	case STR_ERR_NO_REG_FILE:
     56 		return (gettext("Not a regular file"));
     57 	case STR_ERR_NO_READ_STDIN:
     58 		return (gettext("Stdin not open for reading"));
     59 	case STR_ERR_AU_READ_ERR:
     60 		return (gettext("Unable to read au header"));
     61 	case STR_ERR_AU_UNSUPPORTED_FORMAT:
     62 		return (gettext("Unsupported au format"));
     63 	case STR_ERR_AU_BAD_HEADER:
     64 		return (gettext("Bad au header"));
     65 	case STR_ERR_WAV_READ_ERR:
     66 		return (gettext("Unable to read wav header"));
     67 	case STR_ERR_WAV_UNSUPPORTED_FORMAT:
     68 		return (gettext("Unsupported wav format"));
     69 	case STR_ERR_WAV_BAD_HEADER:
     70 		return (gettext("Bad wav header"));
     71 	case STR_ERR_ISO_READ_ERR:
     72 		return (gettext("Unable to read ISO header"));
     73 	case STR_ERR_ISO_BAD_HEADER:
     74 		return (gettext("Invalid ISO header or not an ISO"));
     75 	default:
     76 		return (gettext("unknown error"));
     77 	}
     78 }
     79 
     80 static int
     81 file_stream_size(bstreamhandle h, off_t *size)
     82 {
     83 	struct stat st;
     84 
     85 	str_errno = 0;
     86 
     87 	if (fstat(h->bstr_fd, &st) < 0)
     88 		return (0);
     89 	if ((st.st_mode & S_IFMT) != S_IFREG) {
     90 		str_errno = STR_ERR_NO_REG_FILE;
     91 		return (0);
     92 	}
     93 	*size = st.st_size;
     94 	return (1);
     95 }
     96 
     97 static int
     98 audio_stream_size(bstreamhandle h, off_t *size)
     99 {
    100 	str_errno = 0;
    101 	*size = (off_t)(uintptr_t)(h->bstr_private);
    102 	return (1);
    103 }
    104 
    105 static int
    106 file_stream_read(bstreamhandle h, uchar_t *buf, off_t size)
    107 {
    108 	str_errno = 0;
    109 	return (read(h->bstr_fd, buf, size));
    110 }
    111 
    112 static int
    113 file_stream_write(bstreamhandle h, uchar_t *buf, off_t size)
    114 {
    115 	str_errno = 0;
    116 	return (write(h->bstr_fd, buf, size));
    117 }
    118 
    119 /*
    120  * with reverse byteorder
    121  */
    122 static int
    123 file_stream_read_wrbo(bstreamhandle h, uchar_t *buf, off_t size)
    124 {
    125 	int cnt;
    126 
    127 	str_errno = 0;
    128 	cnt = read(h->bstr_fd, buf, size);
    129 	if (cnt > 0) {
    130 		int i;
    131 		uchar_t ch;
    132 
    133 		for (i = 0; i < cnt; i += 2) {
    134 			ch = buf[i];
    135 			buf[i] = buf[i+1];
    136 			buf[i+1] = ch;
    137 		}
    138 	}
    139 	return (cnt);
    140 }
    141 
    142 /*
    143  * This will change the byteorder in the buffer but that is fine with us.
    144  */
    145 static int
    146 file_stream_write_wrbo(bstreamhandle h, uchar_t *buf, off_t size)
    147 {
    148 	int i;
    149 	uchar_t ch;
    150 
    151 	str_errno = 0;
    152 	if (size > 0) {
    153 		for (i = 0; i < size; i += 2) {
    154 			ch = buf[i];
    155 			buf[i] = buf[i+1];
    156 			buf[i+1] = ch;
    157 		}
    158 	}
    159 	return (write(h->bstr_fd, buf, size));
    160 }
    161 
    162 static int
    163 file_stream_close(bstreamhandle h)
    164 {
    165 	int fd;
    166 
    167 	str_errno = 0;
    168 	fd = h->bstr_fd;
    169 	free(h);
    170 	return (close(fd));
    171 }
    172 
    173 static int
    174 stdin_stream_close(bstreamhandle h)
    175 {
    176 	str_errno = 0;
    177 	free(h);
    178 	return (0);
    179 }
    180 
    181 static int
    182 wav_write_stream_close(bstreamhandle h)
    183 {
    184 	uint32_t sz;
    185 	Wave_filehdr wav;
    186 
    187 	str_errno = 0;
    188 	(void) memset(&wav, 0, sizeof (wav));
    189 	sz = lseek(h->bstr_fd, 0L, SEEK_END);
    190 	(void) lseek(h->bstr_fd, 0L, SEEK_SET);
    191 	if (read(h->bstr_fd, &wav, sizeof (wav)) != sizeof (wav)) {
    192 		return (1);
    193 	}
    194 	wav.total_chunk_size = CPU_TO_LE32(sz - 8);
    195 	wav.data_size = CPU_TO_LE32(sz - 44);
    196 	(void) lseek(h->bstr_fd, 0L, SEEK_SET);
    197 	if (write(h->bstr_fd, &wav, sizeof (wav)) != sizeof (wav)) {
    198 		return (1);
    199 	}
    200 	(void) close(h->bstr_fd);
    201 	free(h);
    202 	return (0);
    203 }
    204 
    205 static int
    206 au_write_stream_close(bstreamhandle h)
    207 {
    208 	uint32_t sz;
    209 
    210 	str_errno = 0;
    211 	sz = lseek(h->bstr_fd, 0L, SEEK_END);
    212 	sz -= PRE_DEF_AU_HDR_LEN;
    213 	sz = CPU_TO_BE32(sz);
    214 	if (lseek(h->bstr_fd, 8L, SEEK_SET) < 0)
    215 		return (1);
    216 
    217 	if (write(h->bstr_fd, &sz, 4) < 0)
    218 		return (1);
    219 
    220 	(void) close(h->bstr_fd);
    221 	free(h);
    222 	return (0);
    223 }
    224 
    225 /* ARGSUSED */
    226 static void
    227 stdin_stream_rewind(bstreamhandle h)
    228 {
    229 }
    230 
    231 static void
    232 file_stream_rewind(bstreamhandle h)
    233 {
    234 	(void) lseek(h->bstr_fd, 0L, SEEK_SET);
    235 }
    236 
    237 static void
    238 au_stream_rewind(bstreamhandle h)
    239 {
    240 	au_filehdr_t au;
    241 
    242 	(void) lseek(h->bstr_fd, 0L, SEEK_SET);
    243 	if (read(h->bstr_fd, &au, sizeof (au)) != sizeof (au)) {
    244 		return;
    245 	}
    246 
    247 	if (lseek(h->bstr_fd, (long)(BE32_TO_CPU(au.au_offset)),
    248 	    SEEK_SET) < 0) {
    249 		return;
    250 	}
    251 }
    252 
    253 static void
    254 wav_stream_rewind(bstreamhandle h)
    255 {
    256 	(void) lseek(h->bstr_fd, (long)(sizeof (Wave_filehdr)), SEEK_SET);
    257 }
    258 
    259 bstreamhandle
    260 open_file_read_stream(char *file)
    261 {
    262 	bstreamhandle h;
    263 	int fd;
    264 	struct stat st;
    265 
    266 	str_errno = 0;
    267 	if (stat(file, &st) < 0)
    268 		return (NULL);
    269 	if ((st.st_mode & S_IFMT) == S_IFDIR) {
    270 		str_errno = STR_ERR_NO_REG_FILE;
    271 		return (NULL);
    272 	}
    273 	fd = open(file, O_RDONLY);
    274 	if (fd < 0)
    275 		return (NULL);
    276 	h = (bstreamhandle)my_zalloc(sizeof (*h));
    277 	h->bstr_fd = fd;
    278 	h->bstr_read = file_stream_read;
    279 	h->bstr_close = file_stream_close;
    280 	h->bstr_size = file_stream_size;
    281 	h->bstr_rewind = file_stream_rewind;
    282 
    283 	return (h);
    284 }
    285 
    286 bstreamhandle
    287 open_iso_read_stream(char *fname)
    288 {
    289 	bstreamhandle h;
    290 	off_t iso_size = 0;
    291 	char iso_desc[ISO9660_PRIMARY_DESC_SIZE];
    292 
    293 	h = open_file_read_stream(fname);
    294 
    295 	/* If we don't have a valid handle immediately return NULL */
    296 	if (h == NULL)
    297 		return (NULL);
    298 
    299 	if (debug)
    300 		(void) printf("Checking the ISO 9660 file header\n");
    301 
    302 	/* Check to see if we have a valid sized ISO image */
    303 	h->bstr_size(h, &iso_size);
    304 	if (iso_size < ISO9660_HEADER_SIZE) {
    305 		if (debug)
    306 			(void) printf("ISO 9660 header size not sane.\n");
    307 		h->bstr_close(h);
    308 		str_errno = STR_ERR_ISO_BAD_HEADER;
    309 		return (NULL);
    310 	}
    311 
    312 	if (debug)
    313 		(void) printf("ISO 9660 header size is sane.\n");
    314 
    315 	/* Skip over the boot block sector of the ISO. */
    316 	(void) lseek(h->bstr_fd, ISO9660_BOOT_BLOCK_SIZE, SEEK_SET);
    317 
    318 	/*
    319 	 * Try to read in the ISO Descriptor and validate this
    320 	 * is in fact an ISO 9660 image.
    321 	 */
    322 	if (read(h->bstr_fd, iso_desc, ISO9660_PRIMARY_DESC_SIZE) ==
    323 	    ISO9660_PRIMARY_DESC_SIZE) {
    324 		/*
    325 		 * Bytes one through five of a valid ISO 9660 cd image
    326 		 * should contain the string CD001. High Sierra format,
    327 		 * the ISO 9660 predecessor, fills this field with the
    328 		 * string CDROM. If neither is the case then we should
    329 		 * close the stream, set str_errno, and return NULL.
    330 		 */
    331 		if (strncmp(iso_desc + ISO9660_STD_IDENT_OFFSET, "CD001",
    332 		    5) != 0 && strncmp(iso_desc + ISO9660_STD_IDENT_OFFSET,
    333 		    "CDROM", 5) != 0) {
    334 			if (debug)
    335 				(void) printf("Invalid ISO 9660 identifier.\n");
    336 			h->bstr_close(h);
    337 			str_errno = STR_ERR_ISO_BAD_HEADER;
    338 			return (NULL);
    339 		}
    340 	} else {
    341 		h->bstr_close(h);
    342 		str_errno = STR_ERR_ISO_READ_ERR;
    343 		return (NULL);
    344 	}
    345 
    346 	/*
    347 	 * Our ISO image is valid rewind the stream
    348 	 * and return the handle.
    349 	 */
    350 	if (debug)
    351 		(void) printf("ISO 9660 header is sane.\n");
    352 	h->bstr_rewind(h);
    353 	return (h);
    354 }
    355 
    356 bstreamhandle
    357 open_stdin_read_stream(void)
    358 {
    359 	bstreamhandle h;
    360 	int mode;
    361 
    362 	str_errno = 0;
    363 	if ((mode = fcntl(0, F_GETFD, NULL)) < 0) {
    364 		str_errno = STR_ERR_NO_READ_STDIN;
    365 		return (NULL);
    366 	}
    367 	mode &= 3;
    368 	if ((mode != O_RDONLY) && (mode != O_RDWR)) {
    369 		str_errno = STR_ERR_NO_READ_STDIN;
    370 		return (NULL);
    371 	}
    372 	h = (bstreamhandle)my_zalloc(sizeof (*h));
    373 	h->bstr_fd = 0;
    374 	h->bstr_read = file_stream_read;
    375 	h->bstr_close = stdin_stream_close;
    376 	h->bstr_size = file_stream_size;
    377 	h->bstr_rewind = stdin_stream_rewind;
    378 
    379 	return (h);
    380 }
    381 
    382 bstreamhandle
    383 open_au_read_stream(char *fname)
    384 {
    385 	bstreamhandle h;
    386 	int fd, sav;
    387 	au_filehdr_t *au;
    388 	struct stat st;
    389 	uint32_t data_size;
    390 
    391 	au = NULL;
    392 	str_errno = 0;
    393 	fd = open(fname, O_RDONLY);
    394 	if (fd < 0)
    395 		return (NULL);
    396 
    397 	if (fstat(fd, &st) < 0) {
    398 		goto au_open_failed;
    399 	}
    400 	if ((st.st_mode & S_IFMT) != S_IFREG) {
    401 		str_errno = STR_ERR_NO_REG_FILE;
    402 		goto au_open_failed;
    403 	}
    404 	au = (au_filehdr_t *)my_zalloc(sizeof (*au));
    405 	if (read(fd, au, sizeof (*au)) != sizeof (*au)) {
    406 		str_errno = STR_ERR_AU_READ_ERR;
    407 		goto au_open_failed;
    408 	}
    409 	au->au_magic = BE32_TO_CPU(au->au_magic);
    410 	au->au_offset = BE32_TO_CPU(au->au_offset);
    411 	au->au_data_size = BE32_TO_CPU(au->au_data_size);
    412 	au->au_encoding = BE32_TO_CPU(au->au_encoding);
    413 	au->au_sample_rate = BE32_TO_CPU(au->au_sample_rate);
    414 	au->au_channels = BE32_TO_CPU(au->au_channels);
    415 
    416 	if (au->au_magic != AUDIO_AU_FILE_MAGIC) {
    417 		str_errno = STR_ERR_AU_BAD_HEADER;
    418 		goto au_open_failed;
    419 	}
    420 	if ((au->au_encoding != AUDIO_AU_ENCODING_LINEAR_16) ||
    421 	    (au->au_sample_rate != 44100) || (au->au_channels != 2)) {
    422 
    423 		str_errno = STR_ERR_AU_UNSUPPORTED_FORMAT;
    424 		goto au_open_failed;
    425 	}
    426 	if (au->au_data_size != AUDIO_AU_UNKNOWN_SIZE) {
    427 		if ((au->au_offset + au->au_data_size) != st.st_size) {
    428 			str_errno = STR_ERR_AU_BAD_HEADER;
    429 			goto au_open_failed;
    430 		}
    431 		data_size = au->au_data_size;
    432 	} else {
    433 		data_size = st.st_size - au->au_offset;
    434 	}
    435 	if (data_size == 0) {
    436 		str_errno = STR_ERR_AU_UNSUPPORTED_FORMAT;
    437 		goto au_open_failed;
    438 	}
    439 	if (lseek(fd, au->au_offset, SEEK_SET) < 0) {
    440 		goto au_open_failed;
    441 	}
    442 
    443 	free(au);
    444 	h = (bstreamhandle)my_zalloc(sizeof (*h));
    445 	h->bstr_fd = fd;
    446 	h->bstr_read = file_stream_read_wrbo;
    447 	h->bstr_close = file_stream_close;
    448 	h->bstr_size = audio_stream_size;
    449 	h->bstr_rewind = au_stream_rewind;
    450 	h->bstr_private = (void *)data_size;
    451 
    452 	return (h);
    453 
    454 au_open_failed:
    455 	sav = errno;
    456 	(void) close(fd);
    457 	if (au != NULL)
    458 		free(au);
    459 	errno = sav;
    460 	return (NULL);
    461 }
    462 
    463 bstreamhandle
    464 open_wav_read_stream(char *fname)
    465 {
    466 	bstreamhandle h;
    467 	int fd, sav;
    468 	Wave_filehdr *wav;
    469 	struct stat st;
    470 	uint32_t data_size;
    471 
    472 	wav = NULL;
    473 	str_errno = 0;
    474 	fd = open(fname, O_RDONLY);
    475 	if (fd < 0)
    476 		return (NULL);
    477 
    478 	if (fstat(fd, &st) < 0) {
    479 		goto wav_open_failed;
    480 	}
    481 	if ((st.st_mode & S_IFMT) != S_IFREG) {
    482 		str_errno = STR_ERR_NO_REG_FILE;
    483 		goto wav_open_failed;
    484 	}
    485 	wav = (Wave_filehdr *)my_zalloc(sizeof (*wav));
    486 	if (read(fd, wav, sizeof (*wav)) != sizeof (*wav)) {
    487 		str_errno = STR_ERR_WAV_READ_ERR;
    488 		goto wav_open_failed;
    489 	}
    490 	if ((strncmp(wav->riff, "RIFF", 4) != 0) ||
    491 		(strncmp(wav->wave, "WAVE", 4) != 0)) {
    492 		str_errno = STR_ERR_WAV_BAD_HEADER;
    493 		goto wav_open_failed;
    494 	}
    495 	if (((CPU_TO_LE32(wav->total_chunk_size) + 8) != st.st_size) ||
    496 	    (strncmp(wav->fmt, "fmt ", 4) != 0) ||
    497 	    (CPU_TO_LE16(wav->fmt_tag) != 1) ||
    498 	    (CPU_TO_LE16(wav->n_channels) != 2) ||
    499 	    (CPU_TO_LE32(wav->sample_rate) != 44100) ||
    500 	    (CPU_TO_LE16(wav->bits_per_sample) != 16) ||
    501 	    (strncmp(wav->data, "data", 4) != 0) ||
    502 	    ((CPU_TO_LE32(wav->data_size) + 44) != st.st_size)) {
    503 
    504 		str_errno = STR_ERR_WAV_UNSUPPORTED_FORMAT;
    505 		goto wav_open_failed;
    506 	}
    507 	data_size = CPU_TO_LE32(wav->data_size);
    508 	if (lseek(fd, sizeof (*wav), SEEK_SET) < 0) {
    509 		goto wav_open_failed;
    510 	}
    511 
    512 	free(wav);
    513 	h = (bstreamhandle)my_zalloc(sizeof (*h));
    514 	h->bstr_fd = fd;
    515 	h->bstr_read = file_stream_read;
    516 	h->bstr_close = file_stream_close;
    517 	h->bstr_size = audio_stream_size;
    518 	h->bstr_rewind = wav_stream_rewind;
    519 	h->bstr_private = (void *)data_size;
    520 
    521 	return (h);
    522 
    523 wav_open_failed:
    524 	sav = errno;
    525 	(void) close(fd);
    526 	if (wav != NULL)
    527 		free(wav);
    528 	errno = sav;
    529 	return (NULL);
    530 }
    531 
    532 bstreamhandle
    533 open_aur_read_stream(char *fname)
    534 {
    535 	bstreamhandle h;
    536 
    537 	h = open_file_read_stream(fname);
    538 	if (h != NULL) {
    539 		h->bstr_read = file_stream_read_wrbo;
    540 	}
    541 	return (h);
    542 }
    543 
    544 bstreamhandle
    545 open_au_write_stream(char *fname)
    546 {
    547 	bstreamhandle h;
    548 	int esav, fd;
    549 	uchar_t head[] = PRE_DEF_AU_HDR;
    550 
    551 	str_errno = 0;
    552 	fd = -1;
    553 	/* O_RDWR because we need to read while closing */
    554 	fd = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666);
    555 	if (fd < 0)
    556 		goto open_au_write_stream_failed;
    557 	if (write(fd, head, PRE_DEF_AU_HDR_LEN) != PRE_DEF_AU_HDR_LEN) {
    558 		goto open_au_write_stream_failed;
    559 	}
    560 	h = (bstreamhandle)my_zalloc(sizeof (*h));
    561 	h->bstr_fd = fd;
    562 	h->bstr_write = file_stream_write_wrbo;
    563 	h->bstr_close = au_write_stream_close;
    564 	return (h);
    565 
    566 open_au_write_stream_failed:
    567 	esav = errno;
    568 	if (fd != -1)
    569 		(void) close(fd);
    570 	errno = esav;
    571 	return (NULL);
    572 }
    573 
    574 bstreamhandle
    575 open_wav_write_stream(char *fname)
    576 {
    577 	bstreamhandle h;
    578 	int esav, fd;
    579 	uchar_t head[] = PRE_DEF_WAV_HDR;
    580 
    581 	str_errno = 0;
    582 	fd = -1;
    583 	fd = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666);
    584 	if (fd < 0)
    585 		goto open_wav_write_stream_failed;
    586 	if (write(fd, head, PRE_DEF_WAV_HDR_LEN) != PRE_DEF_WAV_HDR_LEN) {
    587 		goto open_wav_write_stream_failed;
    588 	}
    589 	h = (bstreamhandle)my_zalloc(sizeof (*h));
    590 	h->bstr_fd = fd;
    591 	h->bstr_write = file_stream_write;
    592 	h->bstr_close = wav_write_stream_close;
    593 	return (h);
    594 
    595 open_wav_write_stream_failed:
    596 	esav = errno;
    597 	if (fd != -1)
    598 		(void) close(fd);
    599 	errno = esav;
    600 	return (NULL);
    601 }
    602 
    603 bstreamhandle
    604 open_aur_write_stream(char *fname)
    605 {
    606 	bstreamhandle h;
    607 	int fd;
    608 
    609 	str_errno = 0;
    610 	fd = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666);
    611 	if (fd < 0)
    612 		return (NULL);
    613 	h = (bstreamhandle)my_zalloc(sizeof (*h));
    614 	h->bstr_fd = fd;
    615 	h->bstr_write = file_stream_write_wrbo;
    616 	h->bstr_close = file_stream_close;
    617 	return (h);
    618 }
    619 
    620 bstreamhandle
    621 open_file_write_stream(char *fname)
    622 {
    623 	bstreamhandle h;
    624 	int fd;
    625 
    626 	str_errno = 0;
    627 	fd = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666);
    628 	if (fd < 0)
    629 		return (NULL);
    630 	h = (bstreamhandle)my_zalloc(sizeof (*h));
    631 	h->bstr_fd = fd;
    632 	h->bstr_write = file_stream_write;
    633 	h->bstr_close = file_stream_close;
    634 	return (h);
    635 }
    636 
    637 bstreamhandle
    638 open_temp_file_stream(void)
    639 {
    640 	bstreamhandle h;
    641 	char *t;
    642 	int fd;
    643 
    644 	str_errno = 0;
    645 
    646 	t = (char *)get_tmp_name();
    647 
    648 	if (strlcat(t, "/cdXXXXXX", PATH_MAX) >= PATH_MAX)
    649 		return (NULL);
    650 
    651 	fd = mkstemp(t);
    652 
    653 	if (debug)
    654 		(void) printf("temp is: %s length: %d\n", t, strlen(t));
    655 
    656 	if (fd < 0)
    657 		return (NULL);
    658 	(void) unlink(t);
    659 
    660 	h = (bstreamhandle)my_zalloc(sizeof (*h));
    661 	h->bstr_fd = fd;
    662 	h->bstr_read = file_stream_read;
    663 	h->bstr_write = file_stream_write;
    664 	h->bstr_close = file_stream_close;
    665 	h->bstr_size = file_stream_size;
    666 	h->bstr_rewind = file_stream_rewind;
    667 
    668 	return (h);
    669 }
    670 
    671 /*
    672  * check_avail_temp_space returns 0 if there is adequate space
    673  * in the temporary directory, or a non-zero error code if
    674  * something goes wrong
    675  */
    676 int
    677 check_avail_temp_space(size_t req_size)
    678 {
    679 	struct statvfs buf;
    680 	u_longlong_t free_size = 0;
    681 
    682 	if (statvfs(get_tmp_name(), &buf) < 0) {
    683 		return (errno);
    684 	}
    685 
    686 	free_size = buf.f_bfree * buf.f_frsize;
    687 
    688 	if (free_size <= req_size)
    689 		return (ENOMEM);
    690 
    691 	return (0);
    692 }
    693 
    694 
    695 char *
    696 get_tmp_name(void)
    697 {
    698 	char *t;
    699 	char *envptr;
    700 
    701 	t = (char *)my_zalloc(PATH_MAX);
    702 
    703 	/*
    704 	 * generate temp directory path based on this order:
    705 	 * user specified (-m option), temp env variable,
    706 	 * and finally /tmp if nothing is found.
    707 	 */
    708 
    709 	if (alt_tmp_dir) {
    710 
    711 		/* copy and leave room for temp filename */
    712 
    713 		(void) strlcpy(t, alt_tmp_dir, PATH_MAX - 10);
    714 	} else {
    715 		envptr = getenv("TMPDIR");
    716 		if (envptr != NULL) {
    717 			(void) strlcpy(t, envptr, PATH_MAX - 10);
    718 		} else {
    719 			(void) strlcpy(t, "/tmp", 5);
    720 		}
    721 	}
    722 
    723 	/*
    724 	 * no need to check if path is valid. statvfs will catch
    725 	 * it later and fail with a proper error message.
    726 	 */
    727 
    728 	return (t);
    729 }
    730