source: trunk/libs/newlib/src/newlib/libc/stdio64/fseeko64.c @ 450

Last change on this file since 450 was 444, checked in by satin@…, 6 years ago

add newlib,libalmos-mkh, restructure shared_syscalls.h and mini-libc

File size: 8.6 KB
Line 
1/*
2 * Copyright (c) 1990 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms are permitted
6 * provided that the above copyright notice and this paragraph are
7 * duplicated in all such forms and that any documentation,
8 * advertising materials, and other materials related to such
9 * distribution and use acknowledge that the software was developed
10 * by the University of California, Berkeley.  The name of the
11 * University may not be used to endorse or promote products derived
12 * from this software without specific prior written permission.
13 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16 */
17
18/*
19FUNCTION
20<<fseeko64>>---set file position for large file
21
22INDEX
23        fseeko64
24INDEX
25        _fseeko64_r
26
27SYNOPSIS
28        #include <stdio.h>
29        int fseeko64(FILE *<[fp]>, _off64_t <[offset]>, int <[whence]>);
30        int _fseeko64_r (struct _reent *<[ptr]>, FILE *<[fp]>,
31                         _off64_t <[offset]>, int <[whence]>);
32
33DESCRIPTION
34Objects of type <<FILE>> can have a ``position'' that records how much
35of the file your program has already read.  Many of the <<stdio>> functions
36depend on this position, and many change it as a side effect.
37
38You can use <<fseeko64>> to set the position for the file identified by
39<[fp]> that was opened via <<fopen64>>.  The value of <[offset]> determines
40the new position, in one of three ways selected by the value of <[whence]>
41(defined as macros in `<<stdio.h>>'):
42
43<<SEEK_SET>>---<[offset]> is the absolute file position (an offset
44from the beginning of the file) desired.  <[offset]> must be positive.
45
46<<SEEK_CUR>>---<[offset]> is relative to the current file position.
47<[offset]> can meaningfully be either positive or negative.
48
49<<SEEK_END>>---<[offset]> is relative to the current end of file.
50<[offset]> can meaningfully be either positive (to increase the size
51of the file) or negative.
52
53See <<ftello64>> to determine the current file position.
54
55RETURNS
56<<fseeko64>> returns <<0>> when successful.  On failure, the
57result is <<EOF>>.  The reason for failure is indicated in <<errno>>:
58either <<ESPIPE>> (the stream identified by <[fp]> doesn't support
59repositioning or wasn't opened via <<fopen64>>) or <<EINVAL>>
60(invalid file position).
61
62PORTABILITY
63<<fseeko64>> is a glibc extension.
64
65Supporting OS subroutines required: <<close>>, <<fstat64>>, <<isatty>>,
66<<lseek64>>, <<read>>, <<sbrk>>, <<write>>.
67*/
68
69#include <stdio.h>
70#include <time.h>
71#include <fcntl.h>
72#include <stdlib.h>
73#include <errno.h>
74#include <sys/types.h>
75#include <sys/stat.h>
76#include "local.h"
77
78#define POS_ERR (-(_fpos64_t)1)
79
80#ifdef __LARGE64_FILES
81
82/*
83 * Seek the given file to the given offset.
84 * `Whence' must be one of the three SEEK_* macros.
85 */
86
87_off64_t
88_fseeko64_r (struct _reent *ptr,
89     register FILE *fp,
90     _off64_t offset,
91     int whence)
92{
93  _fpos64_t (*seekfn) (struct _reent *, void *, _fpos64_t, int);
94  _fpos64_t target, curoff;
95  size_t n;
96
97  struct stat64 st;
98  int havepos;
99
100  /* Only do 64-bit seek on large file.  */
101  if (!(fp->_flags & __SL64))
102    {
103      if ((_off_t) offset != offset)
104        {
105          ptr->_errno = EOVERFLOW;
106          return EOF;
107        }
108      return (_off64_t) _fseeko_r (ptr, fp, offset, whence);
109    }
110
111  /* Make sure stdio is set up.  */
112
113  CHECK_INIT (ptr, fp);
114
115  _newlib_flockfile_start (fp);
116
117  curoff = fp->_offset;
118
119  /* If we've been doing some writing, and we're in append mode
120     then we don't really know where the filepos is.  */
121
122  if (fp->_flags & __SAPP && fp->_flags & __SWR)
123    {
124      /* So flush the buffer and seek to the end.  */
125      _fflush_r (ptr, fp);
126    }
127
128  /* Have to be able to seek.  */
129
130  if ((seekfn = fp->_seek64) == NULL)
131    {
132      ptr->_errno = ESPIPE;     /* ??? */
133      _newlib_flockfile_exit(fp);
134      return EOF;
135    }
136
137  /*
138   * Change any SEEK_CUR to SEEK_SET, and check `whence' argument.
139   * After this, whence is either SEEK_SET or SEEK_END.
140   */
141
142  switch (whence)
143    {
144    case SEEK_CUR:
145      /*
146       * In order to seek relative to the current stream offset,
147       * we have to first find the current stream offset a la
148       * ftell (see ftell for details).
149       */
150      _fflush_r (ptr, fp);   /* may adjust seek offset on append stream */
151      if (fp->_flags & __SOFF)
152        curoff = fp->_offset;
153      else
154        {
155          curoff = seekfn (ptr, fp->_cookie, (_fpos64_t) 0, SEEK_CUR);
156          if (curoff == -1L)
157            {
158              _newlib_flockfile_exit(fp);
159              return EOF;
160            }
161        }
162      if (fp->_flags & __SRD)
163        {
164          curoff -= fp->_r;
165          if (HASUB (fp))
166            curoff -= fp->_ur;
167        }
168      else if (fp->_flags & __SWR && fp->_p != NULL)
169        curoff += fp->_p - fp->_bf._base;
170
171      offset += curoff;
172      whence = SEEK_SET;
173      havepos = 1;
174      break;
175
176    case SEEK_SET:
177    case SEEK_END:
178      havepos = 0;
179      break;
180
181    default:
182      ptr->_errno = EINVAL;
183      _newlib_flockfile_exit(fp);
184      return (EOF);
185    }
186
187  /*
188   * Can only optimise if:
189   *    reading (and not reading-and-writing);
190   *    not unbuffered; and
191   *    this is a `regular' Unix file (and hence seekfn==__sseek).
192   * We must check __NBF first, because it is possible to have __NBF
193   * and __SOPT both set.
194   */
195
196  if (fp->_bf._base == NULL)
197    __smakebuf_r (ptr, fp);
198
199#if _FSEEK_OPTIMIZATION
200  if (fp->_flags & (__SWR | __SRW | __SNBF | __SNPT))
201    goto dumb;
202  if ((fp->_flags & __SOPT) == 0)
203    {
204      if (seekfn != __sseek64
205          || fp->_file < 0
206          || _fstat64_r (ptr, fp->_file, &st)
207          || (st.st_mode & S_IFMT) != S_IFREG)
208        {
209          fp->_flags |= __SNPT;
210          goto dumb;
211        }
212#ifdef  HAVE_BLKSIZE
213      fp->_blksize = st.st_blksize;
214#else
215      fp->_blksize = 1024;
216#endif
217      fp->_flags |= __SOPT;
218    }
219
220  /*
221   * We are reading; we can try to optimise.
222   * Figure out where we are going and where we are now.
223   */
224
225  if (whence == SEEK_SET)
226    target = offset;
227  else
228    {
229      if (_fstat64_r (ptr, fp->_file, &st))
230        goto dumb;
231      target = st.st_size + offset;
232    }
233
234  if (!havepos)
235    {
236      if (fp->_flags & __SOFF)
237        curoff = fp->_offset;
238      else
239        {
240          curoff = seekfn (ptr, fp->_cookie, (_fpos64_t)0, SEEK_CUR);
241          if (curoff == POS_ERR)
242            goto dumb;
243        }
244      curoff -= fp->_r;
245      if (HASUB (fp))
246        curoff -= fp->_ur;
247    }
248
249  /*
250   * Compute the number of bytes in the input buffer (pretending
251   * that any ungetc() input has been discarded).  Adjust current
252   * offset backwards by this count so that it represents the
253   * file offset for the first byte in the current input buffer.
254   */
255
256  if (HASUB (fp))
257    {
258      curoff += fp->_r;       /* kill off ungetc */
259      n = fp->_up - fp->_bf._base;
260      curoff -= n;
261      n += fp->_ur;
262    }
263  else
264    {
265      n = fp->_p - fp->_bf._base;
266      curoff -= n;
267      n += fp->_r;
268    }
269
270  /*
271   * If the target offset is within the current buffer,
272   * simply adjust the pointers, clear EOF, undo ungetc(),
273   * and return.
274   */
275
276  if (target >= curoff && target < curoff + n)
277    {
278      register int o = target - curoff;
279
280      fp->_p = fp->_bf._base + o;
281      fp->_r = n - o;
282      if (HASUB (fp))
283        FREEUB (ptr, fp);
284      fp->_flags &= ~__SEOF;
285      _newlib_flockfile_exit(fp);
286      return 0;
287    }
288
289  /*
290   * The place we want to get to is not within the current buffer,
291   * but we can still be kind to the kernel copyout mechanism.
292   * By aligning the file offset to a block boundary, we can let
293   * the kernel use the VM hardware to map pages instead of
294   * copying bytes laboriously.  Using a block boundary also
295   * ensures that we only read one block, rather than two.
296   */
297
298  curoff = target & ~((_fpos64_t)(fp->_blksize - 1));
299  if (seekfn (ptr, fp->_cookie, curoff, SEEK_SET) == POS_ERR)
300    goto dumb;
301  fp->_r = 0;
302  fp->_p = fp->_bf._base;
303  if (HASUB (fp))
304    FREEUB (ptr, fp);
305  fp->_flags &= ~__SEOF;
306  n = target - curoff;
307  if (n)
308    {
309      if (__srefill_r (ptr, fp) || fp->_r < n)
310        goto dumb;
311      fp->_p += n;
312      fp->_r -= n;
313    }
314  _newlib_flockfile_end(fp);
315  return 0;
316
317  /*
318   * We get here if we cannot optimise the seek ... just
319   * do it.  Allow the seek function to change fp->_bf._base.
320   */
321#endif
322
323dumb:
324  if (_fflush_r (ptr, fp)
325      || seekfn (ptr, fp->_cookie, offset, whence) == POS_ERR)
326    {
327      _funlockfile(fp);
328      return EOF;
329    }
330  /* success: clear EOF indicator and discard ungetc() data */
331  if (HASUB (fp))
332    FREEUB (ptr, fp);
333  fp->_p = fp->_bf._base;
334  fp->_r = 0;
335  /* fp->_w = 0; *//* unnecessary (I think...) */
336  fp->_flags &= ~__SEOF;
337  _funlockfile(fp);
338  return 0;
339}
340
341#ifndef _REENT_ONLY
342
343_off64_t
344fseeko64 (register FILE *fp,
345     _off64_t offset,
346     int whence)
347{
348  return _fseeko64_r (_REENT, fp, offset, whence);
349}
350
351#endif /* !_REENT_ONLY */
352
353#endif /* __LARGE64_FILES */
Note: See TracBrowser for help on using the repository browser.