1 /***********************************************************************
2 * *
3 * This software is part of the ast package *
4 * Copyright (c) 1985-2010 AT&T Intellectual Property *
5 * and is licensed under the *
6 * Common Public License, Version 1.0 *
7 * by AT&T Intellectual Property *
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 /* Internal function to do a hard read.
25 ** This knows about discipline and memory mapping, peek read.
26 **
27 ** Written by Kiem-Phong Vo.
28 */
29
30 /* synchronize unseekable write streams */
31 #if __STD_C
_sfwrsync(void)32 static void _sfwrsync(void)
33 #else
34 static void _sfwrsync()
35 #endif
36 { reg Sfpool_t* p;
37 reg Sfio_t* f;
38 reg int n;
39
40 /* sync all pool heads */
41 for(p = _Sfpool.next; p; p = p->next)
42 { if(p->n_sf <= 0)
43 continue;
44 f = p->sf[0];
45 if(!SFFROZEN(f) && f->next > f->data &&
46 (f->mode&SF_WRITE) && f->extent < 0 )
47 (void)_sfflsbuf(f,-1);
48 }
49
50 /* and all the ones in the discrete pool */
51 for(n = 0; n < _Sfpool.n_sf; ++n)
52 { f = _Sfpool.sf[n];
53
54 if(!SFFROZEN(f) && f->next > f->data &&
55 (f->mode&SF_WRITE) && f->extent < 0 )
56 (void)_sfflsbuf(f,-1);
57 }
58 }
59
60 #if __STD_C
sfrd(Sfio_t * f,Void_t * buf,size_t n,Sfdisc_t * disc)61 ssize_t sfrd(Sfio_t* f, Void_t* buf, size_t n, Sfdisc_t* disc)
62 #else
63 ssize_t sfrd(f,buf,n,disc)
64 Sfio_t* f;
65 Void_t* buf;
66 size_t n;
67 Sfdisc_t* disc;
68 #endif
69 {
70 Sfoff_t r;
71 reg Sfdisc_t* dc;
72 reg int local, rcrv, dosync, oerrno;
73 SFMTXDECL(f);
74
75 SFMTXENTER(f,-1);
76
77 GETLOCAL(f,local);
78 if((rcrv = f->mode & (SF_RC|SF_RV)) )
79 f->mode &= ~(SF_RC|SF_RV);
80 f->bits &= ~SF_JUSTSEEK;
81
82 if(f->mode&SF_PKRD)
83 SFMTXRETURN(f, -1);
84
85 if(!local && !(f->bits&SF_DCDOWN)) /* an external user's call */
86 { if(f->mode != SF_READ && _sfmode(f,SF_READ,0) < 0)
87 SFMTXRETURN(f, -1);
88 if(f->next < f->endb)
89 { if(SFSYNC(f) < 0)
90 SFMTXRETURN(f, -1);
91 if((f->mode&(SF_SYNCED|SF_READ)) == (SF_SYNCED|SF_READ) )
92 { f->endb = f->next = f->endr = f->data;
93 f->mode &= ~SF_SYNCED;
94 }
95 #ifdef MAP_TYPE
96 if((f->bits&SF_MMAP) && f->data)
97 { SFMUNMAP(f, f->data, f->endb-f->data);
98 f->data = NIL(uchar*);
99 }
100 #endif
101 f->next = f->endb = f->endr = f->endw = f->data;
102 }
103 }
104
105 for(dosync = 0;;)
106 { /* stream locked by sfsetfd() */
107 if(!(f->flags&SF_STRING) && f->file < 0)
108 SFMTXRETURN(f, 0);
109
110 f->flags &= ~(SF_EOF|SF_ERROR);
111
112 dc = disc;
113 if(f->flags&SF_STRING)
114 { if((r = (f->data+f->extent) - f->next) < 0)
115 r = 0;
116 if(r <= 0)
117 goto do_except;
118 SFMTXRETURN(f, (ssize_t)r);
119 }
120
121 /* warn that a read is about to happen */
122 SFDISC(f,dc,readf);
123 if(dc && dc->exceptf && (f->flags&SF_IOCHECK) )
124 { reg int rv;
125 if(local)
126 SETLOCAL(f);
127 if((rv = _sfexcept(f,SF_READ,n,dc)) > 0)
128 n = rv;
129 else if(rv < 0)
130 { f->flags |= SF_ERROR;
131 SFMTXRETURN(f, (ssize_t)rv);
132 }
133 }
134
135 #ifdef MAP_TYPE
136 if(f->bits&SF_MMAP)
137 { reg ssize_t a, round;
138 sfstat_t st;
139
140 /* determine if we have to copy data to buffer */
141 if((uchar*)buf >= f->data && (uchar*)buf <= f->endb)
142 { n += f->endb - f->next;
143 buf = NIL(char*);
144 }
145
146 /* actual seek location */
147 if((f->flags&(SF_SHARE|SF_PUBLIC)) == (SF_SHARE|SF_PUBLIC) &&
148 (r = SFSK(f,(Sfoff_t)0,SEEK_CUR,dc)) != f->here)
149 f->here = r;
150 else f->here -= f->endb-f->next;
151
152 /* before mapping, make sure we have data to map */
153 if((f->flags&SF_SHARE) || (size_t)(r = f->extent-f->here) < n)
154 { if((r = sysfstatf(f->file,&st)) < 0)
155 goto do_except;
156 if((r = (f->extent = st.st_size) - f->here) <= 0 )
157 { r = 0; /* eof */
158 goto do_except;
159 }
160 }
161
162 /* make sure current position is page aligned */
163 if((a = (size_t)(f->here%_Sfpage)) != 0)
164 { f->here -= a;
165 r += a;
166 }
167
168 /* map minimal requirement */
169 if(r > (round = (1 + (n+a)/f->size)*f->size) )
170 r = round;
171
172 if(f->data)
173 SFMUNMAP(f, f->data, f->endb-f->data);
174
175 for(;;)
176 { f->data = (uchar*) sysmmapf((caddr_t)0, (size_t)r,
177 (PROT_READ|PROT_WRITE),
178 MAP_PRIVATE,
179 f->file, (sfoff_t)f->here);
180 if(f->data && (caddr_t)f->data != (caddr_t)(-1))
181 break;
182 else
183 { f->data = NIL(uchar*);
184 if((r >>= 1) < (_Sfpage*SF_NMAP) ||
185 (errno != EAGAIN && errno != ENOMEM) )
186 break;
187 }
188 }
189
190 if(f->data)
191 { if(f->bits&SF_SEQUENTIAL)
192 SFMMSEQON(f,f->data,r);
193 f->next = f->data+a;
194 f->endr = f->endb = f->data+r;
195 f->endw = f->data;
196 f->here += r;
197
198 /* make known our seek location */
199 (void)SFSK(f,f->here,SEEK_SET,dc);
200
201 if(buf)
202 { if(n > (size_t)(r-a))
203 n = (ssize_t)(r-a);
204 memcpy(buf,f->next,n);
205 f->next += n;
206 }
207 else n = f->endb - f->next;
208
209 SFMTXRETURN(f, n);
210 }
211 else
212 { r = -1;
213 f->here += a;
214
215 /* reset seek pointer to its physical location */
216 (void)SFSK(f,f->here,SEEK_SET,dc);
217
218 /* make a buffer */
219 (void)SFSETBUF(f,(Void_t*)f->tiny,(size_t)SF_UNBOUND);
220
221 if(!buf)
222 { buf = (Void_t*)f->data;
223 n = f->size;
224 }
225 }
226 }
227 #endif
228
229 /* sync unseekable write streams to prevent deadlock */
230 if(!dosync && f->extent < 0)
231 { dosync = 1;
232 _sfwrsync();
233 }
234
235 /* make sure file pointer is right */
236 if(f->extent >= 0 && (f->flags&SF_SHARE) )
237 { if(!(f->flags&SF_PUBLIC) )
238 f->here = SFSK(f,f->here,SEEK_SET,dc);
239 else f->here = SFSK(f,(Sfoff_t)0,SEEK_CUR,dc);
240 }
241
242 oerrno = errno;
243 errno = 0;
244
245 if(dc && dc->readf)
246 { int share = f->flags&SF_SHARE;
247
248 if(rcrv) /* pass on rcrv for possible continuations */
249 f->mode |= rcrv;
250 /* tell readf that no peeking necessary */
251 else f->flags &= ~SF_SHARE;
252
253 SFDCRD(f,buf,n,dc,r);
254
255 /* reset flags */
256 if(rcrv)
257 f->mode &= ~rcrv;
258 else f->flags |= share;
259 }
260 else if(SFISNULL(f))
261 r = 0;
262 else if(f->extent < 0 && (f->flags&SF_SHARE) && rcrv)
263 { /* try peek read */
264 r = sfpkrd(f->file, (char*)buf, n,
265 (rcrv&SF_RC) ? (int)f->getr : -1,
266 -1L, (rcrv&SF_RV) ? 1 : 0);
267 if(r > 0)
268 { if(rcrv&SF_RV)
269 f->mode |= SF_PKRD;
270 else f->mode |= SF_RC;
271 }
272 }
273 else r = sysreadf(f->file,buf,n);
274
275 if(errno == 0 )
276 errno = oerrno;
277
278 if(r > 0 )
279 { if(!(f->bits&SF_DCDOWN) ) /* not a continuation call */
280 { if(!(f->mode&SF_PKRD) )
281 { f->here += r;
282 if(f->extent >= 0 && f->extent < f->here)
283 f->extent = f->here;
284 }
285 if((uchar*)buf >= f->data &&
286 (uchar*)buf < f->data+f->size)
287 f->endb = f->endr = ((uchar*)buf) + r;
288 }
289
290 SFMTXRETURN(f, (ssize_t)r);
291 }
292
293 do_except:
294 if(local)
295 SETLOCAL(f);
296 switch(_sfexcept(f,SF_READ,(ssize_t)r,dc))
297 {
298 case SF_ECONT :
299 goto do_continue;
300 case SF_EDONE :
301 n = local ? 0 : (ssize_t)r;
302 SFMTXRETURN(f,n);
303 case SF_EDISC :
304 if(!local && !(f->flags&SF_STRING))
305 goto do_continue;
306 /* else fall thru */
307 case SF_ESTACK :
308 SFMTXRETURN(f, -1);
309 }
310
311 do_continue:
312 for(dc = f->disc; dc; dc = dc->disc)
313 if(dc == disc)
314 break;
315 disc = dc;
316 }
317 }
318