2
* Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5
* This code is free software; you can redistribute it and/or modify it
6
* under the terms of the GNU General Public License version 2 only, as
7
* published by the Free Software Foundation. Oracle designates this
8
* particular file as subject to the "Classpath" exception as provided
9
* by Oracle in the LICENSE file that accompanied this code.
11
* This code is distributed in the hope that it will be useful, but WITHOUT
12
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14
* version 2 for more details (a copy is included in the LICENSE file that
15
* accompanied this code).
17
* You should have received a copy of the GNU General Public License version
18
* 2 along with this work; if not, write to the Free Software Foundation,
19
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
21
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22
* or visit www.oracle.com if you need additional information or have any
28
import cli.System.IO.FileAccess;
29
import cli.System.IO.FileMode;
30
import cli.System.IO.FileShare;
31
import cli.System.IO.FileStream;
32
import cli.System.IO.SeekOrigin;
33
import cli.System.Runtime.InteropServices.DllImportAttribute;
34
import java.util.concurrent.atomic.AtomicInteger;
37
* Instances of the file descriptor class serve as an opaque handle
38
* to the underlying machine-specific structure representing an
39
* open file, an open socket, or another source or sink of bytes.
40
* The main practical use for a file descriptor is to create a
41
* {@link FileInputStream} or {@link FileOutputStream} to contain it.
43
* <p>Applications should not create their own file descriptors.
45
* @author Pavani Diwanji
48
public final class FileDescriptor {
50
private volatile cli.System.IO.Stream stream;
51
private volatile cli.System.Net.Sockets.Socket socket;
52
private volatile boolean nonBlockingSocket;
53
private volatile cli.System.IAsyncResult asyncResult;
57
* JRuby uses reflection to get at the handle (on Windows) and fd (on non-Windows)
58
* fields to convert it into a native handle and query if it is a tty.
60
@ikvm.lang.Property(get = "get_handle")
63
@ikvm.lang.Property(get = "get_fd")
66
@cli.System.Security.SecurityCriticalAttribute.Annotation
67
private long get_handle()
69
if (ikvm.internal.Util.WINDOWS)
71
if (stream instanceof cli.System.IO.FileStream)
73
cli.System.IO.FileStream fs = (cli.System.IO.FileStream)stream;
74
return fs.get_Handle().ToInt64();
78
return GetStdHandle(-10).ToInt64();
82
return GetStdHandle(-11).ToInt64();
86
return GetStdHandle(-12).ToInt64();
92
@cli.System.Security.SecurityCriticalAttribute.Annotation
95
if (!ikvm.internal.Util.WINDOWS)
97
if (stream instanceof cli.System.IO.FileStream)
99
cli.System.IO.FileStream fs = (cli.System.IO.FileStream)stream;
100
return fs.get_Handle().ToInt32();
106
else if (this == out)
110
else if (this == err)
118
@DllImportAttribute.Annotation("kernel32")
119
private static native cli.System.IntPtr GetStdHandle(int nStdHandle);
122
* A use counter for tracking the FIS/FOS/RAF instances that
123
* use this FileDescriptor. The FIS/FOS.finalize() will not release
124
* the FileDescriptor if it is still under use by any stream.
126
private AtomicInteger useCount;
130
* Constructs an (invalid) FileDescriptor
133
public /**/ FileDescriptor() {
134
useCount = new AtomicInteger();
138
* A handle to the standard input stream. Usually, this file
139
* descriptor is not used directly, but rather via the input stream
140
* known as {@code System.in}.
142
* @see java.lang.System#in
144
public static final FileDescriptor in = standardStream(0);
147
* A handle to the standard output stream. Usually, this file
148
* descriptor is not used directly, but rather via the output stream
149
* known as {@code System.out}.
150
* @see java.lang.System#out
152
public static final FileDescriptor out = standardStream(1);
155
* A handle to the standard error stream. Usually, this file
156
* descriptor is not used directly, but rather via the output stream
157
* known as {@code System.err}.
159
* @see java.lang.System#err
161
public static final FileDescriptor err = standardStream(2);
164
* Tests if this file descriptor object is valid.
166
* @return {@code true} if the file descriptor object represents a
167
* valid, open file, socket, or other active I/O connection;
168
* {@code false} otherwise.
170
public boolean valid() {
171
return stream != null || socket != null;
175
* Force all system buffers to synchronize with the underlying
176
* device. This method returns after all modified data and
177
* attributes of this FileDescriptor have been written to the
178
* relevant device(s). In particular, if this FileDescriptor
179
* refers to a physical storage medium, such as a file in a file
180
* system, sync will not return until all in-memory modified copies
181
* of buffers associated with this FileDesecriptor have been
182
* written to the physical medium.
184
* sync is meant to be used by code that requires physical
185
* storage (such as a file) to be in a known state For
186
* example, a class that provided a simple transaction facility
187
* might use sync to ensure that all changes to a file caused
188
* by a given transaction were recorded on a storage medium.
190
* sync only affects buffers downstream of this FileDescriptor. If
191
* any in-memory buffering is being done by the application (for
192
* example, by a BufferedOutputStream object), those buffers must
193
* be flushed into the FileDescriptor (for example, by invoking
194
* OutputStream.flush) before that data will be affected by sync.
196
* @exception SyncFailedException
197
* Thrown when the buffers cannot be flushed,
198
* or because the system cannot guarantee that all the
199
* buffers have been synchronized with physical media.
202
public void sync() throws SyncFailedException
206
throw new SyncFailedException("sync failed");
209
if (!stream.get_CanWrite())
216
if (false) throw new cli.System.IO.IOException();
219
catch (cli.System.IO.IOException x)
221
throw new SyncFailedException(x.getMessage());
224
if (stream instanceof FileStream)
226
FileStream fs = (FileStream)stream;
227
boolean ok = ikvm.internal.Util.WINDOWS ? flushWin32(fs) : flushPosix(fs);
230
throw new SyncFailedException("sync failed");
235
private static native boolean flushPosix(FileStream fs);
237
@cli.System.Security.SecuritySafeCriticalAttribute.Annotation
238
private static boolean flushWin32(FileStream fs)
240
return FlushFileBuffers(fs.get_SafeFileHandle()) != 0;
243
@DllImportAttribute.Annotation("kernel32")
244
private static native int FlushFileBuffers(cli.Microsoft.Win32.SafeHandles.SafeFileHandle handle);
246
private static FileDescriptor standardStream(int fd) {
247
FileDescriptor desc = new FileDescriptor();
250
desc.stream = getStandardStream(fd);
252
catch (cli.System.MissingMethodException _)
254
desc.stream = cli.System.IO.Stream.Null;
259
private static cli.System.IO.Stream getStandardStream(int fd) throws cli.System.MissingMethodException
264
return cli.System.Console.OpenStandardInput();
266
return cli.System.Console.OpenStandardOutput();
268
return cli.System.Console.OpenStandardError();
274
// package private methods used by FIS, FOS and RAF.
276
int incrementAndGetUseCount() {
277
return useCount.incrementAndGet();
280
int decrementAndGetUseCount() {
281
return useCount.decrementAndGet();
284
void openReadOnly(String name) throws FileNotFoundException
286
open(name, FileMode.Open, FileAccess.Read);
289
void openWriteOnly(String name) throws FileNotFoundException
291
open(name, FileMode.Create, FileAccess.Write);
294
void openReadWrite(String name) throws FileNotFoundException
296
open(name, FileMode.OpenOrCreate, FileAccess.ReadWrite);
299
void openAppend(String name) throws FileNotFoundException
301
open(name, FileMode.Append, FileAccess.Write);
304
private static native cli.System.IO.Stream open(String name, FileMode fileMode, FileAccess fileAccess)
305
throws cli.System.IO.IOException,
306
cli.System.Security.SecurityException,
307
cli.System.UnauthorizedAccessException,
308
cli.System.ArgumentException,
309
cli.System.NotSupportedException;
311
private void open(String name, int fileMode, int fileAccess) throws FileNotFoundException
315
stream = open(name, FileMode.wrap(fileMode), FileAccess.wrap(fileAccess));
317
catch (cli.System.Security.SecurityException x1)
319
throw new SecurityException(x1.getMessage());
321
catch (cli.System.IO.IOException x2)
323
throw new FileNotFoundException(x2.getMessage());
325
catch (cli.System.UnauthorizedAccessException x3)
327
// this is caused by "name" being a directory instead of a file
328
// or by name being a read-only file
329
throw new FileNotFoundException(name + " (Access is denied)");
331
catch (cli.System.ArgumentException x4)
333
throw new FileNotFoundException(x4.getMessage());
335
catch (cli.System.NotSupportedException x5)
337
throw new FileNotFoundException(x5.getMessage());
341
private void checkOpen() throws IOException
345
throw new IOException("Stream Closed");
349
int read() throws IOException
354
if (false) throw new cli.System.NotSupportedException();
355
if (false) throw new cli.System.IO.IOException();
356
if (false) throw new cli.System.ObjectDisposedException(null);
357
return stream.ReadByte();
359
catch (cli.System.NotSupportedException x)
361
throw new IOException(x.getMessage());
363
catch (cli.System.IO.IOException x)
365
throw new IOException(x.getMessage());
367
catch (cli.System.ObjectDisposedException x)
369
throw new java.nio.channels.ClosedChannelException();
374
public int readBytes(byte buf[], int offset, int len) throws IOException
376
// NOTE we start by dereferencing buf, to make sure you get a NullPointerException first if you pass a null reference.
377
int bufLen = buf.length;
378
if ((offset < 0) || (offset > bufLen) || (len < 0) || (len > (bufLen - offset)))
380
throw new IndexOutOfBoundsException();
392
if (false) throw new cli.System.NotSupportedException();
393
if (false) throw new cli.System.IO.IOException();
394
if (false) throw new cli.System.ObjectDisposedException(null);
395
int count = stream.Read(buf, offset, len);
402
catch (cli.System.NotSupportedException x)
404
throw new IOException(x.getMessage());
406
catch (cli.System.IO.IOException x)
408
throw new IOException(x.getMessage());
410
catch (cli.System.ObjectDisposedException x)
412
throw new java.nio.channels.ClosedChannelException();
416
long skip(long n) throws IOException
419
if (!stream.get_CanSeek())
421
// in a somewhat bizar twist, for non-seekable streams the JDK throws an exception
422
throw new IOException("The handle is invalid");
426
if (false) throw new cli.System.IO.IOException();
427
if (false) throw new cli.System.NotSupportedException();
428
if (false) throw new cli.System.ObjectDisposedException(null);
429
long cur = stream.get_Position();
430
long end = stream.Seek(n, SeekOrigin.wrap(SeekOrigin.Current));
433
catch (cli.System.IO.IOException x)
435
throw new IOException(x.getMessage());
437
catch (cli.System.NotSupportedException x1)
439
// this means we have a broken Stream, because if CanSeek returns true, it must
440
// support Length and Position
441
throw new IOException(x1);
443
catch (cli.System.ObjectDisposedException x)
445
throw new java.nio.channels.ClosedChannelException();
450
public int available() throws IOException
455
if (false) throw new cli.System.IO.IOException();
456
if (false) throw new cli.System.NotSupportedException();
457
if (false) throw new cli.System.ObjectDisposedException(null);
458
if (stream.get_CanSeek())
460
return (int)Math.min(Integer.MAX_VALUE, Math.max(0, stream.get_Length() - stream.get_Position()));
464
catch (cli.System.IO.IOException x)
466
throw new IOException(x.getMessage());
468
catch (cli.System.NotSupportedException x1)
470
// this means we have a broken Stream, because if CanSeek returns true, it must
471
// support Length and Position
472
throw new IOException(x1);
474
catch (cli.System.ObjectDisposedException x)
476
throw new java.nio.channels.ClosedChannelException();
480
void write(int b) throws IOException
485
if (false) throw new cli.System.NotSupportedException();
486
if (false) throw new cli.System.IO.IOException();
487
if (false) throw new cli.System.ObjectDisposedException(null);
488
stream.WriteByte((byte)b);
489
// NOTE FileStream buffers the output, so we have to flush explicitly
492
catch (cli.System.NotSupportedException x)
494
throw new IOException(x.getMessage());
496
catch (cli.System.IO.IOException x)
498
throw new IOException(x.getMessage());
500
catch (cli.System.ObjectDisposedException x)
502
throw new java.nio.channels.ClosedChannelException();
507
public void writeBytes(byte buf[], int offset, int len) throws IOException
509
// NOTE we start by dereferencing buf, to make sure you get a NullPointerException first if you pass a null reference.
510
int bufLen = buf.length;
511
if ((offset < 0) || (offset > bufLen) || (len < 0) || (len > (bufLen - offset)))
513
throw new IndexOutOfBoundsException();
525
if (false) throw new cli.System.NotSupportedException();
526
if (false) throw new cli.System.IO.IOException();
527
if (false) throw new cli.System.ObjectDisposedException(null);
528
stream.Write(buf, offset, len);
529
// NOTE FileStream buffers the output, so we have to flush explicitly
532
catch (cli.System.NotSupportedException x)
534
throw new IOException(x.getMessage());
536
catch (cli.System.IO.IOException x)
538
throw new IOException(x.getMessage());
540
catch (cli.System.ObjectDisposedException x)
542
throw new java.nio.channels.ClosedChannelException();
547
public long getFilePointer() throws IOException
552
if (false) throw new cli.System.IO.IOException();
553
if (false) throw new cli.System.NotSupportedException();
554
if (false) throw new cli.System.ObjectDisposedException(null);
555
return stream.get_Position();
557
catch (cli.System.IO.IOException x)
559
throw new IOException(x.getMessage());
561
catch (cli.System.NotSupportedException x1)
563
throw new IOException(x1);
565
catch (cli.System.ObjectDisposedException x)
567
throw new java.nio.channels.ClosedChannelException();
572
public void seek(long newPosition) throws IOException
577
if (false) throw new cli.System.IO.IOException();
578
if (false) throw new cli.System.NotSupportedException();
579
if (false) throw new cli.System.ObjectDisposedException(null);
580
if (false) throw new cli.System.ArgumentOutOfRangeException();
581
stream.set_Position(newPosition);
583
catch (cli.System.IO.IOException x)
585
throw new IOException(x.getMessage());
587
catch (cli.System.NotSupportedException x1)
589
throw new IOException(x1);
591
catch (cli.System.ObjectDisposedException x)
593
throw new java.nio.channels.ClosedChannelException();
595
catch (cli.System.ArgumentOutOfRangeException _)
597
throw new IOException("Negative seek offset");
602
public long length() throws IOException
607
if (false) throw new cli.System.IO.IOException();
608
if (false) throw new cli.System.NotSupportedException();
609
if (false) throw new cli.System.ObjectDisposedException(null);
610
return stream.get_Length();
612
catch (cli.System.IO.IOException x)
614
throw new IOException(x.getMessage());
616
catch (cli.System.NotSupportedException x1)
618
throw new IOException(x1);
620
catch (cli.System.ObjectDisposedException x)
622
throw new java.nio.channels.ClosedChannelException();
627
public void setLength(long newLength) throws IOException
632
if (false) throw new cli.System.IO.IOException();
633
if (false) throw new cli.System.NotSupportedException();
634
if (false) throw new cli.System.ObjectDisposedException(null);
635
stream.SetLength(newLength);
637
catch (cli.System.IO.IOException x)
639
throw new IOException(x.getMessage());
641
catch (cli.System.NotSupportedException x1)
643
throw new IOException(x1);
645
catch (cli.System.ObjectDisposedException x)
647
throw new java.nio.channels.ClosedChannelException();
652
public void close() throws IOException
654
cli.System.IO.Stream s = stream;
663
public cli.System.IO.Stream getStream()
669
public static FileDescriptor fromStream(cli.System.IO.Stream stream)
671
FileDescriptor desc = new FileDescriptor();
672
desc.stream = stream;
677
public cli.System.Net.Sockets.Socket getSocket()
683
public void setSocket(cli.System.Net.Sockets.Socket socket)
685
this.socket = socket;
689
public void setSocketBlocking(boolean blocking) throws IOException
691
this.nonBlockingSocket = !blocking;
694
if (false) throw new cli.System.Net.Sockets.SocketException();
695
if (false) throw new cli.System.ObjectDisposedException("");
696
socket.set_Blocking(blocking);
698
catch (cli.System.Net.Sockets.SocketException x)
700
if (x.get_ErrorCode() == java.net.SocketUtil.WSAEINVAL)
702
// Work around for winsock issue. You can't set a socket to blocking if a connection request is pending,
703
// so we'll have to set the blocking again in SocketChannelImpl.checkConnect().
706
throw java.net.SocketUtil.convertSocketExceptionToIOException(x);
708
catch (cli.System.ObjectDisposedException _)
710
throw new java.net.SocketException("Socket is closed");
715
public boolean isSocketBlocking()
717
return !nonBlockingSocket;
721
public cli.System.IAsyncResult getAsyncResult()
727
public void setAsyncResult(cli.System.IAsyncResult asyncResult)
729
this.asyncResult = asyncResult;