arch/m68k-amiga: Define the gcc symbol 'start' instead of using .bss
[AROS.git] / compiler / clib / lseek.c
blob029232c8c8fac5aa81701f9c58c525c1ffd73a9f
1 /*
2 Copyright © 1995-2003, The AROS Development Team. All rights reserved.
3 $Id$
5 Reposition read/write file offset.
6 */
7 #include <errno.h>
8 #include <dos/dos.h>
9 #include <proto/dos.h>
10 #include <exec/exec.h>
11 #include <proto/exec.h>
12 #include <clib/macros.h>
13 #include "__errno.h"
14 #include "__fdesc.h"
16 /*****************************************************************************
18 NAME */
19 #include <unistd.h>
21 off_t lseek (
23 /* SYNOPSIS */
24 int filedes,
25 off_t offset,
26 int whence)
28 /* FUNCTION
29 Reposition read/write file offset
31 INPUTS
32 filedef - the filedescriptor being modified
33 offset, whence -
34 How to modify the current position. whence
35 can be SEEK_SET, then offset is the absolute position
36 in the file (0 is the first byte), SEEK_CUR then the
37 position will change by offset (ie. -5 means to move
38 5 bytes to the beginning of the file) or SEEK_END.
39 SEEK_END means that the offset is relative to the
40 end of the file (-1 is the last byte and 0 is
41 the EOF).
43 RESULT
44 The new position on success and -1 on error. If an error occurred, the global
45 variable errno is set.
47 NOTES
49 EXAMPLE
51 BUGS
52 File is extended with zeros if desired position is beyond the end of
53 file.
55 Since it's not possible to use Seek() for directories, this
56 implementation fails with EISDIR for directory file descriptors.
58 SEE ALSO
59 fopen(), fwrite()
61 INTERNALS
63 ******************************************************************************/
65 int cnt;
66 fdesc *fdesc = __getfdesc(filedes);
68 if (!fdesc)
70 errno = EBADF;
71 return -1;
74 if(fdesc->fcb->isdir)
76 errno = EISDIR;
77 return -1;
80 switch (whence)
82 case SEEK_SET: whence = OFFSET_BEGINNING; break;
83 case SEEK_CUR: whence = OFFSET_CURRENT; break;
84 case SEEK_END: whence = OFFSET_END; break;
86 default:
87 errno = EINVAL;
88 return -1;
91 cnt = Seek ((BPTR)fdesc->fcb->fh, offset, whence);
93 if (cnt == -1)
95 if(IoErr() == ERROR_SEEK_ERROR)
97 LONG saved_error = IoErr();
98 /* Most likely we tried to seek behind EOF. POSIX lseek allows
99 that, and if anything is written at the end on the gap,
100 reads from the gap should return 0 unless some real data
101 is written there. Since implementing it would be rather
102 difficult, we simply extend the file by writing zeros
103 and hope for the best. */
104 LONG abs_cur_pos = Seek(fdesc->fcb->fh, 0, OFFSET_CURRENT);
105 if(abs_cur_pos == -1)
106 goto error;
107 LONG file_size = Seek(fdesc->fcb->fh, 0, OFFSET_END);
108 if(file_size == -1)
109 goto error;
110 /* Now compute how much we have to extend the file */
111 LONG abs_new_pos = 0;
112 switch(whence)
114 case OFFSET_BEGINNING: abs_new_pos = offset; break;
115 case OFFSET_CURRENT: abs_new_pos = abs_cur_pos + offset; break;
116 case OFFSET_END: abs_new_pos = file_size + offset; break;
118 if(abs_new_pos > abs_cur_pos)
120 ULONG bufsize = 4096;
121 APTR zeros = AllocMem(bufsize, MEMF_ANY | MEMF_CLEAR);
122 if(!zeros)
124 /* Restore previous position */
125 Seek(fdesc->fcb->fh, abs_cur_pos, OFFSET_BEGINNING);
126 errno = ENOMEM;
127 return -1;
130 LONG towrite = abs_new_pos - abs_cur_pos;
133 Write(fdesc->fcb->fh, zeros, MIN(towrite, bufsize));
134 towrite -= bufsize;
136 while(towrite > 0);
138 FreeMem(zeros, bufsize);
140 else
142 /* Hmm, that's strange. Looks like ERROR_SEEK_ERROR has
143 been caused by something else */
144 SetIoErr(saved_error);
145 goto error;
148 else
149 goto error;
152 return Seek((BPTR)fdesc->fcb->fh, 0, OFFSET_CURRENT);
153 error:
154 errno = IoErr2errno (IoErr ());
155 return (off_t) -1;
156 } /* lseek */