OSDN Git Service

- fix inline keyword
[uclinux-h8/uclibc-ng.git] / libc / sysdeps / linux / common / pread_write.c
1 /* vi: set sw=4 ts=4: */
2 /*
3  * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>
4  *
5  * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
6  */
7 /*
8  * Based in part on the files
9  *              ./sysdeps/unix/sysv/linux/pwrite.c,
10  *              ./sysdeps/unix/sysv/linux/pread.c,
11  *              sysdeps/posix/pread.c
12  *              sysdeps/posix/pwrite.c
13  * from GNU libc 2.2.5, but reworked considerably...
14  */
15
16 #include <sys/syscall.h>
17 #include <unistd.h>
18 #include <stdint.h>
19 #include <endian.h>
20
21 extern __typeof(pread) __libc_pread;
22 extern __typeof(pwrite) __libc_pwrite;
23 #ifdef __UCLIBC_HAS_LFS__
24 extern __typeof(pread64) __libc_pread64;
25 extern __typeof(pwrite64) __libc_pwrite64;
26 #endif
27
28 #include <bits/kernel_types.h>
29
30 #ifdef __NR_pread
31
32 # define __NR___syscall_pread __NR_pread
33 static __inline__ _syscall5(ssize_t, __syscall_pread, int, fd, void *, buf,
34                 size_t, count, off_t, offset_hi, off_t, offset_lo);
35
36 ssize_t __libc_pread(int fd, void *buf, size_t count, off_t offset)
37 {
38         return __syscall_pread(fd, buf, count, __LONG_LONG_PAIR(offset >> 31, offset));
39 }
40 weak_alias(__libc_pread,pread)
41
42 # ifdef __UCLIBC_HAS_LFS__
43 ssize_t __libc_pread64(int fd, void *buf, size_t count, off64_t offset)
44 {
45     uint32_t low = offset & 0xffffffff;
46     uint32_t high = offset >> 32;
47         return __syscall_pread(fd, buf, count, __LONG_LONG_PAIR(high, low));
48 }
49 weak_alias(__libc_pread64,pread64)
50 # endif /* __UCLIBC_HAS_LFS__  */
51
52 #endif /* __NR_pread */
53
54 #ifdef __NR_pwrite
55
56 # define __NR___syscall_pwrite __NR_pwrite
57 static __inline__ _syscall5(ssize_t, __syscall_pwrite, int, fd, const void *, buf,
58                 size_t, count, off_t, offset_hi, off_t, offset_lo);
59
60 ssize_t __libc_pwrite(int fd, const void *buf, size_t count, off_t offset)
61 {
62         return __syscall_pwrite(fd, buf, count, __LONG_LONG_PAIR(offset >> 31, offset));
63 }
64 weak_alias(__libc_pwrite,pwrite)
65
66 # ifdef __UCLIBC_HAS_LFS__
67 ssize_t __libc_pwrite64(int fd, const void *buf, size_t count, off64_t offset)
68 {
69     uint32_t low = offset & 0xffffffff;
70     uint32_t high = offset >> 32;
71         return __syscall_pwrite(fd, buf, count, __LONG_LONG_PAIR(high, low));
72 }
73 weak_alias(__libc_pwrite64,pwrite64)
74 # endif /* __UCLIBC_HAS_LFS__  */
75 #endif /* __NR_pwrite */
76
77 #if ! defined __NR_pread || ! defined __NR_pwrite
78 libc_hidden_proto(read)
79 libc_hidden_proto(write)
80 libc_hidden_proto(lseek)
81
82 static ssize_t __fake_pread_write(int fd, void *buf,
83                 size_t count, off_t offset, int do_pwrite)
84 {
85         int save_errno;
86         ssize_t result;
87         off_t old_offset;
88
89         /* Since we must not change the file pointer preserve the
90          * value so that we can restore it later.  */
91         if ((old_offset=lseek(fd, 0, SEEK_CUR)) == (off_t) -1)
92                 return -1;
93
94         /* Set to wanted position.  */
95         if (lseek(fd, offset, SEEK_SET) == (off_t) -1)
96                 return -1;
97
98         if (do_pwrite == 1) {
99                 /* Write the data.  */
100                 result = write(fd, buf, count);
101         } else {
102                 /* Read the data.  */
103                 result = read(fd, buf, count);
104         }
105
106         /* Now we have to restore the position.  If this fails we
107          * have to return this as an error.  */
108         save_errno = errno;
109         if (lseek(fd, old_offset, SEEK_SET) == (off_t) -1)
110         {
111                 if (result == -1)
112                         __set_errno(save_errno);
113                 return -1;
114         }
115         __set_errno(save_errno);
116         return(result);
117 }
118
119 # ifdef __UCLIBC_HAS_LFS__
120 libc_hidden_proto(lseek64)
121
122 static ssize_t __fake_pread_write64(int fd, void *buf,
123                 size_t count, off64_t offset, int do_pwrite)
124 {
125         int save_errno;
126         ssize_t result;
127         off64_t old_offset;
128
129         /* Since we must not change the file pointer preserve the
130          * value so that we can restore it later.  */
131         if ((old_offset=lseek64(fd, 0, SEEK_CUR)) == (off64_t) -1)
132                 return -1;
133
134         /* Set to wanted position.  */
135         if (lseek64(fd, offset, SEEK_SET) == (off64_t) -1)
136                 return -1;
137
138         if (do_pwrite == 1) {
139                 /* Write the data.  */
140                 result = write(fd, buf, count);
141         } else {
142                 /* Read the data.  */
143                 result = read(fd, buf, count);
144         }
145
146         /* Now we have to restore the position. */
147         save_errno = errno;
148         if (lseek64(fd, old_offset, SEEK_SET) == (off64_t) -1) {
149                 if (result == -1)
150                         __set_errno (save_errno);
151                 return -1;
152         }
153         __set_errno (save_errno);
154         return result;
155 }
156 # endif /* __UCLIBC_HAS_LFS__  */
157 #endif /*  ! defined __NR_pread || ! defined __NR_pwrite */
158
159 #ifndef __NR_pread
160 ssize_t __libc_pread(int fd, void *buf, size_t count, off_t offset)
161 {
162         return __fake_pread_write(fd, buf, count, offset, 0);
163 }
164 weak_alias(__libc_pread,pread)
165
166 # ifdef __UCLIBC_HAS_LFS__
167 ssize_t __libc_pread64(int fd, void *buf, size_t count, off64_t offset)
168 {
169         return __fake_pread_write64(fd, buf, count, offset, 0);
170 }
171 weak_alias(__libc_pread64,pread64)
172 # endif /* __UCLIBC_HAS_LFS__  */
173 #endif /* ! __NR_pread */
174
175 #ifndef __NR_pwrite
176 ssize_t __libc_pwrite(int fd, const void *buf, size_t count, off_t offset)
177 {
178         /* we won't actually be modifying the buffer,
179          *just cast it to get rid of warnings */
180         return __fake_pread_write(fd, (void*)buf, count, offset, 1);
181 }
182 weak_alias(__libc_pwrite,pwrite)
183
184 # ifdef __UCLIBC_HAS_LFS__
185 ssize_t __libc_pwrite64(int fd, const void *buf, size_t count, off64_t offset)
186 {
187         return __fake_pread_write64(fd, (void*)buf, count, offset, 1);
188 }
189 weak_alias(__libc_pwrite64,pwrite64)
190 # endif /* __UCLIBC_HAS_LFS__  */
191 #endif /* ! __NR_pwrite */