xref: /titanic_51/usr/src/lib/libast/common/sfio/sfreserve.c (revision ff17c8bf86c3e567734be83f90267edee20f580f)
1 /***********************************************************************
2 *                                                                      *
3 *               This software is part of the ast package               *
4 *           Copyright (c) 1985-2007 AT&T Knowledge Ventures            *
5 *                      and is licensed under the                       *
6 *                  Common Public License, Version 1.0                  *
7 *                      by AT&T Knowledge Ventures                      *
8 *                                                                      *
9 *                A copy of the License is available at                 *
10 *            http://www.opensource.org/licenses/cpl1.0.txt             *
11 *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
12 *                                                                      *
13 *              Information and Software Systems Research               *
14 *                            AT&T Research                             *
15 *                           Florham Park NJ                            *
16 *                                                                      *
17 *                 Glenn Fowler <gsf@research.att.com>                  *
18 *                  David Korn <dgk@research.att.com>                   *
19 *                   Phong Vo <kpv@research.att.com>                    *
20 *                                                                      *
21 ***********************************************************************/
22 #include	"sfhdr.h"
23 
24 /*	Reserve a segment of data or buffer.
25 **
26 **	Written by Kiem-Phong Vo.
27 */
28 
29 #if __STD_C
30 Void_t* sfreserve(reg Sfio_t* f, ssize_t size, int type)
31 #else
32 Void_t* sfreserve(f,size,type)
33 reg Sfio_t*	f;	/* file to peek */
34 ssize_t		size;	/* size of peek */
35 int		type;	/* LOCKR: lock stream, LASTR: last record */
36 #endif
37 {
38 	reg ssize_t	n, now, sz, iosz;
39 	reg Sfrsrv_t*	rsrv;
40 	reg Void_t*	data;
41 	reg int		mode, local;
42 
43 	SFMTXSTART(f,NIL(Void_t*));
44 
45 	sz = size < 0 ? -size : size;
46 
47 	/* see if we need to bias toward SF_WRITE instead of the default SF_READ */
48 	if(type < 0)
49 		mode = 0;
50 	else if((mode = type&SF_WRITE) )
51 		type &= ~SF_WRITE;
52 
53 	/* return the last record */
54 	if(type == SF_LASTR )
55 	{	if((n = f->endb - f->next) > 0 && n == f->val )
56 		{	data = (Void_t*)f->next;
57 			f->next += n;
58 		}
59 		else if((rsrv = f->rsrv) && (n = -rsrv->slen) > 0)
60 		{	rsrv->slen = 0;
61 			_Sfi = f->val = n;
62 			data = (Void_t*)rsrv->data;
63 		}
64 		else
65 		{	_Sfi = f->val = -1;
66 			data = NIL(Void_t*);
67 		}
68 
69 		SFMTXRETURN(f, data);
70 	}
71 
72 	if(type > 0)
73 	{	if(type == 1 ) /* upward compatibility mode */
74 			type = SF_LOCKR;
75 		else if(type != SF_LOCKR)
76 			SFMTXRETURN(f, NIL(Void_t*));
77 	}
78 
79 	if(size == 0 && (type < 0 || type == SF_LOCKR) )
80 	{	if((f->mode&SF_RDWR) != f->mode && _sfmode(f,0,0) < 0)
81 			SFMTXRETURN(f, NIL(Void_t*));
82 
83 		SFLOCK(f,0);
84 		if((n = f->endb - f->next) < 0)
85 			n = 0;
86 
87 		goto done;
88 	}
89 
90 	/* iterate until get to a stream that has data or buffer space */
91 	for(local = 0;; local = SF_LOCAL)
92 	{	_Sfi = f->val = -1;
93 
94 		if(!mode && !(mode = f->flags&SF_READ) )
95 			mode = SF_WRITE;
96 		if((int)f->mode != mode && _sfmode(f,mode,local) < 0)
97 		{	SFOPEN(f,0);
98 			SFMTXRETURN(f, NIL(Void_t*));
99 		}
100 
101 		SFLOCK(f,local);
102 
103 		if((n = now = f->endb - f->next) < 0)
104 			n = 0;
105 		if(n > 0 && n >= sz) /* all done */
106 			break;
107 
108 		/* amount to perform IO */
109 		if(size == 0 || (f->mode&SF_WRITE) )
110 			iosz = -1;
111 		else
112 		{	iosz = sz - n;
113 			if(type != SF_LOCKR && size < 0 && iosz < (f->size - n) )
114 				iosz = f->size - n;
115 			if(iosz <= 0)
116 				break;
117 		}
118 
119 		/* do a buffer refill or flush */
120 		now = n;
121 		if(f->mode&SF_WRITE)
122 			(void)SFFLSBUF(f, iosz);
123 		else if(type == SF_LOCKR && f->extent < 0 && (f->flags&SF_SHARE) )
124 		{	if(n == 0) /* peek-read only if there is no buffered data */
125 			{	f->mode |= SF_RV;
126 				(void)SFFILBUF(f, iosz );
127 			}
128 			if((n = f->endb - f->next) < sz)
129 			{	if(f->mode&SF_PKRD)
130 				{	f->endb = f->endr = f->next;
131 					f->mode &= ~SF_PKRD;
132 				}
133 				break;
134 			}
135 		}
136 		else	(void)SFFILBUF(f, iosz );
137 
138 		if((n = f->endb - f->next) <= 0)
139 			n = 0;
140 
141 		if(n >= sz) /* got it */
142 			break;
143 
144 		if(n == now || sferror(f) || sfeof(f)) /* no progress */
145 			break;
146 
147 		/* request was only to assess data availability */
148 		if(type == SF_LOCKR && size > 0 && n > 0 )
149 			break;
150 	}
151 
152 done:	/* compute the buffer to be returned */
153 	data = NIL(Void_t*);
154 	if(size == 0 || n == 0)
155 	{	if(n > 0) /* got data */
156 			data = (Void_t*)f->next;
157 		else if(type == SF_LOCKR && size == 0 && (rsrv = _sfrsrv(f,0)) )
158 			data = (Void_t*)rsrv->data;
159 	}
160 	else if(n >= sz) /* got data */
161 		data = (Void_t*)f->next;
162 	else if(f->flags&SF_STRING) /* try extending string buffer */
163 	{	if((f->mode&SF_WRITE) && (f->flags&SF_MALLOC) )
164 		{	(void)SFWR(f,f->next,sz,f->disc);
165 			if((n = f->endb - f->next) >= sz )
166 				data = (Void_t*)f->next;
167 		}
168 	}
169 	else if(f->mode&SF_WRITE) /* allocate side buffer */
170 	{	if(type == SF_LOCKR && (rsrv = _sfrsrv(f, sz)) )
171 			data = (Void_t*)rsrv->data;
172 	}
173 	else if(type != SF_LOCKR && sz > f->size && (rsrv = _sfrsrv(f,sz)) )
174 	{	if((n = SFREAD(f,(Void_t*)rsrv->data,sz)) >= sz) /* read side buffer */
175 			data = (Void_t*)rsrv->data;
176 		else	rsrv->slen = -n;
177 	}
178 
179 	SFOPEN(f,0);
180 
181 	if(data)
182 	{	if(type == SF_LOCKR)
183 		{	f->mode |= SF_PEEK;
184 			if((f->mode & SF_READ) && size == 0 && data != f->next)
185 				f->mode |= SF_GETR; /* so sfread() will unlock */
186 			f->endr = f->endw = f->data;
187 		}
188 		else
189 		{	if(data == (Void_t*)f->next)
190 				f->next += (size >= 0 ? size : n);
191 		}
192 	}
193 
194 	_Sfi = f->val = n; /* return true buffer size */
195 
196 	SFMTXRETURN(f, data);
197 }
198