OSDN Git Service

2ad2d9dce77b57318a6a57947b9f132c52c7e496
[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, 2002, 2003  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
21 #ifdef HAVE_SYS_IOCTL_H
22 #define BSD_COMP /* Get FIONREAD on Solaris2. */
23 #include <sys/ioctl.h>
24 #endif
25
26 // Pick up FIONREAD on Solaris 2.5.
27 #ifdef HAVE_SYS_FILIO_H
28 #include <sys/filio.h>
29 #endif
30
31 #include <gcj/cni.h>
32 #include <jvm.h>
33 #include <java/io/FileDescriptor.h>
34 #include <java/io/SyncFailedException.h>
35 #include <java/io/IOException.h>
36 #include <java/io/InterruptedIOException.h>
37 #include <java/io/EOFException.h>
38 #include <java/lang/ArrayIndexOutOfBoundsException.h>
39 #include <java/lang/NullPointerException.h>
40 #include <java/lang/System.h>
41 #include <java/lang/String.h>
42 #include <java/lang/Thread.h>
43 #include <java/io/FileNotFoundException.h>
44
45 #define NO_FSYNC_MESSAGE "sync unsupported"
46
47 void
48 java::io::FileDescriptor::init (void)
49 {
50   in = new java::io::FileDescriptor(0);
51   out = new java::io::FileDescriptor(1);
52   err = new java::io::FileDescriptor(2);
53 }
54
55 jboolean
56 java::io::FileDescriptor::valid (void)
57 {
58   struct stat sb;
59   return fd >= 0 && ::fstat (fd, &sb) == 0;
60 }
61
62 void
63 java::io::FileDescriptor::sync (void)
64 {
65   // Some files don't support fsync.  We don't bother reporting these
66   // as errors.
67 #ifdef HAVE_FSYNC
68   if (::fsync (fd) && errno != EROFS && errno != EINVAL)
69     throw new SyncFailedException (JvNewStringLatin1 (strerror (errno)));
70 #else
71   throw new SyncFailedException (JvNewStringLatin1 (NO_FSYNC_MESSAGE));
72 #endif
73 }
74
75 jint
76 java::io::FileDescriptor::open (jstring path, jint jflags)
77 {
78   char *buf = (char *) _Jv_AllocBytes (_Jv_GetStringUTFLength (path) + 1);
79   jsize total = JvGetStringUTFRegion (path, 0, path->length(), buf);
80   buf[total] = '\0';
81   int flags = 0;
82 #ifdef O_BINARY
83   flags |= O_BINARY;
84 #endif
85
86   JvAssert ((jflags & READ) || (jflags & WRITE));
87   int mode = 0666;
88   if ((jflags & READ) && (jflags & WRITE))
89     flags |= O_RDWR | O_CREAT;
90   else if ((jflags & READ))
91     flags |= O_RDONLY;
92   else
93     {
94       flags |= O_WRONLY | O_CREAT;
95       if ((jflags & APPEND))
96         flags |= O_APPEND;
97       else
98         flags |= O_TRUNC;
99
100       if ((jflags & EXCL))
101         {
102           flags |= O_EXCL;
103           // In this case we are making a temp file.
104           mode = 0600;
105         }
106     }
107
108   if ((jflags & SYNC))
109     flags |= O_SYNC;
110
111   if ((jflags & DSYNC))
112     flags |= O_DSYNC;
113
114   int fd = ::open (buf, flags, mode);
115   if (fd == -1 && errno == EMFILE)
116     {
117       // Because finalize () calls close () we might be able to continue.
118       java::lang::System::gc ();
119       java::lang::System::runFinalization ();
120       fd = ::open (buf, flags, mode);
121     }
122   if (fd == -1)
123     {
124       char msg[MAXPATHLEN + 200];
125       // We choose the formatting here for JDK compatibility, believe
126       // it or not.
127       sprintf (msg, "%s (%s)", buf, strerror (errno));
128       throw new FileNotFoundException (JvNewStringLatin1 (msg));
129     }
130
131   _Jv_platform_close_on_exec (fd);
132
133   return fd;
134 }
135
136 void
137 java::io::FileDescriptor::write (jint b)
138 {
139   jbyte d = (jbyte) b;
140   int r = 0;
141   while (r != 1)
142     {
143       r = ::write (fd, &d, 1);
144       if (r == -1)
145         {
146           if (java::lang::Thread::interrupted())
147             {
148               InterruptedIOException *iioe
149                 = new InterruptedIOException (JvNewStringLatin1 (strerror (errno)));
150               iioe->bytesTransferred = r == -1 ? 0 : r;
151               throw iioe;
152             }       
153           throw new IOException (JvNewStringLatin1 (strerror (errno)));
154         }
155     }
156   position++;
157 }
158
159 void
160 java::io::FileDescriptor::write (jbyteArray b, jint offset, jint len)
161 {
162   if (! b)
163     throw new java::lang::NullPointerException;
164   if (offset < 0 || len < 0 || offset + len > JvGetArrayLength (b))
165     throw new java::lang::ArrayIndexOutOfBoundsException;
166   jbyte *bytes = elements (b) + offset;
167
168   int written = 0;
169   while (len > 0)
170     {
171       int r = ::write (fd, bytes, len);
172       if (r == -1)
173         {
174           if (java::lang::Thread::interrupted())
175             {
176               InterruptedIOException *iioe
177                 = new InterruptedIOException (JvNewStringLatin1 (strerror (errno)));
178               iioe->bytesTransferred = written;
179               throw iioe;
180             }
181           throw new IOException (JvNewStringLatin1 (strerror (errno)));
182         }
183
184       written += r;
185       len -= r;
186       bytes += r;
187       position += r;
188     }
189 }
190
191 void
192 java::io::FileDescriptor::close (void)
193 {
194   jint save = fd;
195   fd = -1;
196   if (::close (save))
197     throw new IOException (JvNewStringLatin1 (strerror (errno)));
198 }
199
200 void
201 java::io::FileDescriptor::setLength (jlong pos)
202 {
203   struct stat sb;
204
205 #ifdef HAVE_FTRUNCATE
206   if (::fstat (fd, &sb))
207     throw new IOException (JvNewStringLatin1 (strerror (errno)));
208
209   if ((jlong) sb.st_size == pos) 
210     return;
211
212   // If the file is too short, we extend it.  We can't rely on
213   // ftruncate() extending the file.  So we lseek() to 1 byte less
214   // than we want, and then we write a single byte at the end.
215   if ((jlong) sb.st_size < pos)
216     {
217       if (::lseek (fd, (off_t) (pos - 1), SEEK_SET) == -1)
218         throw new IOException (JvNewStringLatin1 (strerror (errno)));
219       char out = '\0';
220       int r = ::write (fd, &out, 1);
221       if (r <= 0 || ::lseek (fd, position, SEEK_SET) == -1)
222         throw new IOException (JvNewStringLatin1 (strerror (errno)));
223     }
224   else
225     {
226       if (::ftruncate (fd, (off_t) pos))
227         throw new IOException (JvNewStringLatin1 (strerror (errno)));
228       position = pos;
229     }
230 #else /* HAVE_FTRUNCATE */
231   throw new IOException (JvNewStringLatin1 ("FileDescriptor.setLength not implemented"));
232 #endif /* HAVE_FTRUNCATE */
233 }
234
235 jint
236 java::io::FileDescriptor::seek (jlong pos, jint whence, jboolean eof_trunc)
237 {
238   JvAssert (whence == SET || whence == CUR);
239
240   if (eof_trunc)
241     {
242       jlong len = getLength ();
243       if (whence == SET)
244         {
245           if (pos > len)
246             pos = len;
247         }
248       else
249         {
250           jlong here = getFilePointer ();
251           if (here + pos > len)
252             {
253               pos = len;
254               whence = SET;
255             }
256         }
257     }
258
259   off_t r = ::lseek (fd, (off_t) pos, whence == SET ? SEEK_SET : SEEK_CUR);
260   if (r == -1)
261     throw new IOException (JvNewStringLatin1 (strerror (errno)));
262   position = r;
263   return r;
264 }
265
266 jlong
267 java::io::FileDescriptor::getLength (void)
268 {
269   struct stat sb;
270   if (::fstat (fd, &sb))
271     throw new IOException (JvNewStringLatin1 (strerror (errno)));
272   return sb.st_size;
273 }
274
275 jlong
276 java::io::FileDescriptor::getFilePointer (void)
277 {
278   return position;
279 }
280
281 jint
282 java::io::FileDescriptor::read (void)
283 {
284   jbyte b;
285   int r = ::read (fd, &b, 1);
286   if (r == 0)
287     return -1;
288   if (r == -1)
289     {
290       if (java::lang::Thread::interrupted())
291         {
292           InterruptedIOException *iioe
293             = new InterruptedIOException (JvNewStringLatin1 (strerror (errno)));
294           iioe->bytesTransferred = r == -1 ? 0 : r;
295           throw iioe;
296         }
297       throw new IOException (JvNewStringLatin1 (strerror (errno)));
298     }
299   position++;
300   return b & 0xFF;
301 }
302
303 jint
304 java::io::FileDescriptor::read (jbyteArray buffer, jint offset, jint count)
305 {
306   if (! buffer)
307     throw new java::lang::NullPointerException;
308   jsize bsize = JvGetArrayLength (buffer);
309   if (offset < 0 || count < 0 || offset + count > bsize)
310     throw new java::lang::ArrayIndexOutOfBoundsException;
311
312   // Must return 0 if an attempt is made to read 0 bytes.
313   if (count == 0)
314     return 0;
315
316   jbyte *bytes = elements (buffer) + offset;
317   int r = ::read (fd, bytes, count);
318   if (r == 0)
319     return -1;
320   if (r == -1)
321     {    
322       if (java::lang::Thread::interrupted())
323         {
324           InterruptedIOException *iioe
325             = new InterruptedIOException (JvNewStringLatin1 (strerror (errno)));
326           iioe->bytesTransferred = r == -1 ? 0 : r;
327           throw iioe;
328         }
329       throw new IOException (JvNewStringLatin1 (strerror (errno)));
330     }
331   position += r;
332   return r;
333 }
334
335 jint
336 java::io::FileDescriptor::available (void)
337 {
338 #if defined (FIONREAD) || defined (HAVE_SELECT) || defined (HAVE_FSTAT)
339   long num = 0;
340   int r = 0;
341   bool num_set = false;
342
343 #if defined (FIONREAD)
344   r = ::ioctl (fd, FIONREAD, &num);
345   if (r == -1 && errno == ENOTTY)
346     {
347       // If the ioctl doesn't work, we don't care.
348       r = 0;
349       num = 0;
350     }
351   else
352     num_set = true;
353 #elif defined (HAVE_SELECT)
354   if (fd < 0)
355     {
356       errno = EBADF;
357       r = -1;
358     }
359 #endif
360
361   if (r == -1)
362     {
363     posix_error:
364       throw new IOException (JvNewStringLatin1 (strerror (errno)));
365     }
366
367   // If we didn't get anything, and we have fstat, then see if see if
368   // we're reading a regular file.  On many systems, FIONREAD does not
369   // work on regular files; select() likewise returns a useless
370   // result.  This is run incorrectly when FIONREAD does work on
371   // regular files and we are at the end of the file.  However, this
372   // case probably isn't very important.
373 #if defined (HAVE_FSTAT)
374   if (! num_set)
375     {
376       struct stat sb;
377       off_t where = 0;
378       if (fstat (fd, &sb) != -1
379           && S_ISREG (sb.st_mode)
380           && (where = lseek (fd, 0, SEEK_CUR)) != (off_t) -1)
381         {
382           num = (long) (sb.st_size - where);
383           num_set = true;
384         }
385     }
386 #endif /* HAVE_FSTAT */
387
388 #if defined (HAVE_SELECT)
389   if (! num_set)
390     {
391       fd_set rd;
392       FD_ZERO (&rd);
393       FD_SET (fd, &rd);
394       struct timeval tv;
395       tv.tv_sec = 0;
396       tv.tv_usec = 0;
397       r = _Jv_select (fd + 1, &rd, NULL, NULL, &tv);
398       if (r == -1)
399         goto posix_error;
400       num = r == 0 ? 0 : 1;
401     }
402 #endif /* HAVE_SELECT */
403
404   return (jint) num;
405 #else
406   return 0;
407 #endif
408 }