Rev 4874 | Go to most recent revision | Show entire file | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 4874 | Rev 4921 | ||
---|---|---|---|
Line 99... | Line 99... | ||
99 | */ |
99 | */ |
Line 100... | Line 100... | ||
100 | 100 | ||
101 | #include <_ansi.h> |
101 | #include <_ansi.h> |
102 | #include |
102 | #include |
103 | #include |
- | |
104 | #include |
- | |
105 | #include |
- | |
106 | #include |
- | |
107 | #include |
103 | #include |
108 | #include |
- | |
109 | #include |
104 | #include |
Line 110... | Line -... | ||
110 | #include "local.h" |
- | |
111 | - | ||
112 | #define POS_ERR (-(_fpos_t)1) |
- | |
113 | - | ||
114 | /* |
- | |
115 | * Seek the given file to the given offset. |
- | |
116 | * `Whence' must be one of the three SEEK_* macros. |
- | |
117 | */ |
105 | #include "local.h" |
118 | 106 | ||
119 | int |
107 | int |
120 | _DEFUN(_fseek_r, (ptr, fp, offset, whence), |
108 | _DEFUN(_fseek_r, (ptr, fp, offset, whence), |
121 | struct _reent *ptr _AND |
109 | struct _reent *ptr _AND |
122 | register FILE *fp _AND |
110 | register FILE *fp _AND |
123 | long offset _AND |
111 | long offset _AND |
124 | int whence) |
- | |
125 | { |
- | |
126 | _fpos_t _EXFNPTR(seekfn, (struct _reent *, _PTR, _fpos_t, int)); |
- | |
127 | _fpos_t target; |
- | |
128 | _fpos_t curoff = 0; |
- | |
129 | size_t n; |
- | |
130 | #ifdef __USE_INTERNAL_STAT64 |
- | |
131 | struct stat64 st; |
- | |
132 | #else |
- | |
133 | struct stat st; |
- | |
134 | #endif |
- | |
135 | int havepos; |
- | |
136 | - | ||
137 | /* Make sure stdio is set up. */ |
- | |
138 | - | ||
139 | CHECK_INIT (ptr, fp); |
- | |
140 | - | ||
141 | _flockfile (fp); |
- | |
142 | - | ||
143 | /* If we've been doing some writing, and we're in append mode |
- | |
144 | then we don't really know where the filepos is. */ |
- | |
145 | - | ||
146 | if (fp->_flags & __SAPP && fp->_flags & __SWR) |
- | |
147 | { |
- | |
148 | /* So flush the buffer and seek to the end. */ |
- | |
149 | _fflush_r (ptr, fp); |
- | |
150 | } |
- | |
151 | - | ||
152 | /* Have to be able to seek. */ |
- | |
153 | - | ||
154 | if ((seekfn = fp->_seek) == NULL) |
- | |
155 | { |
- | |
156 | ptr->_errno = ESPIPE; /* ??? */ |
- | |
157 | _funlockfile (fp); |
- | |
158 | return EOF; |
- | |
159 | } |
- | |
160 | - | ||
161 | /* |
- | |
162 | * Change any SEEK_CUR to SEEK_SET, and check `whence' argument. |
- | |
163 | * After this, whence is either SEEK_SET or SEEK_END. |
- | |
164 | */ |
- | |
165 | - | ||
166 | switch (whence) |
- | |
167 | { |
- | |
168 | case SEEK_CUR: |
- | |
169 | /* |
- | |
170 | * In order to seek relative to the current stream offset, |
- | |
171 | * we have to first find the current stream offset a la |
- | |
172 | * ftell (see ftell for details). |
- | |
173 | */ |
- | |
174 | _fflush_r (ptr, fp); /* may adjust seek offset on append stream */ |
- | |
175 | if (fp->_flags & __SOFF) |
- | |
176 | curoff = fp->_offset; |
- | |
177 | else |
- | |
178 | { |
- | |
179 | curoff = seekfn (ptr, fp->_cookie, (_fpos_t) 0, SEEK_CUR); |
- | |
180 | if (curoff == -1L) |
- | |
181 | { |
- | |
182 | _funlockfile (fp); |
- | |
183 | return EOF; |
- | |
184 | } |
- | |
185 | } |
- | |
186 | if (fp->_flags & __SRD) |
- | |
187 | { |
- | |
188 | curoff -= fp->_r; |
- | |
189 | if (HASUB (fp)) |
- | |
190 | curoff -= fp->_ur; |
- | |
191 | } |
- | |
192 | else if (fp->_flags & __SWR && fp->_p != NULL) |
- | |
193 | curoff += fp->_p - fp->_bf._base; |
- | |
194 | - | ||
195 | offset += curoff; |
- | |
196 | whence = SEEK_SET; |
- | |
197 | havepos = 1; |
- | |
198 | break; |
- | |
199 | - | ||
200 | case SEEK_SET: |
- | |
201 | case SEEK_END: |
- | |
202 | havepos = 0; |
- | |
203 | break; |
- | |
204 | - | ||
205 | default: |
- | |
206 | ptr->_errno = EINVAL; |
- | |
207 | _funlockfile (fp); |
- | |
208 | return (EOF); |
- | |
209 | } |
- | |
210 | - | ||
211 | /* |
- | |
212 | * Can only optimise if: |
- | |
213 | * reading (and not reading-and-writing); |
- | |
214 | * not unbuffered; and |
- | |
215 | * this is a `regular' Unix file (and hence seekfn==__sseek). |
- | |
216 | * We must check __NBF first, because it is possible to have __NBF |
- | |
217 | * and __SOPT both set. |
- | |
218 | */ |
- | |
219 | - | ||
220 | if (fp->_bf._base == NULL) |
- | |
221 | __smakebuf_r (ptr, fp); |
- | |
222 | if (fp->_flags & (__SWR | __SRW | __SNBF | __SNPT)) |
- | |
223 | goto dumb; |
- | |
224 | if ((fp->_flags & __SOPT) == 0) |
- | |
225 | { |
- | |
226 | if (seekfn != __sseek |
- | |
227 | || fp->_file < 0 |
- | |
228 | #ifdef __USE_INTERNAL_STAT64 |
- | |
229 | || _fstat64_r (ptr, fp->_file, &st) |
- | |
230 | #else |
- | |
231 | || _fstat_r (ptr, fp->_file, &st) |
- | |
232 | #endif |
- | |
233 | || (st.st_mode & S_IFMT) != S_IFREG) |
- | |
234 | { |
- | |
235 | fp->_flags |= __SNPT; |
- | |
236 | goto dumb; |
- | |
237 | } |
- | |
238 | #ifdef HAVE_BLKSIZE |
- | |
239 | fp->_blksize = st.st_blksize; |
- | |
240 | #else |
- | |
241 | fp->_blksize = 1024; |
- | |
242 | #endif |
- | |
243 | fp->_flags |= __SOPT; |
- | |
244 | } |
- | |
245 | - | ||
246 | /* |
- | |
247 | * We are reading; we can try to optimise. |
- | |
248 | * Figure out where we are going and where we are now. |
- | |
249 | */ |
- | |
250 | - | ||
251 | if (whence == SEEK_SET) |
- | |
252 | target = offset; |
- | |
253 | else |
- | |
254 | { |
- | |
255 | #ifdef __USE_INTERNAL_STAT64 |
- | |
256 | if (_fstat64_r (ptr, fp->_file, &st)) |
112 | int whence) |
257 | #else |
- | |
258 | if (_fstat_r (ptr, fp->_file, &st)) |
- | |
259 | #endif |
- | |
260 | goto dumb; |
- | |
261 | target = st.st_size + offset; |
- | |
262 | } |
- | |
263 | if ((long)target != target) |
- | |
264 | { |
- | |
265 | ptr->_errno = EOVERFLOW; |
- | |
266 | _funlockfile (fp); |
- | |
267 | return EOF; |
- | |
268 | } |
- | |
269 | - | ||
270 | if (!havepos) |
- | |
271 | { |
- | |
272 | if (fp->_flags & __SOFF) |
- | |
273 | curoff = fp->_offset; |
- | |
274 | else |
- | |
275 | { |
- | |
276 | curoff = seekfn (ptr, fp->_cookie, 0L, SEEK_CUR); |
- | |
277 | if (curoff == POS_ERR) |
- | |
278 | goto dumb; |
- | |
279 | } |
- | |
280 | curoff -= fp->_r; |
- | |
281 | if (HASUB (fp)) |
- | |
282 | curoff -= fp->_ur; |
- | |
283 | } |
- | |
284 | - | ||
285 | /* |
- | |
286 | * Compute the number of bytes in the input buffer (pretending |
- | |
287 | * that any ungetc() input has been discarded). Adjust current |
- | |
288 | * offset backwards by this count so that it represents the |
- | |
289 | * file offset for the first byte in the current input buffer. |
- | |
290 | */ |
- | |
291 | - | ||
292 | if (HASUB (fp)) |
- | |
293 | { |
- | |
294 | curoff += fp->_r; /* kill off ungetc */ |
- | |
295 | n = fp->_up - fp->_bf._base; |
- | |
296 | curoff -= n; |
- | |
297 | n += fp->_ur; |
- | |
298 | } |
- | |
299 | else |
- | |
300 | { |
- | |
301 | n = fp->_p - fp->_bf._base; |
- | |
302 | curoff -= n; |
- | |
303 | n += fp->_r; |
- | |
304 | } |
- | |
305 | - | ||
306 | /* |
- | |
307 | * If the target offset is within the current buffer, |
- | |
308 | * simply adjust the pointers, clear EOF, undo ungetc(), |
- | |
309 | * and return. |
- | |
310 | */ |
- | |
311 | - | ||
312 | if (target >= curoff && target < curoff + n) |
- | |
313 | { |
- | |
314 | register int o = target - curoff; |
- | |
315 | - | ||
316 | fp->_p = fp->_bf._base + o; |
- | |
317 | fp->_r = n - o; |
- | |
318 | if (HASUB (fp)) |
- | |
319 | FREEUB (ptr, fp); |
- | |
320 | fp->_flags &= ~__SEOF; |
- | |
321 | memset (&fp->_mbstate, 0, sizeof (_mbstate_t)); |
- | |
322 | _funlockfile (fp); |
- | |
323 | return 0; |
- | |
324 | } |
- | |
325 | - | ||
326 | /* |
- | |
327 | * The place we want to get to is not within the current buffer, |
- | |
328 | * but we can still be kind to the kernel copyout mechanism. |
- | |
329 | * By aligning the file offset to a block boundary, we can let |
- | |
330 | * the kernel use the VM hardware to map pages instead of |
- | |
331 | * copying bytes laboriously. Using a block boundary also |
- | |
332 | * ensures that we only read one block, rather than two. |
- | |
333 | */ |
- | |
334 | - | ||
335 | curoff = target & ~(fp->_blksize - 1); |
- | |
336 | if (seekfn (ptr, fp->_cookie, curoff, SEEK_SET) == POS_ERR) |
- | |
337 | goto dumb; |
- | |
338 | fp->_r = 0; |
- | |
339 | fp->_p = fp->_bf._base; |
- | |
340 | if (HASUB (fp)) |
- | |
341 | FREEUB (ptr, fp); |
- | |
342 | fp->_flags &= ~__SEOF; |
- | |
343 | n = target - curoff; |
- | |
344 | if (n) |
- | |
345 | { |
- | |
346 | if (__srefill_r (ptr, fp) || fp->_r < n) |
- | |
347 | goto dumb; |
- | |
348 | fp->_p += n; |
- | |
349 | fp->_r -= n; |
- | |
350 | } |
- | |
351 | memset (&fp->_mbstate, 0, sizeof (_mbstate_t)); |
- | |
352 | _funlockfile (fp); |
- | |
353 | return 0; |
- | |
354 | - | ||
355 | /* |
- | |
356 | * We get here if we cannot optimise the seek ... just |
- | |
357 | * do it. Allow the seek function to change fp->_bf._base. |
- | |
358 | */ |
- | |
359 | - | ||
360 | dumb: |
- | |
361 | if (_fflush_r (ptr, fp) |
- | |
362 | || seekfn (ptr, fp->_cookie, offset, whence) == POS_ERR) |
- | |
363 | { |
- | |
364 | _funlockfile (fp); |
- | |
365 | return EOF; |
- | |
366 | } |
- | |
367 | /* success: clear EOF indicator and discard ungetc() data */ |
- | |
368 | if (HASUB (fp)) |
- | |
369 | FREEUB (ptr, fp); |
- | |
370 | fp->_p = fp->_bf._base; |
- | |
371 | fp->_r = 0; |
- | |
372 | /* fp->_w = 0; *//* unnecessary (I think...) */ |
- | |
373 | fp->_flags &= ~__SEOF; |
- | |
374 | /* Reset no-optimization flag after successful seek. The |
- | |
375 | no-optimization flag may be set in the case of a read |
- | |
376 | stream that is flushed which by POSIX/SUSv3 standards, |
- | |
377 | means that a corresponding seek must not optimize. The |
- | |
378 | optimization is then allowed if no subsequent flush |
- | |
379 | is performed. */ |
- | |
380 | fp->_flags &= ~__SNPT; |
- | |
381 | memset (&fp->_mbstate, 0, sizeof (_mbstate_t)); |
- | |
382 | _funlockfile (fp); |
113 | { |
Line 383... | Line 114... | ||
383 | return 0; |
114 | return _fseeko_r (ptr, fp, offset, whence); |
Line 384... | Line 115... | ||
384 | } |
115 | } |