OSDN Git Service

4e05cfe1df340e9d42ad4895e250b6875962ee40
[pf3gnuchains/gcc-fork.git] / libjava / java / io / natFileDescriptorPosix.cc
1 // natFileDescriptor.cc - Native part of FileDescriptor class.
2
3 /* Copyright (C) 1998, 1999, 2000, 2001  Free Software Foundation
4
5    This file is part of libgcj.
6
7 This software is copyrighted work licensed under the terms of the
8 Libgcj License.  Please consult the file "LIBGCJ_LICENSE" for
9 details.  */
10
11 #include <config.h>
12
13 #include "posix.h"
14
15 #include <errno.h>
16 #include <stdio.h>
17 #include <string.h>
18 #include <sys/stat.h>
19 #include <sys/param.h>
20 #include <fcntl.h>
21
22 #ifdef HAVE_SYS_IOCTL_H
23 #define BSD_COMP /* Get FIONREAD on Solaris2. */
24 #include <sys/ioctl.h>
25 #endif
26
27 // Pick up FIONREAD on Solaris 2.5.
28 #ifdef HAVE_SYS_FILIO_H
29 #include <sys/filio.h>
30 #endif
31
32 #include <gcj/cni.h>
33 #include <jvm.h>
34 #include <java/io/FileDescriptor.h>
35 #include <java/io/SyncFailedException.h>
36 #include <java/io/IOException.h>
37 #include <java/io/InterruptedIOException.h>
38 #include <java/io/EOFException.h>
39 #include <java/lang/ArrayIndexOutOfBoundsException.h>
40 #include <java/lang/NullPointerException.h>
41 #include <java/lang/System.h>
42 #include <java/lang/String.h>
43 #include <java/lang/Thread.h>
44 #include <java/io/FileNotFoundException.h>
45
46 #define NO_FSYNC_MESSAGE "sync unsupported"
47
48 jboolean
49 java::io::FileDescriptor::valid (void)
50 {
51   struct stat sb;
52   return ::fstat (fd, &sb) == 0;
53 }
54
55 void
56 java::io::FileDescriptor::sync (void)
57 {
58   // Some files don't support fsync.  We don't bother reporting these
59   // as errors.
60 #ifdef HAVE_FSYNC
61   if (::fsync (fd) && errno != EROFS && errno != EINVAL)
62     throw new SyncFailedException (JvNewStringLatin1 (strerror (errno)));
63 #else
64   throw new SyncFailedException (JvNewStringLatin1 (NO_FSYNC_MESSAGE));
65 #endif
66 }
67
68 jint
69 java::io::FileDescriptor::open (jstring path, jint jflags)
70 {
71   char *buf = (char *) _Jv_AllocBytes (_Jv_GetStringUTFLength (path) + 1);
72   jsize total = JvGetStringUTFRegion (path, 0, path->length(), buf);
73   buf[total] = '\0';
74   int flags = 0;
75 #ifdef O_BINARY
76   flags |= O_BINARY;
77 #endif
78
79   JvAssert ((jflags & READ) || (jflags & WRITE));
80   int mode = 0666;
81   if ((jflags & READ) && (jflags & WRITE))
82     flags |= O_RDWR | O_CREAT;
83   else if ((jflags & READ))
84     flags |= O_RDONLY;
85   else
86     {
87       flags |= O_WRONLY | O_CREAT;
88       if ((jflags & APPEND))
89         flags |= O_APPEND;
90       else
91         flags |= O_TRUNC;
92
93       if ((jflags & EXCL))
94         {
95           flags |= O_EXCL;
96           // In this case we are making a temp file.
97           mode = 0600;
98         }
99     }
100
101   int fd = ::open (buf, flags, mode);
102   if (fd == -1 && errno == EMFILE)
103     {
104       // Because finalize () calls close () we might be able to continue.
105       java::lang::System::gc ();
106       java::lang::System::runFinalization ();
107       fd = ::open (buf, flags, mode);
108     }
109   if (fd == -1)
110     {
111       char msg[MAXPATHLEN + 200];
112       // We choose the formatting here for JDK compatibility, believe
113       // it or not.
114       sprintf (msg, "%s (%s)", buf, strerror (errno));
115       throw new FileNotFoundException (JvNewStringLatin1 (msg));
116     }
117   return fd;
118 }
119
120 void
121 java::io::FileDescriptor::write (jint b)
122 {
123   jbyte d = (jbyte) b;
124   int r = 0;
125   while (r != 1)
126     {
127       r = ::write (fd, &d, 1);
128       if (java::lang::Thread::interrupted())
129         {
130           InterruptedIOException *iioe
131             = new InterruptedIOException (JvNewStringLatin1 ("write interrupted"));
132           iioe->bytesTransferred = r == -1 ? 0 : r;
133           throw iioe;
134         }
135       else if (r == -1)
136         throw new IOException (JvNewStringLatin1 (strerror (errno)));
137     }
138 }
139
140 void
141 java::io::FileDescriptor::write (jbyteArray b, jint offset, jint len)
142 {
143   if (! b)
144     throw new java::lang::NullPointerException;
145   if (offset < 0 || len < 0 || offset + len > JvGetArrayLength (b))
146     throw new java::lang::ArrayIndexOutOfBoundsException;
147   jbyte *bytes = elements (b) + offset;
148
149   int written = 0;
150   while (len > 0)
151     {
152       int r = ::write (fd, bytes, len);
153       if (r != -1)
154         written += r;
155       if (java::lang::Thread::interrupted())
156         {
157           InterruptedIOException *iioe
158             = new InterruptedIOException (JvNewStringLatin1 ("write interrupted"));
159           iioe->bytesTransferred = written;
160           throw iioe;
161         }
162       else if (r == -1)
163         throw new IOException (JvNewStringLatin1 (strerror (errno)));
164
165       len -= r;
166       bytes += r;
167     }
168 }
169
170 void
171 java::io::FileDescriptor::close (void)
172 {
173   jint save = fd;
174   fd = -1;
175   if (::close (save))
176     throw new IOException (JvNewStringLatin1 (strerror (errno)));
177 }
178
179 jint
180 java::io::FileDescriptor::seek (jlong pos, jint whence)
181 {
182   JvAssert (whence == SET || whence == CUR);
183
184   jlong len = length ();
185   jlong here = getFilePointer ();
186
187   if ((whence == SET && pos > len) || (whence == CUR && here + pos > len))
188     throw new EOFException;
189
190   off_t r = ::lseek (fd, (off_t) pos, whence == SET ? SEEK_SET : SEEK_CUR);
191   if (r == -1)
192     throw new IOException (JvNewStringLatin1 (strerror (errno)));
193   return r;
194 }
195
196 jlong
197 java::io::FileDescriptor::length (void)
198 {
199   struct stat sb;
200   if (::fstat (fd, &sb))
201     throw new IOException (JvNewStringLatin1 (strerror (errno)));
202   return sb.st_size;
203 }
204
205 jlong
206 java::io::FileDescriptor::getFilePointer (void)
207 {
208   off_t r = ::lseek (fd, 0, SEEK_CUR);
209   if (r == -1)
210     throw new IOException (JvNewStringLatin1 (strerror (errno)));
211   return r;
212 }
213
214 jint
215 java::io::FileDescriptor::read (void)
216 {
217   jbyte b;
218   int r = ::read (fd, &b, 1);
219   if (r == 0)
220     return -1;
221   if (java::lang::Thread::interrupted())
222     {
223       InterruptedIOException *iioe
224         = new InterruptedIOException (JvNewStringLatin1 ("read interrupted"));
225       iioe->bytesTransferred = r == -1 ? 0 : r;
226       throw iioe;
227     }
228   else if (r == -1)
229     throw new IOException (JvNewStringLatin1 (strerror (errno)));
230   return b & 0xFF;
231 }
232
233 jint
234 java::io::FileDescriptor::read (jbyteArray buffer, jint offset, jint count)
235 {
236   if (! buffer)
237     throw new java::lang::NullPointerException;
238   jsize bsize = JvGetArrayLength (buffer);
239   if (offset < 0 || count < 0 || offset + count > bsize)
240     throw new java::lang::ArrayIndexOutOfBoundsException;
241   jbyte *bytes = elements (buffer) + offset;
242   int r = ::read (fd, bytes, count);
243   if (r == 0)
244     return -1;
245   if (java::lang::Thread::interrupted())
246     {
247       InterruptedIOException *iioe
248         = new InterruptedIOException (JvNewStringLatin1 ("read interrupted"));
249       iioe->bytesTransferred = r == -1 ? 0 : r;
250       throw iioe;
251     }
252   else if (r == -1)
253     throw new IOException (JvNewStringLatin1 (strerror (errno)));
254   return r;
255 }
256
257 jint
258 java::io::FileDescriptor::available (void)
259 {
260 #if defined (FIONREAD) || defined (HAVE_SELECT) || defined (HAVE_FSTAT)
261   long num = 0;
262   int r = 0;
263   bool num_set = false;
264
265 #if defined (FIONREAD)
266   r = ::ioctl (fd, FIONREAD, &num);
267   if (r == -1 && errno == ENOTTY)
268     {
269       // If the ioctl doesn't work, we don't care.
270       r = 0;
271       num = 0;
272     }
273   else
274     num_set = true;
275 #elif defined (HAVE_SELECT)
276   if (fd < 0)
277     {
278       errno = EBADF;
279       r = -1;
280     }
281 #endif
282
283   if (r == -1)
284     {
285     posix_error:
286       throw new IOException (JvNewStringLatin1 (strerror (errno)));
287     }
288
289   // If we didn't get anything, and we have fstat, then see if see if
290   // we're reading a regular file.  On many systems, FIONREAD does not
291   // work on regular files; select() likewise returns a useless
292   // result.  This is run incorrectly when FIONREAD does work on
293   // regular files and we are at the end of the file.  However, this
294   // case probably isn't very important.
295 #if defined (HAVE_FSTAT)
296   if (! num_set)
297     {
298       struct stat sb;
299       off_t where = 0;
300       if (fstat (fd, &sb) != -1
301           && S_ISREG (sb.st_mode)
302           && (where = lseek (fd, SEEK_CUR, 0)) != (off_t) -1)
303         {
304           num = (long) (sb.st_size - where);
305           num_set = true;
306         }
307     }
308 #endif /* HAVE_FSTAT */
309
310 #if defined (HAVE_SELECT)
311   if (! num_set)
312     {
313       fd_set rd;
314       FD_ZERO (&rd);
315       FD_SET (fd, &rd);
316       struct timeval tv;
317       tv.tv_sec = 0;
318       tv.tv_usec = 0;
319       r = _Jv_select (fd + 1, &rd, NULL, NULL, &tv);
320       if (r == -1)
321         goto posix_error;
322       num = r == 0 ? 0 : 1;
323     }
324 #endif /* HAVE_SELECT */
325
326   return (jint) num;
327 #else
328   throw new IOException (JvNewStringLatin1 ("unimplemented"));
329 #endif
330 }