blob: 7157a7baa5113943d196759c39543333cd34dbd4 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 1998-2006 Sun Microsystems, Inc. All Rights Reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
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. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun in the LICENSE file that accompanied this code.
10 *
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).
16 *
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.
20 *
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26#include <assert.h>
27#include <stdio.h>
28#include <stdlib.h>
29#include <ctype.h>
30#include <direct.h>
31#include <windows.h>
32#include <io.h>
33
34#include "jvm.h"
35#include "jni.h"
36#include "jni_util.h"
37#include "jlong.h"
38#include "io_util.h"
39#include "dirent_md.h"
40#include "java_io_FileSystem.h"
41
42/* This macro relies upon the fact that JNU_GetStringPlatformChars always makes
43 a copy of the string */
44
45#define WITH_NATIVE_PATH(env, object, id, var) \
46 WITH_FIELD_PLATFORM_STRING(env, object, id, var) \
47 JVM_NativePath((char *)var);
48
49#define END_NATIVE_PATH(env, var) END_PLATFORM_STRING(env, var)
50
51
52static struct {
53 jfieldID path;
54} ids;
55
56JNIEXPORT void JNICALL
57Java_java_io_Win32FileSystem_initIDs(JNIEnv *env, jclass cls)
58{
59 jclass fileClass = (*env)->FindClass(env, "java/io/File");
60 if (!fileClass) return;
61 ids.path = (*env)->GetFieldID(env, fileClass,
62 "path", "Ljava/lang/String;");
63}
64
65
66/* -- Path operations -- */
67
68
69extern int canonicalize(char *path, const char *out, int len);
70extern int canonicalizeWithPrefix(const char* canonicalPrefix, const char *pathWithCanonicalPrefix, char *out, int len);
71
72JNIEXPORT jstring JNICALL
73Java_java_io_Win32FileSystem_canonicalize0(JNIEnv *env, jobject this,
74 jstring pathname)
75{
76 jstring rv = NULL;
77
78 WITH_PLATFORM_STRING(env, pathname, path) {
79 char canonicalPath[JVM_MAXPATHLEN];
80 if (canonicalize(JVM_NativePath((char *)path),
81 canonicalPath, JVM_MAXPATHLEN) < 0) {
82 JNU_ThrowIOExceptionWithLastError(env, "Bad pathname");
83 } else {
84 rv = JNU_NewStringPlatform(env, canonicalPath);
85 }
86 } END_PLATFORM_STRING(env, path);
87 return rv;
88}
89
90
91JNIEXPORT jstring JNICALL
92Java_java_io_Win32FileSystem_canonicalizeWithPrefix0(JNIEnv *env, jobject this,
93 jstring canonicalPrefixString,
94 jstring pathWithCanonicalPrefixString)
95{
96 jstring rv = NULL;
97 char canonicalPath[JVM_MAXPATHLEN];
98
99 WITH_PLATFORM_STRING(env, canonicalPrefixString, canonicalPrefix) {
100 WITH_PLATFORM_STRING(env, pathWithCanonicalPrefixString, pathWithCanonicalPrefix) {
101 if (canonicalizeWithPrefix(canonicalPrefix,
102 pathWithCanonicalPrefix,
103 canonicalPath, JVM_MAXPATHLEN) < 0) {
104 JNU_ThrowIOExceptionWithLastError(env, "Bad pathname");
105 } else {
106 rv = JNU_NewStringPlatform(env, canonicalPath);
107 }
108 } END_PLATFORM_STRING(env, pathWithCanonicalPrefix);
109 } END_PLATFORM_STRING(env, canonicalPrefix);
110 return rv;
111}
112
113
114
115/* -- Attribute accessors -- */
116
117/* Check whether or not the file name in "path" is a Windows reserved
118 device name (CON, PRN, AUX, NUL, COM[1-9], LPT[1-9]) based on the
119 returned result from GetFullPathName. If the file name in the path
120 is indeed a reserved device name GetFuulPathName returns
121 "\\.\[ReservedDeviceName]".
122 */
123BOOL isReservedDeviceName(const char* path) {
124#define BUFSIZE 9
125 char buf[BUFSIZE];
126 char *lpf = NULL;
127 DWORD retLen = GetFullPathName(path,
128 BUFSIZE,
129 buf,
130 &lpf);
131 if ((retLen == BUFSIZE - 1 || retLen == BUFSIZE - 2) &&
132 buf[0] == '\\' && buf[1] == '\\' &&
133 buf[2] == '.' && buf[3] == '\\') {
134 char* dname = _strupr(buf + 4);
135 if (strcmp(dname, "CON") == 0 ||
136 strcmp(dname, "PRN") == 0 ||
137 strcmp(dname, "AUX") == 0 ||
138 strcmp(dname, "NUL") == 0)
139 return TRUE;
140 if ((strncmp(dname, "COM", 3) == 0 ||
141 strncmp(dname, "LPT", 3) == 0) &&
142 dname[3] - '0' > 0 &&
143 dname[3] - '0' <= 9)
144 return TRUE;
145 }
146 return FALSE;
147}
148
149JNIEXPORT jint JNICALL
150Java_java_io_Win32FileSystem_getBooleanAttributes(JNIEnv *env, jobject this,
151 jobject file)
152{
153 jint rv = 0;
154
155 WITH_NATIVE_PATH(env, file, ids.path, path) {
156 WIN32_FILE_ATTRIBUTE_DATA wfad;
157 if (!isReservedDeviceName(path) &&
158 GetFileAttributesEx(path, GetFileExInfoStandard, &wfad)) {
159 rv = (java_io_FileSystem_BA_EXISTS
160 | ((wfad.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
161 ? java_io_FileSystem_BA_DIRECTORY
162 : java_io_FileSystem_BA_REGULAR)
163 | ((wfad.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN)
164 ? java_io_FileSystem_BA_HIDDEN : 0));
165 }
166 } END_NATIVE_PATH(env, path);
167 return rv;
168}
169
170
171JNIEXPORT jboolean JNICALL
172Java_java_io_Win32FileSystem_checkAccess(JNIEnv *env, jobject this,
173 jobject file, jint a)
174{
175 jboolean rv = JNI_FALSE;
176 int mode;
177 switch (a) {
178 case java_io_FileSystem_ACCESS_READ:
179 case java_io_FileSystem_ACCESS_EXECUTE:
180 mode = 4;
181 break;
182 case java_io_FileSystem_ACCESS_WRITE:
183 mode = 2;
184 break;
185 default: assert(0);
186 }
187 WITH_NATIVE_PATH(env, file, ids.path, path) {
188 if (access(path, mode) == 0) {
189 rv = JNI_TRUE;
190 }
191 } END_NATIVE_PATH(env, path);
192 return rv;
193}
194
195JNIEXPORT jboolean JNICALL
196Java_java_io_Win32FileSystem_setPermission(JNIEnv *env, jobject this,
197 jobject file,
198 jint access,
199 jboolean enable,
200 jboolean owneronly)
201{
202 jboolean rv = JNI_FALSE;
203 if (access == java_io_FileSystem_ACCESS_READ ||
204 access == java_io_FileSystem_ACCESS_EXECUTE) {
205 return enable;
206 }
207 WITH_NATIVE_PATH(env, file, ids.path, path) {
208 DWORD a;
209 a = GetFileAttributes(path);
210 if (a != INVALID_FILE_ATTRIBUTES) {
211 if (enable)
212 a = a & ~FILE_ATTRIBUTE_READONLY;
213 else
214 a = a | FILE_ATTRIBUTE_READONLY;
215 if (SetFileAttributes(path, a))
216 rv = JNI_TRUE;
217 }
218 } END_NATIVE_PATH(env, path);
219 return rv;
220}
221
222JNIEXPORT jlong JNICALL
223Java_java_io_Win32FileSystem_getLastModifiedTime(JNIEnv *env, jobject this,
224 jobject file)
225{
226 jlong rv = 0;
227 WITH_NATIVE_PATH(env, file, ids.path, path) {
228 /* Win95, Win98, WinME */
229 WIN32_FIND_DATA fd;
230 jlong temp = 0;
231 LARGE_INTEGER modTime;
232 HANDLE h = FindFirstFile(path, &fd);
233 if (h != INVALID_HANDLE_VALUE) {
234 FindClose(h);
235 modTime.LowPart = (DWORD) fd.ftLastWriteTime.dwLowDateTime;
236 modTime.HighPart = (LONG) fd.ftLastWriteTime.dwHighDateTime;
237 rv = modTime.QuadPart / 10000;
238 rv -= 11644473600000;
239 }
240 } END_NATIVE_PATH(env, path);
241 return rv;
242}
243
244JNIEXPORT jlong JNICALL
245Java_java_io_Win32FileSystem_getLength(JNIEnv *env, jobject this,
246 jobject file)
247{
248 jlong rv = 0;
249
250 WITH_NATIVE_PATH(env, file, ids.path, path) {
251 struct _stati64 sb;
252 if (_stati64(path, &sb) == 0) {
253 rv = sb.st_size;
254 }
255 } END_NATIVE_PATH(env, path);
256 return rv;
257}
258
259
260/* -- File operations -- */
261
262
263JNIEXPORT jboolean JNICALL
264Java_java_io_Win32FileSystem_createFileExclusively(JNIEnv *env, jclass cls,
265 jstring pathname)
266{
267 jboolean rv = JNI_FALSE;
268 DWORD a;
269
270 WITH_PLATFORM_STRING(env, pathname, path) {
271 int orv;
272 int error;
273 JVM_NativePath((char *)path);
274 orv = JVM_Open(path, JVM_O_RDWR | JVM_O_CREAT | JVM_O_EXCL, 0666);
275 if (orv < 0) {
276 if (orv != JVM_EEXIST) {
277 error = GetLastError();
278
279 // If a directory by the named path already exists,
280 // return false (behavior of solaris and linux) instead of
281 // throwing an exception
282 a = GetFileAttributes(path);
283
284 if ((a == INVALID_FILE_ATTRIBUTES) ||
285 !(a & FILE_ATTRIBUTE_DIRECTORY)) {
286 SetLastError(error);
287 JNU_ThrowIOExceptionWithLastError(env, path);
288 }
289 }
290 } else {
291 JVM_Close(orv);
292 rv = JNI_TRUE;
293 }
294 } END_PLATFORM_STRING(env, path);
295 return rv;
296}
297
298
299static int
300removeFileOrDirectory(const char *path) /* Returns 0 on success */
301{
302 DWORD a;
303
304 SetFileAttributes(path, 0);
305 a = GetFileAttributes(path);
306 if (a == INVALID_FILE_ATTRIBUTES) {
307 return 1;
308 } else if (a & FILE_ATTRIBUTE_DIRECTORY) {
309 return !RemoveDirectory(path);
310 } else {
311 return !DeleteFile(path);
312 }
313}
314
315
316JNIEXPORT jboolean JNICALL
317Java_java_io_Win32FileSystem_delete0(JNIEnv *env, jobject this,
318 jobject file)
319{
320 jboolean rv = JNI_FALSE;
321
322 WITH_NATIVE_PATH(env, file, ids.path, path) {
323 if (removeFileOrDirectory(path) == 0) {
324 rv = JNI_TRUE;
325 }
326 } END_NATIVE_PATH(env, path);
327 return rv;
328}
329
330
331/* ## Clean this up to use direct Win32 calls */
332
333JNIEXPORT jobjectArray JNICALL
334Java_java_io_Win32FileSystem_list(JNIEnv *env, jobject this,
335 jobject file)
336{
337 DIR *dir;
338 struct dirent *ptr;
339 int len, maxlen;
340 jobjectArray rv, old;
341
342 WITH_NATIVE_PATH(env, file, ids.path, path) {
343 dir = opendir(path);
344 } END_NATIVE_PATH(env, path);
345 if (dir == NULL) return NULL;
346
347 /* Allocate an initial String array */
348 len = 0;
349 maxlen = 16;
350 rv = (*env)->NewObjectArray(env, maxlen, JNU_ClassString(env), NULL);
351 if (rv == NULL) goto error;
352
353 /* Scan the directory */
354 while ((ptr = readdir(dir)) != NULL) {
355 jstring name;
356 if (!strcmp(ptr->d_name, ".") || !strcmp(ptr->d_name, ".."))
357 continue;
358 if (len == maxlen) {
359 old = rv;
360 rv = (*env)->NewObjectArray(env, maxlen <<= 1,
361 JNU_ClassString(env), NULL);
362 if (rv == NULL) goto error;
363 if (JNU_CopyObjectArray(env, rv, old, len) < 0) goto error;
364 (*env)->DeleteLocalRef(env, old);
365 }
366 name = JNU_NewStringPlatform(env, ptr->d_name);
367 if (name == NULL) goto error;
368 (*env)->SetObjectArrayElement(env, rv, len++, name);
369 (*env)->DeleteLocalRef(env, name);
370 }
371 closedir(dir);
372
373 /* Copy the final results into an appropriately-sized array */
374 old = rv;
375 rv = (*env)->NewObjectArray(env, len, JNU_ClassString(env), NULL);
376 if (rv == NULL) goto error;
377 if (JNU_CopyObjectArray(env, rv, old, len) < 0) goto error;
378 return rv;
379
380 error:
381 closedir(dir);
382 return NULL;
383}
384
385
386JNIEXPORT jboolean JNICALL
387Java_java_io_Win32FileSystem_createDirectory(JNIEnv *env, jobject this,
388 jobject file)
389{
390 jboolean rv = JNI_FALSE;
391
392 WITH_NATIVE_PATH(env, file, ids.path, path) {
393 if (mkdir(path) == 0) {
394 rv = JNI_TRUE;
395 }
396 } END_NATIVE_PATH(env, path);
397 return rv;
398}
399
400
401JNIEXPORT jboolean JNICALL
402Java_java_io_Win32FileSystem_rename0(JNIEnv *env, jobject this,
403 jobject from, jobject to)
404{
405 jboolean rv = JNI_FALSE;
406
407 WITH_NATIVE_PATH(env, from, ids.path, fromPath) {
408 WITH_NATIVE_PATH(env, to, ids.path, toPath) {
409 if (rename(fromPath, toPath) == 0) {
410 rv = JNI_TRUE;
411 }
412 } END_NATIVE_PATH(env, toPath);
413 } END_NATIVE_PATH(env, fromPath);
414 return rv;
415}
416
417
418JNIEXPORT jboolean JNICALL
419Java_java_io_Win32FileSystem_setLastModifiedTime(JNIEnv *env, jobject this,
420 jobject file, jlong time)
421{
422 jboolean rv = JNI_FALSE;
423
424 WITH_NATIVE_PATH(env, file, ids.path, path) {
425 HANDLE h;
426 h = CreateFile(path, GENERIC_WRITE, 0, NULL, OPEN_EXISTING,
427 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS, 0);
428 if (h != INVALID_HANDLE_VALUE) {
429 LARGE_INTEGER modTime;
430 FILETIME t;
431 modTime.QuadPart = (time + 11644473600000L) * 10000L;
432 t.dwLowDateTime = (DWORD)modTime.LowPart;
433 t.dwHighDateTime = (DWORD)modTime.HighPart;
434 if (SetFileTime(h, NULL, NULL, &t)) {
435 rv = JNI_TRUE;
436 }
437 CloseHandle(h);
438 }
439 } END_NATIVE_PATH(env, path);
440
441 return rv;
442}
443
444
445JNIEXPORT jboolean JNICALL
446Java_java_io_Win32FileSystem_setReadOnly(JNIEnv *env, jobject this,
447 jobject file)
448{
449 jboolean rv = JNI_FALSE;
450
451 WITH_NATIVE_PATH(env, file, ids.path, path) {
452 DWORD a;
453 a = GetFileAttributes(path);
454 if (a != INVALID_FILE_ATTRIBUTES) {
455 if (SetFileAttributes(path, a | FILE_ATTRIBUTE_READONLY))
456 rv = JNI_TRUE;
457 }
458 } END_NATIVE_PATH(env, path);
459 return rv;
460}
461
462
463/* -- Filesystem interface -- */
464
465
466JNIEXPORT jobject JNICALL
467Java_java_io_Win32FileSystem_getDriveDirectory(JNIEnv *env, jclass ignored,
468 jint drive)
469{
470 char buf[_MAX_PATH];
471 char *p = _getdcwd(drive, buf, sizeof(buf));
472 if (p == NULL) return NULL;
473 if (isalpha(*p) && (p[1] == ':')) p += 2;
474 return JNU_NewStringPlatform(env, p);
475}
476
477
478JNIEXPORT jint JNICALL
479Java_java_io_Win32FileSystem_listRoots0(JNIEnv *env, jclass ignored)
480{
481 return GetLogicalDrives();
482}
483
484JNIEXPORT jlong JNICALL
485Java_java_io_Win32FileSystem_getSpace0(JNIEnv *env, jobject this,
486 jobject file, jint t)
487{
488 jlong rv = 0L;
489
490 WITH_NATIVE_PATH(env, file, ids.path, path) {
491 ULARGE_INTEGER totalSpace, freeSpace, usableSpace;
492 if (GetDiskFreeSpaceEx(path, &usableSpace, &totalSpace, &freeSpace)) {
493 switch(t) {
494 case java_io_FileSystem_SPACE_TOTAL:
495 rv = long_to_jlong(totalSpace.QuadPart);
496 break;
497 case java_io_FileSystem_SPACE_FREE:
498 rv = long_to_jlong(freeSpace.QuadPart);
499 break;
500 case java_io_FileSystem_SPACE_USABLE:
501 rv = long_to_jlong(usableSpace.QuadPart);
502 break;
503 default:
504 assert(0);
505 }
506 }
507 } END_NATIVE_PATH(env, path);
508 return rv;
509}