1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*7c478bd9Sstevel@tonic-gate 
29*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
30*7c478bd9Sstevel@tonic-gate #include <stdio.h>
31*7c478bd9Sstevel@tonic-gate #include <unistd.h>
32*7c478bd9Sstevel@tonic-gate #include <errno.h>
33*7c478bd9Sstevel@tonic-gate #include <malloc.h>
34*7c478bd9Sstevel@tonic-gate #include <string.h>
35*7c478bd9Sstevel@tonic-gate #include <fcntl.h>
36*7c478bd9Sstevel@tonic-gate #include <sys/stat.h>
37*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
38*7c478bd9Sstevel@tonic-gate #include <sys/mman.h>
39*7c478bd9Sstevel@tonic-gate 
40*7c478bd9Sstevel@tonic-gate #include <AudioFile.h>
41*7c478bd9Sstevel@tonic-gate #include <AudioLib.h>
42*7c478bd9Sstevel@tonic-gate #include <AudioDebug.h>
43*7c478bd9Sstevel@tonic-gate #include <libaudio.h>
44*7c478bd9Sstevel@tonic-gate #include <audio_hdr.h>
45*7c478bd9Sstevel@tonic-gate 
46*7c478bd9Sstevel@tonic-gate // XX64  This should go away when <sys/mman.h> gets fixed.
47*7c478bd9Sstevel@tonic-gate extern "C" int madvise(caddr_t, size_t, int);
48*7c478bd9Sstevel@tonic-gate 
49*7c478bd9Sstevel@tonic-gate // class AudioFile methods
50*7c478bd9Sstevel@tonic-gate 
51*7c478bd9Sstevel@tonic-gate 
52*7c478bd9Sstevel@tonic-gate // Initialize temporary file params
53*7c478bd9Sstevel@tonic-gate #define	TMPDIR		"/tmp"
54*7c478bd9Sstevel@tonic-gate #define	TMPFILE		"/audiotoolXXXXXX"
55*7c478bd9Sstevel@tonic-gate static char		*tmpdir = NULL;
56*7c478bd9Sstevel@tonic-gate static const char	*tmpname = "(temporary file)";
57*7c478bd9Sstevel@tonic-gate static const FileAccess	tmpmode = ReadWrite;
58*7c478bd9Sstevel@tonic-gate static const VMAccess	defaccess = SequentialAccess;
59*7c478bd9Sstevel@tonic-gate 
60*7c478bd9Sstevel@tonic-gate // Initialize default access mode, used when a filename is supplied
61*7c478bd9Sstevel@tonic-gate const FileAccess	AudioFile::defmode = ReadOnly;
62*7c478bd9Sstevel@tonic-gate 
63*7c478bd9Sstevel@tonic-gate // Default audio file path prefix environment variable
64*7c478bd9Sstevel@tonic-gate const char *AudioFile::AUDIO_PATH = "AUDIOPATH";
65*7c478bd9Sstevel@tonic-gate 
66*7c478bd9Sstevel@tonic-gate 
67*7c478bd9Sstevel@tonic-gate // Constructor with no arguments opens a read/write temporary file
68*7c478bd9Sstevel@tonic-gate AudioFile::
AudioFile()69*7c478bd9Sstevel@tonic-gate AudioFile():
70*7c478bd9Sstevel@tonic-gate 	AudioUnixfile(tmpname, tmpmode),
71*7c478bd9Sstevel@tonic-gate 	hdrsize(0), seekpos(0), origlen(0.), mapaddr(0), maplen(0),
72*7c478bd9Sstevel@tonic-gate 	vmaccess(defaccess)
73*7c478bd9Sstevel@tonic-gate {
74*7c478bd9Sstevel@tonic-gate }
75*7c478bd9Sstevel@tonic-gate 
76*7c478bd9Sstevel@tonic-gate // Constructor with pathname and optional mode arg
77*7c478bd9Sstevel@tonic-gate AudioFile::
AudioFile(const char * path,const FileAccess acc)78*7c478bd9Sstevel@tonic-gate AudioFile(
79*7c478bd9Sstevel@tonic-gate 	const char		*path,		// filename
80*7c478bd9Sstevel@tonic-gate 	const FileAccess	acc):		// access mode
81*7c478bd9Sstevel@tonic-gate 	AudioUnixfile(path, acc),
82*7c478bd9Sstevel@tonic-gate 	hdrsize(0), seekpos(0), origlen(0.), mapaddr(0), maplen(0),
83*7c478bd9Sstevel@tonic-gate 	vmaccess(defaccess)
84*7c478bd9Sstevel@tonic-gate {
85*7c478bd9Sstevel@tonic-gate }
86*7c478bd9Sstevel@tonic-gate 
87*7c478bd9Sstevel@tonic-gate // Destructor must call the local Close() routine
88*7c478bd9Sstevel@tonic-gate AudioFile::
~AudioFile()89*7c478bd9Sstevel@tonic-gate ~AudioFile()
90*7c478bd9Sstevel@tonic-gate {
91*7c478bd9Sstevel@tonic-gate 	// If the file was open, close it
92*7c478bd9Sstevel@tonic-gate 	if (opened())
93*7c478bd9Sstevel@tonic-gate 		(void) Close();
94*7c478bd9Sstevel@tonic-gate }
95*7c478bd9Sstevel@tonic-gate 
96*7c478bd9Sstevel@tonic-gate // Set a default temporary file directory
97*7c478bd9Sstevel@tonic-gate AudioError AudioFile::
SetTempPath(const char * path)98*7c478bd9Sstevel@tonic-gate SetTempPath(
99*7c478bd9Sstevel@tonic-gate 	const char	*path)
100*7c478bd9Sstevel@tonic-gate {
101*7c478bd9Sstevel@tonic-gate 	struct stat	st;
102*7c478bd9Sstevel@tonic-gate 
103*7c478bd9Sstevel@tonic-gate 	// Verify intended path
104*7c478bd9Sstevel@tonic-gate 	if ((stat(path, &st) < 0) ||
105*7c478bd9Sstevel@tonic-gate 	    !S_ISDIR(st.st_mode) ||
106*7c478bd9Sstevel@tonic-gate 	    (access(path, W_OK) < 0)) {
107*7c478bd9Sstevel@tonic-gate 		errno = ENOTDIR;
108*7c478bd9Sstevel@tonic-gate 		return (AUDIO_UNIXERROR);
109*7c478bd9Sstevel@tonic-gate 	}
110*7c478bd9Sstevel@tonic-gate 
111*7c478bd9Sstevel@tonic-gate 	if (tmpdir != NULL)
112*7c478bd9Sstevel@tonic-gate 		(void) free(tmpdir);
113*7c478bd9Sstevel@tonic-gate 	tmpdir = (char *)malloc(strlen(path) + 1);
114*7c478bd9Sstevel@tonic-gate 	(void) strcpy(tmpdir, path);
115*7c478bd9Sstevel@tonic-gate 	return (AUDIO_SUCCESS);
116*7c478bd9Sstevel@tonic-gate }
117*7c478bd9Sstevel@tonic-gate 
118*7c478bd9Sstevel@tonic-gate 
119*7c478bd9Sstevel@tonic-gate // Create a named file according to the current mode setting
120*7c478bd9Sstevel@tonic-gate AudioError AudioFile::
createfile(const char * path)121*7c478bd9Sstevel@tonic-gate createfile(
122*7c478bd9Sstevel@tonic-gate 	const char	*path)			// pathname or 0
123*7c478bd9Sstevel@tonic-gate {
124*7c478bd9Sstevel@tonic-gate 	char		*tmpf;
125*7c478bd9Sstevel@tonic-gate 	char		*tmpstr;
126*7c478bd9Sstevel@tonic-gate 	int		openmode;
127*7c478bd9Sstevel@tonic-gate 	int		desc;
128*7c478bd9Sstevel@tonic-gate 	AudioError	err;
129*7c478bd9Sstevel@tonic-gate 
130*7c478bd9Sstevel@tonic-gate 	// Convert the open mode to an int argument for open()
131*7c478bd9Sstevel@tonic-gate 	openmode = GetAccess();
132*7c478bd9Sstevel@tonic-gate 
133*7c478bd9Sstevel@tonic-gate 	// Was the header properly set?
134*7c478bd9Sstevel@tonic-gate 	if (!hdrset())
135*7c478bd9Sstevel@tonic-gate 		return (RaiseError(AUDIO_ERR_BADHDR));
136*7c478bd9Sstevel@tonic-gate 
137*7c478bd9Sstevel@tonic-gate 	// Can't create if already opened or if mode or name not set
138*7c478bd9Sstevel@tonic-gate 	if ((openmode == -1) || opened() || (strlen(path) == 0))
139*7c478bd9Sstevel@tonic-gate 		return (RaiseError(AUDIO_ERR_NOEFFECT));
140*7c478bd9Sstevel@tonic-gate 
141*7c478bd9Sstevel@tonic-gate 	// If temporary file, create and unlink it.
142*7c478bd9Sstevel@tonic-gate 	if (strcmp(path, tmpname) == 0) {
143*7c478bd9Sstevel@tonic-gate 		// Construct the temporary file path
144*7c478bd9Sstevel@tonic-gate 		tmpstr = (char *)malloc(1 + strlen(TMPFILE) +
145*7c478bd9Sstevel@tonic-gate 		    strlen((tmpdir == NULL) ? TMPDIR : tmpdir));
146*7c478bd9Sstevel@tonic-gate 		(void) sprintf(tmpstr, "%s%s",
147*7c478bd9Sstevel@tonic-gate 		    (tmpdir == NULL) ? TMPDIR : tmpdir, TMPFILE);
148*7c478bd9Sstevel@tonic-gate 		tmpf = mktemp(tmpstr);
149*7c478bd9Sstevel@tonic-gate 
150*7c478bd9Sstevel@tonic-gate 		// Open the temp file and unlink it
151*7c478bd9Sstevel@tonic-gate 		err = createfile(tmpf);
152*7c478bd9Sstevel@tonic-gate 		if ((err == AUDIO_SUCCESS) && (unlink(tmpf) < 0)) {
153*7c478bd9Sstevel@tonic-gate 			(void) Close();
154*7c478bd9Sstevel@tonic-gate 			err = RaiseError(AUDIO_UNIXERROR, Warning);
155*7c478bd9Sstevel@tonic-gate 		}
156*7c478bd9Sstevel@tonic-gate 		(void) free(tmpstr);
157*7c478bd9Sstevel@tonic-gate 		return (err);
158*7c478bd9Sstevel@tonic-gate 	}
159*7c478bd9Sstevel@tonic-gate 
160*7c478bd9Sstevel@tonic-gate 	// Create the file
161*7c478bd9Sstevel@tonic-gate 	desc = open(path, openmode | O_CREAT | O_TRUNC, 0666);
162*7c478bd9Sstevel@tonic-gate 	if ((desc < 0) && (errno == EOVERFLOW)) {
163*7c478bd9Sstevel@tonic-gate 		return (RaiseError(AUDIO_UNIXERROR, Fatal,
164*7c478bd9Sstevel@tonic-gate 		    (char *)"Large File"));
165*7c478bd9Sstevel@tonic-gate 	} else if (desc < 0) {
166*7c478bd9Sstevel@tonic-gate 		return (RaiseError(AUDIO_UNIXERROR));
167*7c478bd9Sstevel@tonic-gate 	}
168*7c478bd9Sstevel@tonic-gate 
169*7c478bd9Sstevel@tonic-gate 	// Set the file descriptor (this marks the file open)
170*7c478bd9Sstevel@tonic-gate 	setfd(desc);
171*7c478bd9Sstevel@tonic-gate 
172*7c478bd9Sstevel@tonic-gate 	// Write the file header with current (usually unknown) size
173*7c478bd9Sstevel@tonic-gate 	err = encode_filehdr();
174*7c478bd9Sstevel@tonic-gate 	if (err != AUDIO_SUCCESS) {
175*7c478bd9Sstevel@tonic-gate 		setfd(-1);
176*7c478bd9Sstevel@tonic-gate 		(void) close(desc);		// If error, remove file
177*7c478bd9Sstevel@tonic-gate 		(void) unlink(path);
178*7c478bd9Sstevel@tonic-gate 		return (err);
179*7c478bd9Sstevel@tonic-gate 	}
180*7c478bd9Sstevel@tonic-gate 
181*7c478bd9Sstevel@tonic-gate 	// Save the length that got written, then set it to zero
182*7c478bd9Sstevel@tonic-gate 	origlen = GetLength();
183*7c478bd9Sstevel@tonic-gate 	setlength(0.);
184*7c478bd9Sstevel@tonic-gate 
185*7c478bd9Sstevel@tonic-gate 	// Set the size of the file header
186*7c478bd9Sstevel@tonic-gate 	hdrsize = lseek(desc, (off_t)0, SEEK_CUR);
187*7c478bd9Sstevel@tonic-gate 	if (hdrsize < 0) {
188*7c478bd9Sstevel@tonic-gate 		setfd(-1);
189*7c478bd9Sstevel@tonic-gate 		(void) close(desc);		// If error, remove file
190*7c478bd9Sstevel@tonic-gate 		(void) unlink(path);
191*7c478bd9Sstevel@tonic-gate 		return (err);
192*7c478bd9Sstevel@tonic-gate 	}
193*7c478bd9Sstevel@tonic-gate 	seekpos = 0;
194*7c478bd9Sstevel@tonic-gate 
195*7c478bd9Sstevel@tonic-gate 	return (AUDIO_SUCCESS);
196*7c478bd9Sstevel@tonic-gate }
197*7c478bd9Sstevel@tonic-gate 
198*7c478bd9Sstevel@tonic-gate // Create a file whose name is already set, according to the mode setting
199*7c478bd9Sstevel@tonic-gate AudioError AudioFile::
Create()200*7c478bd9Sstevel@tonic-gate Create()
201*7c478bd9Sstevel@tonic-gate {
202*7c478bd9Sstevel@tonic-gate 	return (createfile(GetName()));
203*7c478bd9Sstevel@tonic-gate }
204*7c478bd9Sstevel@tonic-gate 
205*7c478bd9Sstevel@tonic-gate // Open a file whose name is set
206*7c478bd9Sstevel@tonic-gate AudioError AudioFile::
Open()207*7c478bd9Sstevel@tonic-gate Open()
208*7c478bd9Sstevel@tonic-gate {
209*7c478bd9Sstevel@tonic-gate 	return (OpenPath(NULL));
210*7c478bd9Sstevel@tonic-gate }
211*7c478bd9Sstevel@tonic-gate 
212*7c478bd9Sstevel@tonic-gate // Open a file, using the specified path prefixes
213*7c478bd9Sstevel@tonic-gate AudioError AudioFile::
OpenPath(const char * path)214*7c478bd9Sstevel@tonic-gate OpenPath(
215*7c478bd9Sstevel@tonic-gate 	const char	*path)
216*7c478bd9Sstevel@tonic-gate {
217*7c478bd9Sstevel@tonic-gate 	char		*filename;
218*7c478bd9Sstevel@tonic-gate 	int		flen;
219*7c478bd9Sstevel@tonic-gate 	char		*prefix;
220*7c478bd9Sstevel@tonic-gate 	char		*str;
221*7c478bd9Sstevel@tonic-gate 	char		*wrk;
222*7c478bd9Sstevel@tonic-gate 	char		*pathname;
223*7c478bd9Sstevel@tonic-gate 	int		openmode;
224*7c478bd9Sstevel@tonic-gate 	AudioError	err;
225*7c478bd9Sstevel@tonic-gate 
226*7c478bd9Sstevel@tonic-gate 	// Convert the open mode to an int argument for open()
227*7c478bd9Sstevel@tonic-gate 	openmode = GetAccess();
228*7c478bd9Sstevel@tonic-gate 	filename = GetName();
229*7c478bd9Sstevel@tonic-gate 	flen = strlen(filename);
230*7c478bd9Sstevel@tonic-gate 
231*7c478bd9Sstevel@tonic-gate 	// Can't open if already opened or if mode or name not set
232*7c478bd9Sstevel@tonic-gate 	if ((openmode == -1) || opened() || (strlen(filename) == 0))
233*7c478bd9Sstevel@tonic-gate 		return (RaiseError(AUDIO_ERR_NOEFFECT));
234*7c478bd9Sstevel@tonic-gate 
235*7c478bd9Sstevel@tonic-gate 	// Search path:
236*7c478bd9Sstevel@tonic-gate 	//	1) try name: if not found and not readonly:
237*7c478bd9Sstevel@tonic-gate 	//		if Append mode, try creating it
238*7c478bd9Sstevel@tonic-gate 	//	2) if name is a relative pathname, and 'path' is not NULL:
239*7c478bd9Sstevel@tonic-gate 	//		try every path prefix in 'path'
240*7c478bd9Sstevel@tonic-gate 
241*7c478bd9Sstevel@tonic-gate 	err = tryopen(filename, openmode);
242*7c478bd9Sstevel@tonic-gate 	if (!err)
243*7c478bd9Sstevel@tonic-gate 		return (AUDIO_SUCCESS);
244*7c478bd9Sstevel@tonic-gate 	if (GetAccess().Writeable() || (filename[0] == '/')) {
245*7c478bd9Sstevel@tonic-gate 		// If file is non-existent and Append mode, try creating it.
246*7c478bd9Sstevel@tonic-gate 		if ((err == AUDIO_UNIXERROR) && (err.sys == ENOENT) &&
247*7c478bd9Sstevel@tonic-gate 		    GetAccess().Append() && hdrset()) {
248*7c478bd9Sstevel@tonic-gate 			return (Create());
249*7c478bd9Sstevel@tonic-gate 		}
250*7c478bd9Sstevel@tonic-gate 		return (RaiseError(err));
251*7c478bd9Sstevel@tonic-gate 	}
252*7c478bd9Sstevel@tonic-gate 
253*7c478bd9Sstevel@tonic-gate 	// Try path as an environment variable name, else assume it is a path
254*7c478bd9Sstevel@tonic-gate 	str = (path == NULL) ? NULL : getenv(path);
255*7c478bd9Sstevel@tonic-gate 	if (str == NULL)
256*7c478bd9Sstevel@tonic-gate 		str = (char *)path;
257*7c478bd9Sstevel@tonic-gate 
258*7c478bd9Sstevel@tonic-gate 	if (str != NULL) {
259*7c478bd9Sstevel@tonic-gate 		// Make a copy of the path, to parse it
260*7c478bd9Sstevel@tonic-gate 		wrk = new char[strlen(str) + 1];
261*7c478bd9Sstevel@tonic-gate 		(void) strcpy(wrk, str);
262*7c478bd9Sstevel@tonic-gate 		str = wrk;
263*7c478bd9Sstevel@tonic-gate 
264*7c478bd9Sstevel@tonic-gate 		// Try each component as a path prefix
265*7c478bd9Sstevel@tonic-gate 		for (prefix = str;
266*7c478bd9Sstevel@tonic-gate 		    (prefix != NULL) && (prefix[0] != '\0');
267*7c478bd9Sstevel@tonic-gate 		    prefix = str) {
268*7c478bd9Sstevel@tonic-gate 			str = strchr(str, ':');
269*7c478bd9Sstevel@tonic-gate 			if (str != NULL)
270*7c478bd9Sstevel@tonic-gate 				*str++ = '\0';
271*7c478bd9Sstevel@tonic-gate 			pathname = new char[strlen(prefix) + flen + 2];
272*7c478bd9Sstevel@tonic-gate 			(void) sprintf(pathname, "%s/%s", prefix, filename);
273*7c478bd9Sstevel@tonic-gate 			err = tryopen(pathname, openmode);
274*7c478bd9Sstevel@tonic-gate 			delete pathname;
275*7c478bd9Sstevel@tonic-gate 			switch (err) {
276*7c478bd9Sstevel@tonic-gate 			case AUDIO_SUCCESS:	// found the file
277*7c478bd9Sstevel@tonic-gate 				delete wrk;
278*7c478bd9Sstevel@tonic-gate 				return (RaiseError(err));
279*7c478bd9Sstevel@tonic-gate 			// XXX - if file found but not audio, stop looking??
280*7c478bd9Sstevel@tonic-gate 			}
281*7c478bd9Sstevel@tonic-gate 		}
282*7c478bd9Sstevel@tonic-gate 		delete wrk;
283*7c478bd9Sstevel@tonic-gate 	}
284*7c478bd9Sstevel@tonic-gate 	// Can't find file.  Return the original error condition.
285*7c478bd9Sstevel@tonic-gate 	return (RaiseError(tryopen(filename, openmode)));
286*7c478bd9Sstevel@tonic-gate }
287*7c478bd9Sstevel@tonic-gate 
288*7c478bd9Sstevel@tonic-gate // Attempt to open the given audio file
289*7c478bd9Sstevel@tonic-gate AudioError AudioFile::
tryopen(const char * pathname,int openmode)290*7c478bd9Sstevel@tonic-gate tryopen(
291*7c478bd9Sstevel@tonic-gate 	const char	*pathname,
292*7c478bd9Sstevel@tonic-gate 	int		openmode)
293*7c478bd9Sstevel@tonic-gate {
294*7c478bd9Sstevel@tonic-gate 	struct stat	st;
295*7c478bd9Sstevel@tonic-gate 	int		desc;
296*7c478bd9Sstevel@tonic-gate 	AudioError	err;
297*7c478bd9Sstevel@tonic-gate 
298*7c478bd9Sstevel@tonic-gate 	// If the name is changing, set the new one
299*7c478bd9Sstevel@tonic-gate 	if (pathname != GetName())
300*7c478bd9Sstevel@tonic-gate 		SetName(pathname);
301*7c478bd9Sstevel@tonic-gate 
302*7c478bd9Sstevel@tonic-gate 	// Does the file exist?
303*7c478bd9Sstevel@tonic-gate 	if (stat(pathname, &st) < 0)
304*7c478bd9Sstevel@tonic-gate 		return (AUDIO_UNIXERROR);
305*7c478bd9Sstevel@tonic-gate 
306*7c478bd9Sstevel@tonic-gate 	// If not a regular file, stop right there
307*7c478bd9Sstevel@tonic-gate 	if (!S_ISREG(st.st_mode))
308*7c478bd9Sstevel@tonic-gate 		return (AUDIO_ERR_BADFILEHDR);
309*7c478bd9Sstevel@tonic-gate 
310*7c478bd9Sstevel@tonic-gate 	// Open the file and check that it's an audio file
311*7c478bd9Sstevel@tonic-gate 	desc = open(GetName(), openmode);
312*7c478bd9Sstevel@tonic-gate 	if ((desc < 0) && (errno == EOVERFLOW)) {
313*7c478bd9Sstevel@tonic-gate 		return (RaiseError(AUDIO_UNIXERROR, Fatal,
314*7c478bd9Sstevel@tonic-gate 		    (char *)"Large File"));
315*7c478bd9Sstevel@tonic-gate 	} else if (desc < 0) {
316*7c478bd9Sstevel@tonic-gate 		return (AUDIO_UNIXERROR);
317*7c478bd9Sstevel@tonic-gate 	}
318*7c478bd9Sstevel@tonic-gate 
319*7c478bd9Sstevel@tonic-gate 	// Set the file descriptor (this marks the file open)
320*7c478bd9Sstevel@tonic-gate 	setfd(desc);
321*7c478bd9Sstevel@tonic-gate 
322*7c478bd9Sstevel@tonic-gate 	err = decode_filehdr();
323*7c478bd9Sstevel@tonic-gate 	if (err != AUDIO_SUCCESS) {
324*7c478bd9Sstevel@tonic-gate 		(void) close(desc);
325*7c478bd9Sstevel@tonic-gate 		setfd(-1);
326*7c478bd9Sstevel@tonic-gate 		return (err);
327*7c478bd9Sstevel@tonic-gate 	}
328*7c478bd9Sstevel@tonic-gate 
329*7c478bd9Sstevel@tonic-gate 	// Save the length of the data and the size of the file header
330*7c478bd9Sstevel@tonic-gate 	origlen = GetLength();
331*7c478bd9Sstevel@tonic-gate 	hdrsize = (off_t)lseek(desc, (off_t)0, SEEK_CUR);
332*7c478bd9Sstevel@tonic-gate 	if (hdrsize < 0) {
333*7c478bd9Sstevel@tonic-gate 		(void) close(desc);
334*7c478bd9Sstevel@tonic-gate 		setfd(-1);
335*7c478bd9Sstevel@tonic-gate 		return (err);
336*7c478bd9Sstevel@tonic-gate 	}
337*7c478bd9Sstevel@tonic-gate 	seekpos = 0;
338*7c478bd9Sstevel@tonic-gate 
339*7c478bd9Sstevel@tonic-gate 	// If this is ReadOnly file, mmap() it.  Don't worry if mmap() fails.
340*7c478bd9Sstevel@tonic-gate 	if (!GetAccess().Writeable()) {
341*7c478bd9Sstevel@tonic-gate 		maplen = st.st_size;
342*7c478bd9Sstevel@tonic-gate 
343*7c478bd9Sstevel@tonic-gate 		/*
344*7c478bd9Sstevel@tonic-gate 		 * Can't mmap LITTLE_ENDIAN as they are converted in
345*7c478bd9Sstevel@tonic-gate 		 * place.
346*7c478bd9Sstevel@tonic-gate 		 */
347*7c478bd9Sstevel@tonic-gate 		if (localByteOrder() == BIG_ENDIAN) {
348*7c478bd9Sstevel@tonic-gate 			if ((mapaddr = (caddr_t)mmap(0, (int)maplen, PROT_READ,
349*7c478bd9Sstevel@tonic-gate 				MAP_SHARED, desc, 0)) != (caddr_t)-1) {
350*7c478bd9Sstevel@tonic-gate 				// set default access method
351*7c478bd9Sstevel@tonic-gate 				(void) madvise(mapaddr, (unsigned int)maplen,
352*7c478bd9Sstevel@tonic-gate 				    (int)GetAccessType());
353*7c478bd9Sstevel@tonic-gate 			} else {
354*7c478bd9Sstevel@tonic-gate 				(void) RaiseError(AUDIO_UNIXERROR, Warning,
355*7c478bd9Sstevel@tonic-gate 				    (char *)"Could not mmap() file");
356*7c478bd9Sstevel@tonic-gate 				mapaddr = 0;
357*7c478bd9Sstevel@tonic-gate 				maplen = 0;
358*7c478bd9Sstevel@tonic-gate 			}
359*7c478bd9Sstevel@tonic-gate 		} else {
360*7c478bd9Sstevel@tonic-gate 			mapaddr = 0;
361*7c478bd9Sstevel@tonic-gate 			maplen = 0;
362*7c478bd9Sstevel@tonic-gate 		}
363*7c478bd9Sstevel@tonic-gate 	}
364*7c478bd9Sstevel@tonic-gate 	return (AUDIO_SUCCESS);
365*7c478bd9Sstevel@tonic-gate }
366*7c478bd9Sstevel@tonic-gate 
367*7c478bd9Sstevel@tonic-gate // set VM access hint for mmapped files
368*7c478bd9Sstevel@tonic-gate AudioError AudioFile::
SetAccessType(VMAccess vmacc)369*7c478bd9Sstevel@tonic-gate SetAccessType(VMAccess vmacc)
370*7c478bd9Sstevel@tonic-gate {
371*7c478bd9Sstevel@tonic-gate 	if (!opened()) {
372*7c478bd9Sstevel@tonic-gate 		return (AUDIO_ERR_NOEFFECT);
373*7c478bd9Sstevel@tonic-gate 	}
374*7c478bd9Sstevel@tonic-gate 
375*7c478bd9Sstevel@tonic-gate 	if (mapaddr == 0) {
376*7c478bd9Sstevel@tonic-gate 		return (AUDIO_ERR_NOEFFECT);
377*7c478bd9Sstevel@tonic-gate 	}
378*7c478bd9Sstevel@tonic-gate 
379*7c478bd9Sstevel@tonic-gate 	(void) madvise(mapaddr, (unsigned int)maplen, (int)vmacc);
380*7c478bd9Sstevel@tonic-gate 	vmaccess = vmacc;
381*7c478bd9Sstevel@tonic-gate 
382*7c478bd9Sstevel@tonic-gate 	return (AUDIO_SUCCESS);
383*7c478bd9Sstevel@tonic-gate }
384*7c478bd9Sstevel@tonic-gate 
385*7c478bd9Sstevel@tonic-gate // Close the file
386*7c478bd9Sstevel@tonic-gate AudioError AudioFile::
Close()387*7c478bd9Sstevel@tonic-gate Close()
388*7c478bd9Sstevel@tonic-gate {
389*7c478bd9Sstevel@tonic-gate 	AudioError	err;
390*7c478bd9Sstevel@tonic-gate 
391*7c478bd9Sstevel@tonic-gate 	if (!opened())
392*7c478bd9Sstevel@tonic-gate 		return (RaiseError(AUDIO_ERR_NOEFFECT, Warning));
393*7c478bd9Sstevel@tonic-gate 
394*7c478bd9Sstevel@tonic-gate 	// Rewind the file and rewrite the header with the correct length
395*7c478bd9Sstevel@tonic-gate 	if (GetAccess().Writeable() && (origlen != GetLength())) {
396*7c478bd9Sstevel@tonic-gate 
397*7c478bd9Sstevel@tonic-gate 		// sanity check
398*7c478bd9Sstevel@tonic-gate 		if (GetHeader().Time_to_Bytes(GetLength()) !=
399*7c478bd9Sstevel@tonic-gate 		    (lseek(getfd(), (off_t)0, SEEK_END) - hdrsize)) {
400*7c478bd9Sstevel@tonic-gate 			PrintMsg(_MGET_(
401*7c478bd9Sstevel@tonic-gate 			    "AudioFile:Close()...inconsistent length\n"),
402*7c478bd9Sstevel@tonic-gate 			    Fatal);
403*7c478bd9Sstevel@tonic-gate 		}
404*7c478bd9Sstevel@tonic-gate 
405*7c478bd9Sstevel@tonic-gate 		// XXX - should be rewritten in C++
406*7c478bd9Sstevel@tonic-gate 		err = (AudioError) audio_rewrite_filesize(getfd(), FILE_AU,
407*7c478bd9Sstevel@tonic-gate 		    (uint_t)GetHeader().Time_to_Bytes(GetLength()), 0, 0);
408*7c478bd9Sstevel@tonic-gate 	}
409*7c478bd9Sstevel@tonic-gate 
410*7c478bd9Sstevel@tonic-gate 	// Call the generic file close routine
411*7c478bd9Sstevel@tonic-gate 	err = AudioUnixfile::Close();
412*7c478bd9Sstevel@tonic-gate 
413*7c478bd9Sstevel@tonic-gate 	if (mapaddr) {
414*7c478bd9Sstevel@tonic-gate 		munmap(mapaddr, (int)maplen);
415*7c478bd9Sstevel@tonic-gate 		mapaddr = 0;
416*7c478bd9Sstevel@tonic-gate 		maplen = 0;
417*7c478bd9Sstevel@tonic-gate 	}
418*7c478bd9Sstevel@tonic-gate 
419*7c478bd9Sstevel@tonic-gate 	// Init important values, in case the file is reopened
420*7c478bd9Sstevel@tonic-gate 	hdrsize = 0;
421*7c478bd9Sstevel@tonic-gate 	seekpos = 0;
422*7c478bd9Sstevel@tonic-gate 	return (RaiseError(err));
423*7c478bd9Sstevel@tonic-gate }
424*7c478bd9Sstevel@tonic-gate 
425*7c478bd9Sstevel@tonic-gate // Read data from underlying file into specified buffer.
426*7c478bd9Sstevel@tonic-gate // No data format translation takes place.
427*7c478bd9Sstevel@tonic-gate // The object's read position pointer is unaffected.
428*7c478bd9Sstevel@tonic-gate AudioError AudioFile::
ReadData(void * buf,size_t & len,Double & pos)429*7c478bd9Sstevel@tonic-gate ReadData(
430*7c478bd9Sstevel@tonic-gate 	void*		buf,		// destination buffer address
431*7c478bd9Sstevel@tonic-gate 	size_t&		len,		// buffer length (updated)
432*7c478bd9Sstevel@tonic-gate 	Double&		pos)		// start position (updated)
433*7c478bd9Sstevel@tonic-gate {
434*7c478bd9Sstevel@tonic-gate 	off_t		offset;
435*7c478bd9Sstevel@tonic-gate 	size_t		cnt;
436*7c478bd9Sstevel@tonic-gate 	caddr_t		cp;
437*7c478bd9Sstevel@tonic-gate 	AudioError	err;
438*7c478bd9Sstevel@tonic-gate 
439*7c478bd9Sstevel@tonic-gate 	// If the file is not mapped, call parent ReadData() and return
440*7c478bd9Sstevel@tonic-gate 	if (mapaddr == 0) {
441*7c478bd9Sstevel@tonic-gate 		// Call the real routine
442*7c478bd9Sstevel@tonic-gate 		err = AudioUnixfile::ReadData(buf, len, pos);
443*7c478bd9Sstevel@tonic-gate 		// Update the cached seek pointer
444*7c478bd9Sstevel@tonic-gate 		seekpos += len;
445*7c478bd9Sstevel@tonic-gate 		return (err);
446*7c478bd9Sstevel@tonic-gate 	}
447*7c478bd9Sstevel@tonic-gate 
448*7c478bd9Sstevel@tonic-gate 	// If the file is mmapped, do a memcpy() from the mapaddr
449*7c478bd9Sstevel@tonic-gate 
450*7c478bd9Sstevel@tonic-gate 	// Save buffer size and zero transfer count
451*7c478bd9Sstevel@tonic-gate 	cnt = (size_t)len;
452*7c478bd9Sstevel@tonic-gate 	len = 0;
453*7c478bd9Sstevel@tonic-gate 
454*7c478bd9Sstevel@tonic-gate 	// Cannot read if file is not open
455*7c478bd9Sstevel@tonic-gate 	if (!opened() || !GetAccess().Readable())
456*7c478bd9Sstevel@tonic-gate 		return (RaiseError(AUDIO_ERR_NOEFFECT));
457*7c478bd9Sstevel@tonic-gate 
458*7c478bd9Sstevel@tonic-gate 	// Position must be valid
459*7c478bd9Sstevel@tonic-gate 	if (Undefined(pos) || (pos < 0.) || ((int)cnt < 0))
460*7c478bd9Sstevel@tonic-gate 		return (RaiseError(AUDIO_ERR_BADARG));
461*7c478bd9Sstevel@tonic-gate 
462*7c478bd9Sstevel@tonic-gate 	// Make sure we don't read off the end of file
463*7c478bd9Sstevel@tonic-gate 	offset = GetHeader().Time_to_Bytes(pos);
464*7c478bd9Sstevel@tonic-gate 
465*7c478bd9Sstevel@tonic-gate 	if ((offset + hdrsize) >= maplen) {
466*7c478bd9Sstevel@tonic-gate 		// trying to read past EOF
467*7c478bd9Sstevel@tonic-gate 		err = AUDIO_EOF;
468*7c478bd9Sstevel@tonic-gate 		err.sys = AUDIO_COPY_INPUT_EOF;
469*7c478bd9Sstevel@tonic-gate 		return (err);
470*7c478bd9Sstevel@tonic-gate 	} else if ((offset + hdrsize + cnt) > maplen) {
471*7c478bd9Sstevel@tonic-gate 		// re-adjust cnt so it reads up to the end of file
472*7c478bd9Sstevel@tonic-gate 		cnt = (size_t)(maplen - (offset + hdrsize));
473*7c478bd9Sstevel@tonic-gate 	}
474*7c478bd9Sstevel@tonic-gate 
475*7c478bd9Sstevel@tonic-gate 	// Zero-length reads are finished
476*7c478bd9Sstevel@tonic-gate 	if (GetHeader().Bytes_to_Bytes(cnt) == 0) {
477*7c478bd9Sstevel@tonic-gate 		err = AUDIO_SUCCESS;
478*7c478bd9Sstevel@tonic-gate 		err.sys = AUDIO_COPY_ZERO_LIMIT;
479*7c478bd9Sstevel@tonic-gate 		return (err);
480*7c478bd9Sstevel@tonic-gate 	} else {
481*7c478bd9Sstevel@tonic-gate 		cp = mapaddr + offset + hdrsize;
482*7c478bd9Sstevel@tonic-gate 		memcpy((void*)buf, (void*)cp, cnt);
483*7c478bd9Sstevel@tonic-gate 	}
484*7c478bd9Sstevel@tonic-gate 
485*7c478bd9Sstevel@tonic-gate 	// Return the updated byte count and position
486*7c478bd9Sstevel@tonic-gate 	len = cnt;
487*7c478bd9Sstevel@tonic-gate 	pos = GetHeader().Bytes_to_Time(offset + len);
488*7c478bd9Sstevel@tonic-gate 
489*7c478bd9Sstevel@tonic-gate 	// Check to see if the endian is right. Note that special care
490*7c478bd9Sstevel@tonic-gate 	// doesn't need to be taken because of the mmap, since the data
491*7c478bd9Sstevel@tonic-gate 	// is copied into a separate buffer anyway.
492*7c478bd9Sstevel@tonic-gate 	coerceEndian((unsigned char *)buf, len, localByteOrder());
493*7c478bd9Sstevel@tonic-gate 
494*7c478bd9Sstevel@tonic-gate 	return (AUDIO_SUCCESS);
495*7c478bd9Sstevel@tonic-gate }
496*7c478bd9Sstevel@tonic-gate 
497*7c478bd9Sstevel@tonic-gate // Write data to underlying file from specified buffer.
498*7c478bd9Sstevel@tonic-gate // No data format translation takes place.
499*7c478bd9Sstevel@tonic-gate // The object's write position pointer is unaffected.
500*7c478bd9Sstevel@tonic-gate AudioError AudioFile::
WriteData(void * buf,size_t & len,Double & pos)501*7c478bd9Sstevel@tonic-gate WriteData(
502*7c478bd9Sstevel@tonic-gate 	void*		buf, // source buffer address
503*7c478bd9Sstevel@tonic-gate 	size_t&		len, // buffer length (updated)
504*7c478bd9Sstevel@tonic-gate 	Double&		pos) // start position (updated)
505*7c478bd9Sstevel@tonic-gate {
506*7c478bd9Sstevel@tonic-gate 	AudioError	err;
507*7c478bd9Sstevel@tonic-gate 
508*7c478bd9Sstevel@tonic-gate 	// Call the real routine
509*7c478bd9Sstevel@tonic-gate 	err = AudioUnixfile::WriteData(buf, len, pos);
510*7c478bd9Sstevel@tonic-gate 
511*7c478bd9Sstevel@tonic-gate 	// Update the cached seek pointer
512*7c478bd9Sstevel@tonic-gate 	seekpos += len;
513*7c478bd9Sstevel@tonic-gate 	return (err);
514*7c478bd9Sstevel@tonic-gate }
515*7c478bd9Sstevel@tonic-gate 
516*7c478bd9Sstevel@tonic-gate // Set the Unix file pointer to match a given file position.
517*7c478bd9Sstevel@tonic-gate AudioError AudioFile::
seekread(Double pos,off_t & offset)518*7c478bd9Sstevel@tonic-gate seekread(
519*7c478bd9Sstevel@tonic-gate 	Double		pos,	// position to seek to
520*7c478bd9Sstevel@tonic-gate 	off_t&		offset)	// returned byte offset
521*7c478bd9Sstevel@tonic-gate {
522*7c478bd9Sstevel@tonic-gate 	offset = GetHeader().Time_to_Bytes(pos);
523*7c478bd9Sstevel@tonic-gate 	if (offset != seekpos) {
524*7c478bd9Sstevel@tonic-gate 		if (lseek(getfd(), (off_t)(hdrsize + offset), SEEK_SET) < 0)
525*7c478bd9Sstevel@tonic-gate 			return (RaiseError(AUDIO_UNIXERROR, Warning));
526*7c478bd9Sstevel@tonic-gate 		seekpos = offset;
527*7c478bd9Sstevel@tonic-gate 	}
528*7c478bd9Sstevel@tonic-gate 	return (AUDIO_SUCCESS);
529*7c478bd9Sstevel@tonic-gate }
530*7c478bd9Sstevel@tonic-gate 
531*7c478bd9Sstevel@tonic-gate // Set the Unix file pointer to match a given file position.
532*7c478bd9Sstevel@tonic-gate // If seek beyond end-of-file, NULL out intervening data.
533*7c478bd9Sstevel@tonic-gate AudioError AudioFile::
seekwrite(Double pos,off_t & offset)534*7c478bd9Sstevel@tonic-gate seekwrite(
535*7c478bd9Sstevel@tonic-gate 	Double		pos,	// position to seek to
536*7c478bd9Sstevel@tonic-gate 	off_t&		offset)	// returned byte offset
537*7c478bd9Sstevel@tonic-gate {
538*7c478bd9Sstevel@tonic-gate 	// If append-only, can't seek backwards into file
539*7c478bd9Sstevel@tonic-gate 	if (GetAccess().Append() && (pos < GetLength()))
540*7c478bd9Sstevel@tonic-gate 		return (RaiseError(AUDIO_ERR_NOEFFECT, Warning));
541*7c478bd9Sstevel@tonic-gate 
542*7c478bd9Sstevel@tonic-gate 	// If seek beyond eof, fill data
543*7c478bd9Sstevel@tonic-gate 	if (pos > GetLength()) {
544*7c478bd9Sstevel@tonic-gate 		seekwrite(GetLength(), offset);	// seek to eof
545*7c478bd9Sstevel@tonic-gate 
546*7c478bd9Sstevel@tonic-gate 		// XXX - not implemented yet
547*7c478bd9Sstevel@tonic-gate 
548*7c478bd9Sstevel@tonic-gate 		return (AUDIO_SUCCESS);
549*7c478bd9Sstevel@tonic-gate 	}
550*7c478bd9Sstevel@tonic-gate 
551*7c478bd9Sstevel@tonic-gate 	offset = GetHeader().Time_to_Bytes(pos);
552*7c478bd9Sstevel@tonic-gate 	if (offset != seekpos) {
553*7c478bd9Sstevel@tonic-gate 		if (lseek(getfd(), (off_t)(hdrsize + offset), SEEK_SET) < 0)
554*7c478bd9Sstevel@tonic-gate 			return (RaiseError(AUDIO_UNIXERROR, Warning));
555*7c478bd9Sstevel@tonic-gate 		seekpos = offset;
556*7c478bd9Sstevel@tonic-gate 	}
557*7c478bd9Sstevel@tonic-gate 	return (AUDIO_SUCCESS);
558*7c478bd9Sstevel@tonic-gate }
559*7c478bd9Sstevel@tonic-gate 
560*7c478bd9Sstevel@tonic-gate // Copy routine that handles mapped files
561*7c478bd9Sstevel@tonic-gate AudioError AudioFile::
AsyncCopy(Audio * to,Double & frompos,Double & topos,Double & limit)562*7c478bd9Sstevel@tonic-gate AsyncCopy(
563*7c478bd9Sstevel@tonic-gate 	Audio*		to,			// audio object to copy to
564*7c478bd9Sstevel@tonic-gate 	Double&		frompos,
565*7c478bd9Sstevel@tonic-gate 	Double&		topos,
566*7c478bd9Sstevel@tonic-gate 	Double&		limit)
567*7c478bd9Sstevel@tonic-gate {
568*7c478bd9Sstevel@tonic-gate 	caddr_t		bptr;
569*7c478bd9Sstevel@tonic-gate 	size_t		offset;
570*7c478bd9Sstevel@tonic-gate 	size_t		cnt;
571*7c478bd9Sstevel@tonic-gate 	size_t		svlim;
572*7c478bd9Sstevel@tonic-gate 	Double		svfrom;
573*7c478bd9Sstevel@tonic-gate 	Double		svto;
574*7c478bd9Sstevel@tonic-gate 	AudioHdr	tohdr;
575*7c478bd9Sstevel@tonic-gate 	AudioError	err;
576*7c478bd9Sstevel@tonic-gate 
577*7c478bd9Sstevel@tonic-gate 	// If this is NOT mmapped, or the destination is an AudioBuffer,
578*7c478bd9Sstevel@tonic-gate 	// use the default routine
579*7c478bd9Sstevel@tonic-gate 	if ((mapaddr == 0) || to->isBuffer()) {
580*7c478bd9Sstevel@tonic-gate 		return (Audio::AsyncCopy(to, frompos, topos, limit));
581*7c478bd9Sstevel@tonic-gate 	}
582*7c478bd9Sstevel@tonic-gate 
583*7c478bd9Sstevel@tonic-gate 	tohdr = to->GetHeader();
584*7c478bd9Sstevel@tonic-gate 	if (err = tohdr.Validate())
585*7c478bd9Sstevel@tonic-gate 		return (err);
586*7c478bd9Sstevel@tonic-gate 	if (limit < 0.)
587*7c478bd9Sstevel@tonic-gate 		return (RaiseError(AUDIO_ERR_BADARG));
588*7c478bd9Sstevel@tonic-gate 	svlim = (size_t)tohdr.Time_to_Bytes(limit);
589*7c478bd9Sstevel@tonic-gate 
590*7c478bd9Sstevel@tonic-gate 	// Get maximum possible copy length
591*7c478bd9Sstevel@tonic-gate 	svfrom = GetLength();
592*7c478bd9Sstevel@tonic-gate 	if ((frompos >= svfrom) || ((cnt = (size_t)
593*7c478bd9Sstevel@tonic-gate 	    GetHeader().Time_to_Bytes(svfrom - frompos)) == 0)) {
594*7c478bd9Sstevel@tonic-gate 		limit = 0.;
595*7c478bd9Sstevel@tonic-gate 		err = AUDIO_EOF;
596*7c478bd9Sstevel@tonic-gate 		err.sys = AUDIO_COPY_INPUT_EOF;
597*7c478bd9Sstevel@tonic-gate 		return (err);
598*7c478bd9Sstevel@tonic-gate 	}
599*7c478bd9Sstevel@tonic-gate 	if (!Undefined(limit) && (svlim < cnt))
600*7c478bd9Sstevel@tonic-gate 		cnt = svlim;
601*7c478bd9Sstevel@tonic-gate 
602*7c478bd9Sstevel@tonic-gate 	limit = 0.;
603*7c478bd9Sstevel@tonic-gate 
604*7c478bd9Sstevel@tonic-gate 	offset = (size_t)GetHeader().Time_to_Bytes(frompos);
605*7c478bd9Sstevel@tonic-gate 	if ((offset + hdrsize) >= maplen) {
606*7c478bd9Sstevel@tonic-gate 		// trying to read past EOF
607*7c478bd9Sstevel@tonic-gate 		err = AUDIO_EOF;
608*7c478bd9Sstevel@tonic-gate 		err.sys = AUDIO_COPY_INPUT_EOF;
609*7c478bd9Sstevel@tonic-gate 		return (err);
610*7c478bd9Sstevel@tonic-gate 	} else if ((offset + hdrsize + cnt) > maplen) {
611*7c478bd9Sstevel@tonic-gate 		// re-adjust cnt so it reads up to the end of file
612*7c478bd9Sstevel@tonic-gate 		cnt = (size_t)(maplen - (offset + hdrsize));
613*7c478bd9Sstevel@tonic-gate 	}
614*7c478bd9Sstevel@tonic-gate 
615*7c478bd9Sstevel@tonic-gate 	// Zero-length reads are done
616*7c478bd9Sstevel@tonic-gate 	if (GetHeader().Bytes_to_Bytes(cnt) == 0) {
617*7c478bd9Sstevel@tonic-gate 		err = AUDIO_SUCCESS;
618*7c478bd9Sstevel@tonic-gate 		err.sys = AUDIO_COPY_ZERO_LIMIT;
619*7c478bd9Sstevel@tonic-gate 		return (err);
620*7c478bd9Sstevel@tonic-gate 	}
621*7c478bd9Sstevel@tonic-gate 
622*7c478bd9Sstevel@tonic-gate 	// Write the data to the destination and update pointers/ctrs
623*7c478bd9Sstevel@tonic-gate 	svfrom = frompos;
624*7c478bd9Sstevel@tonic-gate 	svto = topos;
625*7c478bd9Sstevel@tonic-gate 	svlim = cnt;
626*7c478bd9Sstevel@tonic-gate 	bptr = mapaddr + hdrsize + offset;
627*7c478bd9Sstevel@tonic-gate 	err = to->WriteData(bptr, cnt, topos);
628*7c478bd9Sstevel@tonic-gate 	limit = topos - svto;
629*7c478bd9Sstevel@tonic-gate 	frompos = svfrom + limit;
630*7c478bd9Sstevel@tonic-gate 
631*7c478bd9Sstevel@tonic-gate 	// Report short writes
632*7c478bd9Sstevel@tonic-gate 	if (!err && (cnt < svlim))
633*7c478bd9Sstevel@tonic-gate 		err.sys = AUDIO_COPY_SHORT_OUTPUT;
634*7c478bd9Sstevel@tonic-gate 	return (err);
635*7c478bd9Sstevel@tonic-gate }
636