xref: /titanic_51/usr/src/lib/libast/common/sfio/sfsetbuf.c (revision 3e14f97f673e8a630f076077de35afdd43dc1587)
1da2e3ebdSchin /***********************************************************************
2da2e3ebdSchin *                                                                      *
3da2e3ebdSchin *               This software is part of the ast package               *
4*3e14f97fSRoger A. Faulkner *          Copyright (c) 1985-2010 AT&T Intellectual Property          *
5da2e3ebdSchin *                      and is licensed under the                       *
6da2e3ebdSchin *                  Common Public License, Version 1.0                  *
77c2fbfb3SApril Chin *                    by AT&T Intellectual Property                     *
8da2e3ebdSchin *                                                                      *
9da2e3ebdSchin *                A copy of the License is available at                 *
10da2e3ebdSchin *            http://www.opensource.org/licenses/cpl1.0.txt             *
11da2e3ebdSchin *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
12da2e3ebdSchin *                                                                      *
13da2e3ebdSchin *              Information and Software Systems Research               *
14da2e3ebdSchin *                            AT&T Research                             *
15da2e3ebdSchin *                           Florham Park NJ                            *
16da2e3ebdSchin *                                                                      *
17da2e3ebdSchin *                 Glenn Fowler <gsf@research.att.com>                  *
18da2e3ebdSchin *                  David Korn <dgk@research.att.com>                   *
19da2e3ebdSchin *                   Phong Vo <kpv@research.att.com>                    *
20da2e3ebdSchin *                                                                      *
21da2e3ebdSchin ***********************************************************************/
22da2e3ebdSchin #if defined(__STDPP__directive) && defined(__STDPP__hide)
23da2e3ebdSchin __STDPP__directive pragma pp:hide getpagesize
24da2e3ebdSchin #else
25da2e3ebdSchin #define getpagesize	______getpagesize
26da2e3ebdSchin #endif
27da2e3ebdSchin 
28da2e3ebdSchin #include	"sfhdr.h"
29da2e3ebdSchin 
30da2e3ebdSchin #if defined(__STDPP__directive) && defined(__STDPP__hide)
31da2e3ebdSchin __STDPP__directive pragma pp:nohide getpagesize
32da2e3ebdSchin #else
33da2e3ebdSchin #undef	getpagesize
34da2e3ebdSchin #endif
35da2e3ebdSchin 
36da2e3ebdSchin #if _lib_getpagesize
37da2e3ebdSchin _BEGIN_EXTERNS_
38da2e3ebdSchin extern int	getpagesize _ARG_((void));
39da2e3ebdSchin _END_EXTERNS_
40da2e3ebdSchin #endif
41da2e3ebdSchin 
42da2e3ebdSchin /*	Set a (new) buffer for a stream.
43da2e3ebdSchin **	If size < 0, it is assigned a suitable value depending on the
44da2e3ebdSchin **	kind of stream. The actual buffer size allocated is dependent
45da2e3ebdSchin **	on how much memory is available.
46da2e3ebdSchin **
47da2e3ebdSchin **	Written by Kiem-Phong Vo.
48da2e3ebdSchin */
49da2e3ebdSchin 
50da2e3ebdSchin #if !_sys_stat
51da2e3ebdSchin struct stat
52da2e3ebdSchin {	int	st_mode;
53da2e3ebdSchin 	int	st_size;
54da2e3ebdSchin };
55da2e3ebdSchin #undef sysfstatf
56da2e3ebdSchin #define sysfstatf(fd,st)	(-1)
57da2e3ebdSchin #endif /*_sys_stat*/
58da2e3ebdSchin 
setlinemode()59da2e3ebdSchin static int setlinemode()
60da2e3ebdSchin {	char*			astsfio;
61da2e3ebdSchin 	char*			endw;
62da2e3ebdSchin 
63da2e3ebdSchin 	static int		modes = -1;
64da2e3ebdSchin 	static const char	sf_line[] = "SF_LINE";
65da2e3ebdSchin 	static const char	sf_wcwidth[] = "SF_WCWIDTH";
66da2e3ebdSchin 
67da2e3ebdSchin #define ISSEPAR(c)	((c) == ',' || (c) == ' ' || (c) == '\t')
68da2e3ebdSchin 	if (modes < 0)
69da2e3ebdSchin 	{	modes = 0;
70da2e3ebdSchin 		if(astsfio = getenv("_AST_SFIO_OPTIONS"))
71da2e3ebdSchin 		{	for(; *astsfio != 0; astsfio = endw)
72da2e3ebdSchin 			{	while(ISSEPAR(*astsfio) )
73da2e3ebdSchin 					*astsfio++;
74da2e3ebdSchin 				for(endw = astsfio; *endw && !ISSEPAR(*endw); ++endw)
75da2e3ebdSchin 					;
76da2e3ebdSchin 				if((endw-astsfio) == (sizeof(sf_line)-1) &&
77da2e3ebdSchin 				   strncmp(astsfio,sf_line,endw-astsfio) == 0)
78da2e3ebdSchin 				{	if ((modes |= SF_LINE) == (SF_LINE|SF_WCWIDTH))
79da2e3ebdSchin 						break;
80da2e3ebdSchin 				}
81da2e3ebdSchin 				else if((endw-astsfio) == (sizeof(sf_wcwidth)-1) &&
82da2e3ebdSchin 				   strncmp(astsfio,sf_wcwidth,endw-astsfio) == 0)
83da2e3ebdSchin 				{	if ((modes |= SF_WCWIDTH) == (SF_LINE|SF_WCWIDTH))
84da2e3ebdSchin 						break;
85da2e3ebdSchin 				}
86da2e3ebdSchin 			}
87da2e3ebdSchin 		}
88da2e3ebdSchin 	}
89da2e3ebdSchin 	return modes;
90da2e3ebdSchin }
91da2e3ebdSchin 
92da2e3ebdSchin #if __STD_C
sfsetbuf(Sfio_t * f,Void_t * buf,size_t size)937c2fbfb3SApril Chin Void_t* sfsetbuf(Sfio_t* f, Void_t* buf, size_t size)
94da2e3ebdSchin #else
95da2e3ebdSchin Void_t* sfsetbuf(f,buf,size)
967c2fbfb3SApril Chin Sfio_t*	f;	/* stream to be buffered */
977c2fbfb3SApril Chin Void_t*	buf;	/* new buffer */
987c2fbfb3SApril Chin size_t	size;	/* buffer size, -1 for default size */
99da2e3ebdSchin #endif
100da2e3ebdSchin {
101da2e3ebdSchin 	int		sf_malloc, oflags, init, okmmap, local;
102da2e3ebdSchin 	ssize_t		bufsize, blksz;
103da2e3ebdSchin 	Sfdisc_t*	disc;
104da2e3ebdSchin 	sfstat_t	st;
105da2e3ebdSchin 	uchar*		obuf = NIL(uchar*);
106da2e3ebdSchin 	ssize_t		osize = 0;
1077c2fbfb3SApril Chin 	SFMTXDECL(f);
108da2e3ebdSchin 
109da2e3ebdSchin 	SFONCE();
110da2e3ebdSchin 
1117c2fbfb3SApril Chin 	SFMTXENTER(f,NIL(Void_t*));
112da2e3ebdSchin 
113da2e3ebdSchin 	GETLOCAL(f,local);
114da2e3ebdSchin 
115da2e3ebdSchin 	if(size == 0 && buf)
116da2e3ebdSchin 	{	/* special case to get buffer info */
117da2e3ebdSchin 		_Sfi = f->val = (f->bits&SF_MMAP) ? (f->endb-f->data) : f->size;
118da2e3ebdSchin 		SFMTXRETURN(f, (Void_t*)f->data);
119da2e3ebdSchin 	}
120da2e3ebdSchin 
121da2e3ebdSchin 	/* cleanup actions already done, don't allow write buffering any more */
122da2e3ebdSchin 	if(_Sfexiting && !(f->flags&SF_STRING) && (f->mode&SF_WRITE))
123da2e3ebdSchin 	{	buf = NIL(Void_t*);
124da2e3ebdSchin 		size = 0;
125da2e3ebdSchin 	}
126da2e3ebdSchin 
127da2e3ebdSchin 	if((init = f->mode&SF_INIT) )
128da2e3ebdSchin 	{	if(!f->pool && _sfsetpool(f) < 0)
129da2e3ebdSchin 			SFMTXRETURN(f, NIL(Void_t*));
130da2e3ebdSchin 	}
131da2e3ebdSchin 	else if((f->mode&SF_RDWR) != SFMODE(f,local) && _sfmode(f,0,local) < 0)
132da2e3ebdSchin 		SFMTXRETURN(f, NIL(Void_t*));
133da2e3ebdSchin 
134da2e3ebdSchin 	if(init)
135da2e3ebdSchin 		f->mode = (f->mode&SF_RDWR)|SF_LOCK;
136da2e3ebdSchin 	else
137da2e3ebdSchin 	{	int	rv;
138da2e3ebdSchin 
139da2e3ebdSchin 		/* make sure there is no hidden read data */
140da2e3ebdSchin 		if(f->proc && (f->flags&SF_READ) && (f->mode&SF_WRITE) &&
141da2e3ebdSchin 		   _sfmode(f,SF_READ,local) < 0)
142da2e3ebdSchin 			SFMTXRETURN(f, NIL(Void_t*));
143da2e3ebdSchin 
144da2e3ebdSchin 		/* synchronize first */
145da2e3ebdSchin 		SFLOCK(f,local); rv = SFSYNC(f); SFOPEN(f,local);
146da2e3ebdSchin 		if(rv < 0)
147da2e3ebdSchin 			SFMTXRETURN(f, NIL(Void_t*));
148da2e3ebdSchin 
149da2e3ebdSchin 		/* turn off the SF_SYNCED bit because buffer is changing */
150da2e3ebdSchin 		f->mode &= ~SF_SYNCED;
151da2e3ebdSchin 	}
152da2e3ebdSchin 
153da2e3ebdSchin 	SFLOCK(f,local);
154da2e3ebdSchin 
155da2e3ebdSchin 	if((Sfio_t*)buf != f)
156da2e3ebdSchin 		blksz = -1;
157da2e3ebdSchin 	else /* setting alignment size only */
158da2e3ebdSchin 	{	blksz = (ssize_t)size;
159da2e3ebdSchin 
160da2e3ebdSchin 		if(!init) /* stream already initialized */
161da2e3ebdSchin 		{	obuf = f->data;
162da2e3ebdSchin 			osize = f->size;
163da2e3ebdSchin 			goto done;
164da2e3ebdSchin 		}
165da2e3ebdSchin 		else /* initialize stream as if in the default case */
166da2e3ebdSchin 		{	buf = NIL(Void_t*);
167da2e3ebdSchin 			size = (size_t)SF_UNBOUND;
168da2e3ebdSchin 		}
169da2e3ebdSchin 	}
170da2e3ebdSchin 
171da2e3ebdSchin 	bufsize = 0;
172da2e3ebdSchin 	oflags = f->flags;
173da2e3ebdSchin 
174da2e3ebdSchin 	/* see if memory mapping is possible (see sfwrite for SF_BOTH) */
175da2e3ebdSchin 	okmmap = (buf || (f->flags&SF_STRING) || (f->flags&SF_RDWR) == SF_RDWR) ? 0 : 1;
176da2e3ebdSchin 
177da2e3ebdSchin 	/* save old buffer info */
178da2e3ebdSchin #ifdef MAP_TYPE
179da2e3ebdSchin 	if(f->bits&SF_MMAP)
180da2e3ebdSchin 	{	if(f->data)
181da2e3ebdSchin 		{	SFMUNMAP(f,f->data,f->endb-f->data);
182da2e3ebdSchin 			f->data = NIL(uchar*);
183da2e3ebdSchin 		}
184da2e3ebdSchin 	} else
185da2e3ebdSchin #endif
186da2e3ebdSchin 	if(f->data == f->tiny)
187da2e3ebdSchin 	{	f->data = NIL(uchar*);
188da2e3ebdSchin 		f->size = 0;
189da2e3ebdSchin 	}
190da2e3ebdSchin 	obuf  = f->data;
191da2e3ebdSchin 	osize = f->size;
192da2e3ebdSchin 
193da2e3ebdSchin 	f->flags &= ~SF_MALLOC;
194da2e3ebdSchin 	f->bits  &= ~SF_MMAP;
195da2e3ebdSchin 
196da2e3ebdSchin 	/* pure read/string streams must have a valid string */
197da2e3ebdSchin 	if((f->flags&(SF_RDWR|SF_STRING)) == SF_RDSTR &&
198da2e3ebdSchin 	   (size == (size_t)SF_UNBOUND || !buf))
199da2e3ebdSchin 		size = 0;
200da2e3ebdSchin 
201da2e3ebdSchin 	/* set disc to the first discipline with a seekf */
202da2e3ebdSchin 	for(disc = f->disc; disc; disc = disc->disc)
203da2e3ebdSchin 		if(disc->seekf)
204da2e3ebdSchin 			break;
205da2e3ebdSchin 
206da2e3ebdSchin 	if((init || local) && !(f->flags&SF_STRING))
207da2e3ebdSchin 	{	/* ASSERT(f->file >= 0) */
208da2e3ebdSchin 		st.st_mode = 0;
209da2e3ebdSchin 
210da2e3ebdSchin 		/* if has discipline, set size by discipline if possible */
211da2e3ebdSchin 		if(!_sys_stat || disc)
212da2e3ebdSchin 		{	if((f->here = SFSK(f,(Sfoff_t)0,SEEK_CUR,disc)) < 0)
213da2e3ebdSchin 				goto unseekable;
214da2e3ebdSchin 			else
215da2e3ebdSchin 			{	Sfoff_t	e;
216da2e3ebdSchin 				if((e = SFSK(f,(Sfoff_t)0,SEEK_END,disc)) >= 0)
217da2e3ebdSchin 					f->extent = e > f->here ? e : f->here;
218da2e3ebdSchin 				(void)SFSK(f,f->here,SEEK_SET,disc);
219da2e3ebdSchin 				goto setbuf;
220da2e3ebdSchin 			}
221da2e3ebdSchin 		}
222da2e3ebdSchin 
223da2e3ebdSchin 		/* get file descriptor status */
224da2e3ebdSchin 		if(sysfstatf((int)f->file,&st) < 0)
225da2e3ebdSchin 			f->here = -1;
226da2e3ebdSchin 		else
227da2e3ebdSchin 		{
228da2e3ebdSchin #if _sys_stat && _stat_blksize	/* preferred io block size */
229da2e3ebdSchin 			f->blksz = (size_t)st.st_blksize;
230da2e3ebdSchin #endif
231da2e3ebdSchin 			bufsize = 64 * 1024;
232da2e3ebdSchin 			if(S_ISDIR(st.st_mode) || (Sfoff_t)st.st_size < (Sfoff_t)SF_GRAIN)
233da2e3ebdSchin 				okmmap = 0;
234da2e3ebdSchin 			if(S_ISREG(st.st_mode) || S_ISDIR(st.st_mode))
235da2e3ebdSchin 				f->here = SFSK(f,(Sfoff_t)0,SEEK_CUR,f->disc);
236da2e3ebdSchin 			else	f->here = -1;
237da2e3ebdSchin 
238da2e3ebdSchin #if O_TEXT /* no memory mapping with O_TEXT because read()/write() alter data stream */
239da2e3ebdSchin 			if(okmmap && f->here >= 0 &&
240da2e3ebdSchin 			   (sysfcntlf((int)f->file,F_GETFL,0) & O_TEXT) )
241da2e3ebdSchin 				okmmap = 0;
242da2e3ebdSchin #endif
243da2e3ebdSchin 		}
244da2e3ebdSchin 
245da2e3ebdSchin 		if(init)
246da2e3ebdSchin 			f->flags |= setlinemode();
247da2e3ebdSchin 
248da2e3ebdSchin 		if(f->here >= 0)
249da2e3ebdSchin 		{	f->extent = (Sfoff_t)st.st_size;
250da2e3ebdSchin 
251da2e3ebdSchin 			/* seekable std-devices are share-public by default */
252da2e3ebdSchin 			if(f == sfstdin || f == sfstdout || f == sfstderr)
253da2e3ebdSchin 				f->flags |= SF_SHARE|SF_PUBLIC;
254da2e3ebdSchin 		}
255da2e3ebdSchin 		else
256da2e3ebdSchin 		{
257da2e3ebdSchin 		unseekable:
258da2e3ebdSchin 			f->extent = -1;
259da2e3ebdSchin 			f->here = 0;
260da2e3ebdSchin 
261da2e3ebdSchin 			if(init)
262da2e3ebdSchin 			{	if(S_ISCHR(st.st_mode) )
263da2e3ebdSchin 				{	int oerrno = errno;
264da2e3ebdSchin 
265da2e3ebdSchin 					bufsize = SF_GRAIN;
266da2e3ebdSchin 
267da2e3ebdSchin 					/* set line mode for terminals */
268da2e3ebdSchin 					if(!(f->flags&(SF_LINE|SF_WCWIDTH)) && isatty(f->file))
269da2e3ebdSchin 						f->flags |= SF_LINE|SF_WCWIDTH;
270da2e3ebdSchin #if _sys_stat
271da2e3ebdSchin 					else	/* special case /dev/null */
272da2e3ebdSchin 					{	reg int	dev, ino;
273da2e3ebdSchin 						dev = (int)st.st_dev;
274da2e3ebdSchin 						ino = (int)st.st_ino;
275da2e3ebdSchin 						if(sysstatf(DEVNULL,&st) >= 0 &&
276da2e3ebdSchin 						   dev == (int)st.st_dev &&
277da2e3ebdSchin 						   ino == (int)st.st_ino)
278da2e3ebdSchin 							SFSETNULL(f);
279da2e3ebdSchin 					}
280da2e3ebdSchin #endif
281da2e3ebdSchin 					errno = oerrno;
282da2e3ebdSchin 				}
283da2e3ebdSchin 
284da2e3ebdSchin 				/* initialize side buffer for r+w unseekable streams */
285da2e3ebdSchin 				if(!f->proc && (f->bits&SF_BOTH) )
286da2e3ebdSchin 					(void)_sfpopen(f,-1,-1,1);
287da2e3ebdSchin 			}
288da2e3ebdSchin 		}
289da2e3ebdSchin 
290da2e3ebdSchin 		/* set page size, this is also the desired default buffer size */
291da2e3ebdSchin 		if(_Sfpage <= 0)
292da2e3ebdSchin 		{
293da2e3ebdSchin #if _lib_getpagesize
294da2e3ebdSchin 			if((_Sfpage = (size_t)getpagesize()) <= 0)
295da2e3ebdSchin #endif
296da2e3ebdSchin 				_Sfpage = SF_PAGE;
297da2e3ebdSchin 		}
298da2e3ebdSchin 	}
299da2e3ebdSchin 
300da2e3ebdSchin #ifdef MAP_TYPE
301da2e3ebdSchin 	if(okmmap && size && (f->mode&SF_READ) && f->extent >= 0 )
302da2e3ebdSchin 	{	/* see if we can try memory mapping */
303da2e3ebdSchin 		if(!disc)
304da2e3ebdSchin 			for(disc = f->disc; disc; disc = disc->disc)
305da2e3ebdSchin 				if(disc->readf)
306da2e3ebdSchin 					break;
307da2e3ebdSchin 		if(!disc)
308da2e3ebdSchin 		{	f->bits |= SF_MMAP;
309da2e3ebdSchin 			if(size == (size_t)SF_UNBOUND)
310da2e3ebdSchin 			{	if(bufsize > _Sfpage)
311da2e3ebdSchin 					size = bufsize * SF_NMAP;
312da2e3ebdSchin 				else	size = _Sfpage * SF_NMAP;
313da2e3ebdSchin 				if(size > 256*1024)
314da2e3ebdSchin 					size = 256*1024;
315da2e3ebdSchin 			}
316da2e3ebdSchin 		}
317da2e3ebdSchin 	}
318da2e3ebdSchin #endif
319da2e3ebdSchin 
320da2e3ebdSchin 	/* get buffer space */
321da2e3ebdSchin setbuf:
322da2e3ebdSchin 	if(size == (size_t)SF_UNBOUND)
323da2e3ebdSchin 	{	/* define a default size suitable for block transfer */
324da2e3ebdSchin 		if(init && osize > 0)
325da2e3ebdSchin 			size = osize;
326da2e3ebdSchin 		else if(f == sfstderr && (f->mode&SF_WRITE))
327da2e3ebdSchin 			size = 0;
328da2e3ebdSchin 		else if(f->flags&SF_STRING )
329da2e3ebdSchin 			size = SF_GRAIN;
330da2e3ebdSchin 		else if((f->flags&SF_READ) && !(f->bits&SF_BOTH) &&
331da2e3ebdSchin 			f->extent > 0 && f->extent < (Sfoff_t)_Sfpage )
332da2e3ebdSchin 			size = (((size_t)f->extent + SF_GRAIN-1)/SF_GRAIN)*SF_GRAIN;
333da2e3ebdSchin 		else if((ssize_t)(size = _Sfpage) < bufsize)
334da2e3ebdSchin 			size = bufsize;
335da2e3ebdSchin 
336da2e3ebdSchin 		buf = NIL(Void_t*);
337da2e3ebdSchin 	}
338da2e3ebdSchin 
339da2e3ebdSchin 	sf_malloc = 0;
340da2e3ebdSchin 	if(size > 0 && !buf && !(f->bits&SF_MMAP))
341da2e3ebdSchin 	{	/* try to allocate a buffer */
342da2e3ebdSchin 		if(obuf && size == (size_t)osize && init)
343da2e3ebdSchin 		{	buf = (Void_t*)obuf;
344da2e3ebdSchin 			obuf = NIL(uchar*);
345da2e3ebdSchin 			sf_malloc = (oflags&SF_MALLOC);
346da2e3ebdSchin 		}
347da2e3ebdSchin 		if(!buf)
348da2e3ebdSchin 		{	/* do allocation */
349da2e3ebdSchin 			while(!buf && size > 0)
350da2e3ebdSchin 			{	if((buf = (Void_t*)malloc(size)) )
351da2e3ebdSchin 					break;
352da2e3ebdSchin 				else	size /= 2;
353da2e3ebdSchin 			}
354da2e3ebdSchin 			if(size > 0)
355da2e3ebdSchin 				sf_malloc = SF_MALLOC;
356da2e3ebdSchin 		}
357da2e3ebdSchin 	}
358da2e3ebdSchin 
359da2e3ebdSchin 	if(size == 0 && !(f->flags&SF_STRING) && !(f->bits&SF_MMAP) && (f->mode&SF_READ))
360da2e3ebdSchin 	{	/* use the internal buffer */
361da2e3ebdSchin 		size = sizeof(f->tiny);
362da2e3ebdSchin 		buf = (Void_t*)f->tiny;
363da2e3ebdSchin 	}
364da2e3ebdSchin 
365da2e3ebdSchin 	/* set up new buffer */
366da2e3ebdSchin 	f->size = size;
367da2e3ebdSchin 	f->next = f->data = f->endr = f->endw = (uchar*)buf;
368da2e3ebdSchin 	f->endb = (f->mode&SF_READ) ? f->data : f->data+size;
369da2e3ebdSchin 	if(f->flags&SF_STRING)
370da2e3ebdSchin 	{	/* these fields are used to test actual size - see sfseek() */
371da2e3ebdSchin 		f->extent = (!sf_malloc &&
372da2e3ebdSchin 			     ((f->flags&SF_READ) || (f->bits&SF_BOTH)) ) ? size : 0;
373da2e3ebdSchin 		f->here = 0;
374da2e3ebdSchin 
375da2e3ebdSchin 		/* read+string stream should have all data available */
376da2e3ebdSchin 		if((f->mode&SF_READ) && !sf_malloc)
377da2e3ebdSchin 			f->endb = f->data+size;
378da2e3ebdSchin 	}
379da2e3ebdSchin 
380da2e3ebdSchin 	f->flags = (f->flags & ~SF_MALLOC)|sf_malloc;
381da2e3ebdSchin 
382da2e3ebdSchin 	if(obuf && obuf != f->data && osize > 0 && (oflags&SF_MALLOC))
383da2e3ebdSchin 	{	free((Void_t*)obuf);
384da2e3ebdSchin 		obuf = NIL(uchar*);
385da2e3ebdSchin 	}
386da2e3ebdSchin 
387da2e3ebdSchin done:
388da2e3ebdSchin 	_Sfi = f->val = obuf ? osize : 0;
389da2e3ebdSchin 
390da2e3ebdSchin 	/* blksz is used for aligning disk block boundary while reading data to
391da2e3ebdSchin 	** optimize data transfer from disk (eg, via direct I/O). blksz can be
392da2e3ebdSchin 	** at most f->size/2 so that data movement in buffer can be optimized.
393da2e3ebdSchin 	** blksz should also be a power-of-2 for optimal disk seeks.
394da2e3ebdSchin 	*/
395da2e3ebdSchin 	if(blksz <= 0 || (blksz & (blksz-1)) != 0 )
396da2e3ebdSchin 		blksz = SF_GRAIN;
397da2e3ebdSchin 	while(blksz > f->size/2)
398da2e3ebdSchin 		blksz /= 2;
399da2e3ebdSchin 	f->blksz = blksz;
400da2e3ebdSchin 
401da2e3ebdSchin 	SFOPEN(f,local);
402da2e3ebdSchin 
403da2e3ebdSchin 	SFMTXRETURN(f, (Void_t*)obuf);
404da2e3ebdSchin }
405