2007-01-28 Michele Sandri <gpointorama@gmail.com>
[gcc.git] / libjava / gnu / java / nio / channels / natFileChannelWin32.cc
1 // natFileChannelImplWin32.cc - Native part of FileChannelImpl class.
2
3 /* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004 Free Software
4 Foundation, Inc.
5
6 This file is part of libgcj.
7
8 This software is copyrighted work licensed under the terms of the
9 Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
10 details. */
11
12 // FIXME: In order to support interrupting of IO operations, we
13 // need to change to use the windows asynchronous IO functions
14
15 #include <config.h>
16 #include <platform.h>
17
18 #include <gcj/cni.h>
19 #include <gcj/javaprims.h>
20 #include <jvm.h>
21
22 #include <stdio.h>
23
24 #include <gnu/gcj/RawData.h>
25 #include <gnu/java/nio/FileLockImpl.h>
26 #include <gnu/java/nio/channels/FileChannelImpl.h>
27 #include <java/io/FileNotFoundException.h>
28 #include <java/io/IOException.h>
29 #include <java/io/SyncFailedException.h>
30 #include <java/io/InterruptedIOException.h>
31 #include <java/io/EOFException.h>
32 #include <java/lang/ArrayIndexOutOfBoundsException.h>
33 #include <java/lang/NullPointerException.h>
34 #include <java/lang/System.h>
35 #include <java/lang/String.h>
36 #include <java/lang/Thread.h>
37 #include <java/nio/ByteBuffer.h>
38 #include <java/nio/MappedByteBufferImpl.h>
39 #include <java/nio/channels/FileChannel.h>
40 #include <java/nio/channels/FileLock.h>
41 #include <gnu/java/nio/channels/FileChannelImpl.h>
42
43 using gnu::gcj::RawData;
44 using java::io::IOException;
45 using java::nio::MappedByteBufferImpl;
46 using java::io::InterruptedIOException;
47 using java::io::FileNotFoundException;
48 using java::lang::ArrayIndexOutOfBoundsException;
49 using gnu::java::nio::channels::FileChannelImpl;
50
51 #undef STRICT
52
53 static bool testCanUseGetHandleInfo()
54 {
55 /* Test to see whether GetHandleInformation can be used
56 for console input or screen buffers. This is better
57 a kludgy OS version check. */
58 DWORD dwFlags;
59 return GetHandleInformation (GetStdHandle (STD_INPUT_HANDLE),
60 &dwFlags) != 0;
61 }
62
63 // FIXME: casting a FILE (pointer) to a jint will not work on Win64 --
64 // we should be using gnu.gcj.RawData's.
65
66 void
67 FileChannelImpl::init(void)
68 {
69 in = new FileChannelImpl((jint)(GetStdHandle (STD_INPUT_HANDLE)),
70 FileChannelImpl::READ);
71 out = new FileChannelImpl((jint)(GetStdHandle (STD_OUTPUT_HANDLE)),
72 FileChannelImpl::WRITE);
73 err = new FileChannelImpl((jint)(GetStdHandle (STD_ERROR_HANDLE)),
74 FileChannelImpl::WRITE);
75 }
76
77 #if 0
78 FileChannelImpl::sync (void) {
79 if (! FlushFileBuffers ((HANDLE)fd))
80 {
81 DWORD dwErrorCode = GetLastError ();
82 throw new SyncFailedException (_Jv_WinStrError (dwErrorCode));
83 }
84 }
85 #endif
86
87 jint
88 FileChannelImpl::open (jstring path, jint jflags) {
89
90 HANDLE handle = NULL;
91 DWORD access = 0;
92 DWORD create = OPEN_EXISTING;
93
94 JV_TEMP_STRING_WIN32(cpath, path)
95
96 JvAssert((jflags & READ) || (jflags & WRITE));
97
98 if ((jflags & READ) && (jflags & WRITE))
99 {
100 access = GENERIC_READ | GENERIC_WRITE;
101 if (jflags & EXCL)
102 create = CREATE_NEW; // this will raise error if file exists.
103 else
104 create = OPEN_ALWAYS; // equivalent to O_CREAT
105 }
106 else if (jflags & READ)
107 {
108 access = GENERIC_READ;
109 create = OPEN_EXISTING; // ignore EXCL
110 }
111 else
112 {
113 access = GENERIC_WRITE;
114 if (jflags & EXCL)
115 create = CREATE_NEW;
116 else if (jflags & APPEND)
117 create = OPEN_ALWAYS;
118 else
119 create = CREATE_ALWAYS;
120 }
121
122 handle = CreateFile(cpath, access, FILE_SHARE_READ | FILE_SHARE_WRITE,
123 NULL, create, 0, NULL);
124
125 if (handle == INVALID_HANDLE_VALUE)
126 {
127 DWORD dwErrorCode = GetLastError ();
128 throw new FileNotFoundException (_Jv_WinStrError (cpath, dwErrorCode));
129 }
130
131 // For APPEND mode, move the file pointer to the end of the file.
132 if (jflags & APPEND)
133 {
134 DWORD low = SetFilePointer (handle, 0, NULL, FILE_END);
135 if ((low == (DWORD) 0xffffffff) && (GetLastError () != NO_ERROR))
136 {
137 DWORD dwErrorCode = GetLastError ();
138 throw new FileNotFoundException (_Jv_WinStrError (cpath, dwErrorCode));
139 }
140 }
141
142 // Make this handle non-inheritable so that child
143 // processes don't inadvertently prevent us from
144 // closing this file.
145 _Jv_platform_close_on_exec (handle);
146
147 return (jint) handle;
148 }
149
150 void
151 FileChannelImpl::write (jint b)
152 {
153 DWORD bytesWritten;
154 jbyte buf = (jbyte)b;
155
156 if (WriteFile ((HANDLE)fd, &buf, 1, &bytesWritten, NULL))
157 {
158 if (::java::lang::Thread::interrupted())
159 {
160 InterruptedIOException *iioe = new InterruptedIOException (JvNewStringLatin1 ("write interrupted"));
161 iioe->bytesTransferred = bytesWritten;
162 throw iioe;
163 }
164 if (bytesWritten != 1)
165 _Jv_ThrowIOException ();
166 }
167 else
168 _Jv_ThrowIOException ();
169 // FIXME: loop until bytesWritten == 1
170 }
171
172 void
173 FileChannelImpl::write(jbyteArray b, jint offset, jint len)
174 {
175 if (! b)
176 throw new ::java::lang::NullPointerException;
177 if(offset < 0 || len < 0 || offset + len > JvGetArrayLength (b))
178 throw new ArrayIndexOutOfBoundsException;
179
180 jbyte *buf = elements (b) + offset;
181 DWORD bytesWritten;
182
183 if (WriteFile ((HANDLE)fd, buf, len, &bytesWritten, NULL))
184 {
185 if (::java::lang::Thread::interrupted())
186 {
187 InterruptedIOException *iioe = new InterruptedIOException (JvNewStringLatin1 ("write interrupted"));
188 iioe->bytesTransferred = bytesWritten;
189 throw iioe;
190 }
191 }
192 else
193 _Jv_ThrowIOException ();
194 // FIXME: loop until bytesWritten == len
195 }
196
197 void
198 FileChannelImpl::implCloseChannel (void)
199 {
200 HANDLE save = (HANDLE)fd;
201 fd = (jint)INVALID_HANDLE_VALUE;
202 if (! CloseHandle (save))
203 _Jv_ThrowIOException ();
204 }
205
206 void
207 FileChannelImpl::implTruncate (jlong size)
208 {
209 LONG liOrigFilePointer;
210 LONG liNewFilePointer;
211 LONG liEndFilePointer;
212
213 // Get the original file pointer.
214 if (SetFilePointer((HANDLE) fd, (LONG) 0, &liOrigFilePointer,
215 FILE_CURRENT) != (BOOL) 0
216 && (GetLastError() != NO_ERROR))
217 _Jv_ThrowIOException ();
218
219 // Get the length of the file.
220 if (SetFilePointer((HANDLE) fd, (LONG) 0, &liEndFilePointer,
221 FILE_END) != (BOOL) 0
222 && (GetLastError() != NO_ERROR))
223 _Jv_ThrowIOException ();
224
225 if ((jlong)liEndFilePointer == size)
226 {
227 // Restore the file pointer.
228 if (liOrigFilePointer != liEndFilePointer)
229 {
230 if (SetFilePointer((HANDLE) fd, liOrigFilePointer, &liNewFilePointer,
231 FILE_BEGIN) != (BOOL) 0
232 && (GetLastError() != NO_ERROR))
233 _Jv_ThrowIOException ();
234 }
235 return;
236 }
237
238 // Seek to the new end of file.
239 if (SetFilePointer((HANDLE) fd, (LONG) size, &liNewFilePointer,
240 FILE_BEGIN) != (BOOL) 0
241 && (GetLastError() != NO_ERROR))
242 _Jv_ThrowIOException ();
243
244 // Truncate the file at this point.
245 if (SetEndOfFile((HANDLE) fd) != (BOOL) 0 && (GetLastError() != NO_ERROR))
246 _Jv_ThrowIOException ();
247
248 if (liOrigFilePointer < liNewFilePointer)
249 {
250 // Restore the file pointer.
251 if (SetFilePointer((HANDLE) fd, liOrigFilePointer, &liNewFilePointer,
252 FILE_BEGIN) != (BOOL) 0
253 && (GetLastError() != NO_ERROR))
254 _Jv_ThrowIOException ();
255 }
256 }
257
258 void
259 FileChannelImpl::seek (jlong newPos)
260 {
261 LONG high = pos >> 32;
262 DWORD low = SetFilePointer ((HANDLE)fd, (DWORD)(0xffffffff & newPos), &high, FILE_BEGIN);
263 if ((low == 0xffffffff) && (GetLastError () != NO_ERROR))
264 _Jv_ThrowIOException ();
265 }
266
267 jlong
268 FileChannelImpl::implPosition (void)
269 {
270 LONG high = 0;
271 DWORD low = SetFilePointer ((HANDLE)fd, 0, &high, FILE_CURRENT);
272 if ((low == 0xffffffff) && (GetLastError() != NO_ERROR))
273 _Jv_ThrowIOException ();
274 return (((jlong)high) << 32L) | (jlong)low;
275 }
276
277 jlong
278 FileChannelImpl::size (void)
279 {
280 DWORD high;
281 DWORD low;
282
283 low = GetFileSize ((HANDLE)fd, &high);
284 // FIXME: Error checking
285 return (((jlong)high) << 32L) | (jlong)low;
286 }
287
288 jint
289 FileChannelImpl::read (void)
290 {
291 CHAR buf;
292 DWORD read;
293
294 if (! ReadFile ((HANDLE)fd, &buf, 1, &read, NULL))
295 {
296 if (GetLastError () == ERROR_BROKEN_PIPE)
297 return -1;
298 else
299 _Jv_ThrowIOException ();
300 }
301
302 if (! read)
303 return -1;
304 else
305 return (jint)(buf & 0xff);
306 }
307
308 jint
309 FileChannelImpl::read (jbyteArray buffer, jint offset, jint count)
310 {
311 if (! buffer)
312 throw new ::java::lang::NullPointerException;
313
314 jsize bsize = JvGetArrayLength (buffer);
315 if (offset < 0 || count < 0 || offset + count > bsize)
316 throw new ArrayIndexOutOfBoundsException;
317
318 // Must return 0 if an attempt is made to read 0 bytes.
319 if (count == 0)
320 return 0;
321
322 jbyte *bytes = elements (buffer) + offset;
323
324 DWORD read;
325 if (! ReadFile((HANDLE)fd, bytes, count, &read, NULL))
326 {
327 if (GetLastError () == ERROR_BROKEN_PIPE)
328 return -1;
329 else
330 _Jv_ThrowIOException ();
331 }
332
333 if (read == 0) return -1;
334
335 return (jint)read;
336 }
337
338 jint
339 FileChannelImpl::available (void)
340 {
341 // FIXME:
342 return size() - position();
343 }
344
345 jboolean
346 FileChannelImpl::lock (jlong pos, jlong len, jboolean shared, jboolean wait)
347 {
348 DWORD flags = 0;
349 OVERLAPPED ovlpd;
350
351 ZeroMemory(&ovlpd,sizeof(OVERLAPPED));
352
353 if(!shared)
354 flags |= LOCKFILE_EXCLUSIVE_LOCK;
355 if(!wait)
356 flags |= LOCKFILE_FAIL_IMMEDIATELY;
357
358 ovlpd.Offset = (DWORD)pos;
359 ovlpd.OffsetHigh = pos>>32;
360
361 DWORD lenlow = (DWORD)len;
362 DWORD lenhigh = len>>32;
363
364 BOOL ret = LockFileEx((HANDLE)fd,flags,0,lenlow,lenhigh,&ovlpd);
365
366 if(ret==ERROR_IO_PENDING && !shared && wait)
367 ret = GetOverlappedResult((HANDLE)fd,&ovlpd,NULL,wait);
368
369 if(!ret)
370 _Jv_ThrowIOException(GetLastError());
371
372 return true;
373 }
374
375 void
376 FileChannelImpl::unlock (jlong pos, jlong len)
377 {
378 OVERLAPPED ovlpd;
379
380 ZeroMemory(&ovlpd,sizeof(OVERLAPPED));
381
382 ovlpd.Offset = (DWORD)pos;
383 ovlpd.OffsetHigh = pos>>32;
384
385 DWORD lenlow = (DWORD)len;
386 DWORD lenhigh = len>>32;
387
388 BOOL ret = UnlockFileEx((HANDLE)fd,0,lenlow,lenhigh,&ovlpd);
389
390 if(!ret)
391 _Jv_ThrowIOException(GetLastError());
392 }
393
394 java::nio::MappedByteBuffer *
395 FileChannelImpl::mapImpl (jchar mmode, jlong position, jint size)
396 {
397 SYSTEM_INFO siSysInfo;
398 GetSystemInfo(&siSysInfo);
399 DWORD page_size = siSysInfo.dwPageSize;
400 jlong offset = position & ~(page_size-1);
401 jint align = position - offset;
402 jlong high = position + size;
403 jlong max_size;
404 if (mmode == '+')
405 max_size = high - offset;
406 else
407 max_size = 0;
408 DWORD access, protect;
409 if (mmode == 'r')
410 {
411 access = FILE_MAP_READ;
412 protect = PAGE_READONLY;
413 }
414 else if (mmode == '+')
415 {
416 access = FILE_MAP_WRITE;
417 protect = PAGE_READWRITE;
418 }
419 else
420 {
421 access = FILE_MAP_COPY;
422 protect = PAGE_WRITECOPY;
423 }
424 HANDLE hFileMapping = CreateFileMapping((HANDLE) fd,
425 (LPSECURITY_ATTRIBUTES) NULL,
426 protect,
427 (DWORD) (max_size >> 32),
428 (DWORD) max_size,
429 (LPCTSTR) NULL);
430 if (hFileMapping == NULL)
431 throw new IOException();
432 void *ptr = MapViewOfFile(hFileMapping, access,
433 (DWORD) (offset >> 32), (DWORD) offset,
434 (SIZE_T) (high - offset));
435 if (ptr == NULL)
436 throw new IOException();
437 MappedByteBufferImpl *buf
438 = new MappedByteBufferImpl((RawData *) ((char *) ptr + align),
439 size, mode == 'r');
440 buf->implPtr = reinterpret_cast<RawData*> (ptr);
441 buf->implLen = (jlong) (size_t) hFileMapping;
442 return buf;
443 }
444
445 void
446 MappedByteBufferImpl::unmapImpl ()
447 {
448 UnmapViewOfFile((void*)implPtr);
449 CloseHandle((HANDLE) (size_t) implLen);
450 }
451
452 void
453 MappedByteBufferImpl::loadImpl ()
454 {
455 }
456
457 jboolean
458 MappedByteBufferImpl::isLoadedImpl ()
459 {
460 return true;
461 }
462
463 void
464 MappedByteBufferImpl::forceImpl ()
465 {
466 }