0N/A/*
2362N/A * Copyright (c) 1998, 2006, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
0N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
0N/A */
0N/A
0N/A#include <assert.h>
0N/A#include <stdio.h>
0N/A#include <stdlib.h>
0N/A#include <ctype.h>
0N/A#include <direct.h>
0N/A#include <windows.h>
0N/A#include <io.h>
0N/A
0N/A#include "jvm.h"
0N/A#include "jni.h"
0N/A#include "jni_util.h"
0N/A#include "jlong.h"
0N/A#include "io_util.h"
0N/A#include "dirent_md.h"
0N/A#include "java_io_FileSystem.h"
0N/A
0N/A/* This macro relies upon the fact that JNU_GetStringPlatformChars always makes
0N/A a copy of the string */
0N/A
0N/A#define WITH_NATIVE_PATH(env, object, id, var) \
0N/A WITH_FIELD_PLATFORM_STRING(env, object, id, var) \
0N/A JVM_NativePath((char *)var);
0N/A
0N/A#define END_NATIVE_PATH(env, var) END_PLATFORM_STRING(env, var)
0N/A
0N/A
0N/Astatic struct {
0N/A jfieldID path;
0N/A} ids;
0N/A
0N/AJNIEXPORT void JNICALL
0N/AJava_java_io_Win32FileSystem_initIDs(JNIEnv *env, jclass cls)
0N/A{
0N/A jclass fileClass = (*env)->FindClass(env, "java/io/File");
0N/A if (!fileClass) return;
0N/A ids.path = (*env)->GetFieldID(env, fileClass,
0N/A "path", "Ljava/lang/String;");
0N/A}
0N/A
0N/A
0N/A/* -- Path operations -- */
0N/A
0N/A
0N/Aextern int canonicalize(char *path, const char *out, int len);
0N/Aextern int canonicalizeWithPrefix(const char* canonicalPrefix, const char *pathWithCanonicalPrefix, char *out, int len);
0N/A
0N/AJNIEXPORT jstring JNICALL
0N/AJava_java_io_Win32FileSystem_canonicalize0(JNIEnv *env, jobject this,
0N/A jstring pathname)
0N/A{
0N/A jstring rv = NULL;
0N/A
0N/A WITH_PLATFORM_STRING(env, pathname, path) {
0N/A char canonicalPath[JVM_MAXPATHLEN];
0N/A if (canonicalize(JVM_NativePath((char *)path),
0N/A canonicalPath, JVM_MAXPATHLEN) < 0) {
0N/A JNU_ThrowIOExceptionWithLastError(env, "Bad pathname");
0N/A } else {
0N/A rv = JNU_NewStringPlatform(env, canonicalPath);
0N/A }
0N/A } END_PLATFORM_STRING(env, path);
0N/A return rv;
0N/A}
0N/A
0N/A
0N/AJNIEXPORT jstring JNICALL
0N/AJava_java_io_Win32FileSystem_canonicalizeWithPrefix0(JNIEnv *env, jobject this,
0N/A jstring canonicalPrefixString,
0N/A jstring pathWithCanonicalPrefixString)
0N/A{
0N/A jstring rv = NULL;
0N/A char canonicalPath[JVM_MAXPATHLEN];
0N/A
0N/A WITH_PLATFORM_STRING(env, canonicalPrefixString, canonicalPrefix) {
0N/A WITH_PLATFORM_STRING(env, pathWithCanonicalPrefixString, pathWithCanonicalPrefix) {
0N/A if (canonicalizeWithPrefix(canonicalPrefix,
0N/A pathWithCanonicalPrefix,
0N/A canonicalPath, JVM_MAXPATHLEN) < 0) {
0N/A JNU_ThrowIOExceptionWithLastError(env, "Bad pathname");
0N/A } else {
0N/A rv = JNU_NewStringPlatform(env, canonicalPath);
0N/A }
0N/A } END_PLATFORM_STRING(env, pathWithCanonicalPrefix);
0N/A } END_PLATFORM_STRING(env, canonicalPrefix);
0N/A return rv;
0N/A}
0N/A
0N/A
0N/A
0N/A/* -- Attribute accessors -- */
0N/A
0N/A/* Check whether or not the file name in "path" is a Windows reserved
0N/A device name (CON, PRN, AUX, NUL, COM[1-9], LPT[1-9]) based on the
0N/A returned result from GetFullPathName. If the file name in the path
0N/A is indeed a reserved device name GetFuulPathName returns
0N/A "\\.\[ReservedDeviceName]".
0N/A */
0N/ABOOL isReservedDeviceName(const char* path) {
0N/A#define BUFSIZE 9
0N/A char buf[BUFSIZE];
0N/A char *lpf = NULL;
0N/A DWORD retLen = GetFullPathName(path,
0N/A BUFSIZE,
0N/A buf,
0N/A &lpf);
0N/A if ((retLen == BUFSIZE - 1 || retLen == BUFSIZE - 2) &&
0N/A buf[0] == '\\' && buf[1] == '\\' &&
0N/A buf[2] == '.' && buf[3] == '\\') {
0N/A char* dname = _strupr(buf + 4);
0N/A if (strcmp(dname, "CON") == 0 ||
0N/A strcmp(dname, "PRN") == 0 ||
0N/A strcmp(dname, "AUX") == 0 ||
0N/A strcmp(dname, "NUL") == 0)
0N/A return TRUE;
0N/A if ((strncmp(dname, "COM", 3) == 0 ||
0N/A strncmp(dname, "LPT", 3) == 0) &&
0N/A dname[3] - '0' > 0 &&
0N/A dname[3] - '0' <= 9)
0N/A return TRUE;
0N/A }
0N/A return FALSE;
0N/A}
0N/A
0N/AJNIEXPORT jint JNICALL
0N/AJava_java_io_Win32FileSystem_getBooleanAttributes(JNIEnv *env, jobject this,
0N/A jobject file)
0N/A{
0N/A jint rv = 0;
0N/A
0N/A WITH_NATIVE_PATH(env, file, ids.path, path) {
0N/A WIN32_FILE_ATTRIBUTE_DATA wfad;
0N/A if (!isReservedDeviceName(path) &&
0N/A GetFileAttributesEx(path, GetFileExInfoStandard, &wfad)) {
0N/A rv = (java_io_FileSystem_BA_EXISTS
0N/A | ((wfad.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
0N/A ? java_io_FileSystem_BA_DIRECTORY
0N/A : java_io_FileSystem_BA_REGULAR)
0N/A | ((wfad.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN)
0N/A ? java_io_FileSystem_BA_HIDDEN : 0));
0N/A }
0N/A } END_NATIVE_PATH(env, path);
0N/A return rv;
0N/A}
0N/A
0N/A
0N/AJNIEXPORT jboolean JNICALL
0N/AJava_java_io_Win32FileSystem_checkAccess(JNIEnv *env, jobject this,
0N/A jobject file, jint a)
0N/A{
0N/A jboolean rv = JNI_FALSE;
0N/A int mode;
0N/A switch (a) {
0N/A case java_io_FileSystem_ACCESS_READ:
0N/A case java_io_FileSystem_ACCESS_EXECUTE:
0N/A mode = 4;
0N/A break;
0N/A case java_io_FileSystem_ACCESS_WRITE:
0N/A mode = 2;
0N/A break;
0N/A default: assert(0);
0N/A }
0N/A WITH_NATIVE_PATH(env, file, ids.path, path) {
0N/A if (access(path, mode) == 0) {
0N/A rv = JNI_TRUE;
0N/A }
0N/A } END_NATIVE_PATH(env, path);
0N/A return rv;
0N/A}
0N/A
0N/AJNIEXPORT jboolean JNICALL
0N/AJava_java_io_Win32FileSystem_setPermission(JNIEnv *env, jobject this,
0N/A jobject file,
0N/A jint access,
0N/A jboolean enable,
0N/A jboolean owneronly)
0N/A{
0N/A jboolean rv = JNI_FALSE;
0N/A if (access == java_io_FileSystem_ACCESS_READ ||
0N/A access == java_io_FileSystem_ACCESS_EXECUTE) {
0N/A return enable;
0N/A }
0N/A WITH_NATIVE_PATH(env, file, ids.path, path) {
0N/A DWORD a;
0N/A a = GetFileAttributes(path);
0N/A if (a != INVALID_FILE_ATTRIBUTES) {
0N/A if (enable)
0N/A a = a & ~FILE_ATTRIBUTE_READONLY;
0N/A else
0N/A a = a | FILE_ATTRIBUTE_READONLY;
0N/A if (SetFileAttributes(path, a))
0N/A rv = JNI_TRUE;
0N/A }
0N/A } END_NATIVE_PATH(env, path);
0N/A return rv;
0N/A}
0N/A
0N/AJNIEXPORT jlong JNICALL
0N/AJava_java_io_Win32FileSystem_getLastModifiedTime(JNIEnv *env, jobject this,
0N/A jobject file)
0N/A{
0N/A jlong rv = 0;
0N/A WITH_NATIVE_PATH(env, file, ids.path, path) {
0N/A /* Win95, Win98, WinME */
0N/A WIN32_FIND_DATA fd;
0N/A jlong temp = 0;
0N/A LARGE_INTEGER modTime;
0N/A HANDLE h = FindFirstFile(path, &fd);
0N/A if (h != INVALID_HANDLE_VALUE) {
0N/A FindClose(h);
0N/A modTime.LowPart = (DWORD) fd.ftLastWriteTime.dwLowDateTime;
0N/A modTime.HighPart = (LONG) fd.ftLastWriteTime.dwHighDateTime;
0N/A rv = modTime.QuadPart / 10000;
0N/A rv -= 11644473600000;
0N/A }
0N/A } END_NATIVE_PATH(env, path);
0N/A return rv;
0N/A}
0N/A
0N/AJNIEXPORT jlong JNICALL
0N/AJava_java_io_Win32FileSystem_getLength(JNIEnv *env, jobject this,
0N/A jobject file)
0N/A{
0N/A jlong rv = 0;
0N/A
0N/A WITH_NATIVE_PATH(env, file, ids.path, path) {
0N/A struct _stati64 sb;
0N/A if (_stati64(path, &sb) == 0) {
0N/A rv = sb.st_size;
0N/A }
0N/A } END_NATIVE_PATH(env, path);
0N/A return rv;
0N/A}
0N/A
0N/A
0N/A/* -- File operations -- */
0N/A
0N/A
0N/AJNIEXPORT jboolean JNICALL
0N/AJava_java_io_Win32FileSystem_createFileExclusively(JNIEnv *env, jclass cls,
0N/A jstring pathname)
0N/A{
0N/A jboolean rv = JNI_FALSE;
0N/A DWORD a;
0N/A
0N/A WITH_PLATFORM_STRING(env, pathname, path) {
0N/A int orv;
0N/A int error;
0N/A JVM_NativePath((char *)path);
0N/A orv = JVM_Open(path, JVM_O_RDWR | JVM_O_CREAT | JVM_O_EXCL, 0666);
0N/A if (orv < 0) {
0N/A if (orv != JVM_EEXIST) {
0N/A error = GetLastError();
0N/A
0N/A // If a directory by the named path already exists,
0N/A // return false (behavior of solaris and linux) instead of
0N/A // throwing an exception
0N/A a = GetFileAttributes(path);
0N/A
0N/A if ((a == INVALID_FILE_ATTRIBUTES) ||
0N/A !(a & FILE_ATTRIBUTE_DIRECTORY)) {
0N/A SetLastError(error);
0N/A JNU_ThrowIOExceptionWithLastError(env, path);
0N/A }
0N/A }
0N/A } else {
0N/A JVM_Close(orv);
0N/A rv = JNI_TRUE;
0N/A }
0N/A } END_PLATFORM_STRING(env, path);
0N/A return rv;
0N/A}
0N/A
0N/A
0N/Astatic int
0N/AremoveFileOrDirectory(const char *path) /* Returns 0 on success */
0N/A{
0N/A DWORD a;
0N/A
0N/A SetFileAttributes(path, 0);
0N/A a = GetFileAttributes(path);
0N/A if (a == INVALID_FILE_ATTRIBUTES) {
0N/A return 1;
0N/A } else if (a & FILE_ATTRIBUTE_DIRECTORY) {
0N/A return !RemoveDirectory(path);
0N/A } else {
0N/A return !DeleteFile(path);
0N/A }
0N/A}
0N/A
0N/A
0N/AJNIEXPORT jboolean JNICALL
0N/AJava_java_io_Win32FileSystem_delete0(JNIEnv *env, jobject this,
0N/A jobject file)
0N/A{
0N/A jboolean rv = JNI_FALSE;
0N/A
0N/A WITH_NATIVE_PATH(env, file, ids.path, path) {
0N/A if (removeFileOrDirectory(path) == 0) {
0N/A rv = JNI_TRUE;
0N/A }
0N/A } END_NATIVE_PATH(env, path);
0N/A return rv;
0N/A}
0N/A
0N/A
0N/A/* ## Clean this up to use direct Win32 calls */
0N/A
0N/AJNIEXPORT jobjectArray JNICALL
0N/AJava_java_io_Win32FileSystem_list(JNIEnv *env, jobject this,
0N/A jobject file)
0N/A{
0N/A DIR *dir;
0N/A struct dirent *ptr;
0N/A int len, maxlen;
0N/A jobjectArray rv, old;
0N/A
0N/A WITH_NATIVE_PATH(env, file, ids.path, path) {
0N/A dir = opendir(path);
0N/A } END_NATIVE_PATH(env, path);
0N/A if (dir == NULL) return NULL;
0N/A
0N/A /* Allocate an initial String array */
0N/A len = 0;
0N/A maxlen = 16;
0N/A rv = (*env)->NewObjectArray(env, maxlen, JNU_ClassString(env), NULL);
0N/A if (rv == NULL) goto error;
0N/A
0N/A /* Scan the directory */
0N/A while ((ptr = readdir(dir)) != NULL) {
0N/A jstring name;
0N/A if (!strcmp(ptr->d_name, ".") || !strcmp(ptr->d_name, ".."))
0N/A continue;
0N/A if (len == maxlen) {
0N/A old = rv;
0N/A rv = (*env)->NewObjectArray(env, maxlen <<= 1,
0N/A JNU_ClassString(env), NULL);
0N/A if (rv == NULL) goto error;
0N/A if (JNU_CopyObjectArray(env, rv, old, len) < 0) goto error;
0N/A (*env)->DeleteLocalRef(env, old);
0N/A }
0N/A name = JNU_NewStringPlatform(env, ptr->d_name);
0N/A if (name == NULL) goto error;
0N/A (*env)->SetObjectArrayElement(env, rv, len++, name);
0N/A (*env)->DeleteLocalRef(env, name);
0N/A }
0N/A closedir(dir);
0N/A
0N/A /* Copy the final results into an appropriately-sized array */
0N/A old = rv;
0N/A rv = (*env)->NewObjectArray(env, len, JNU_ClassString(env), NULL);
0N/A if (rv == NULL) goto error;
0N/A if (JNU_CopyObjectArray(env, rv, old, len) < 0) goto error;
0N/A return rv;
0N/A
0N/A error:
0N/A closedir(dir);
0N/A return NULL;
0N/A}
0N/A
0N/A
0N/AJNIEXPORT jboolean JNICALL
0N/AJava_java_io_Win32FileSystem_createDirectory(JNIEnv *env, jobject this,
0N/A jobject file)
0N/A{
0N/A jboolean rv = JNI_FALSE;
0N/A
0N/A WITH_NATIVE_PATH(env, file, ids.path, path) {
0N/A if (mkdir(path) == 0) {
0N/A rv = JNI_TRUE;
0N/A }
0N/A } END_NATIVE_PATH(env, path);
0N/A return rv;
0N/A}
0N/A
0N/A
0N/AJNIEXPORT jboolean JNICALL
0N/AJava_java_io_Win32FileSystem_rename0(JNIEnv *env, jobject this,
0N/A jobject from, jobject to)
0N/A{
0N/A jboolean rv = JNI_FALSE;
0N/A
0N/A WITH_NATIVE_PATH(env, from, ids.path, fromPath) {
0N/A WITH_NATIVE_PATH(env, to, ids.path, toPath) {
0N/A if (rename(fromPath, toPath) == 0) {
0N/A rv = JNI_TRUE;
0N/A }
0N/A } END_NATIVE_PATH(env, toPath);
0N/A } END_NATIVE_PATH(env, fromPath);
0N/A return rv;
0N/A}
0N/A
0N/A
0N/AJNIEXPORT jboolean JNICALL
0N/AJava_java_io_Win32FileSystem_setLastModifiedTime(JNIEnv *env, jobject this,
0N/A jobject file, jlong time)
0N/A{
0N/A jboolean rv = JNI_FALSE;
0N/A
0N/A WITH_NATIVE_PATH(env, file, ids.path, path) {
0N/A HANDLE h;
0N/A h = CreateFile(path, GENERIC_WRITE, 0, NULL, OPEN_EXISTING,
0N/A FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS, 0);
0N/A if (h != INVALID_HANDLE_VALUE) {
0N/A LARGE_INTEGER modTime;
0N/A FILETIME t;
0N/A modTime.QuadPart = (time + 11644473600000L) * 10000L;
0N/A t.dwLowDateTime = (DWORD)modTime.LowPart;
0N/A t.dwHighDateTime = (DWORD)modTime.HighPart;
0N/A if (SetFileTime(h, NULL, NULL, &t)) {
0N/A rv = JNI_TRUE;
0N/A }
0N/A CloseHandle(h);
0N/A }
0N/A } END_NATIVE_PATH(env, path);
0N/A
0N/A return rv;
0N/A}
0N/A
0N/A
0N/AJNIEXPORT jboolean JNICALL
0N/AJava_java_io_Win32FileSystem_setReadOnly(JNIEnv *env, jobject this,
0N/A jobject file)
0N/A{
0N/A jboolean rv = JNI_FALSE;
0N/A
0N/A WITH_NATIVE_PATH(env, file, ids.path, path) {
0N/A DWORD a;
0N/A a = GetFileAttributes(path);
0N/A if (a != INVALID_FILE_ATTRIBUTES) {
0N/A if (SetFileAttributes(path, a | FILE_ATTRIBUTE_READONLY))
0N/A rv = JNI_TRUE;
0N/A }
0N/A } END_NATIVE_PATH(env, path);
0N/A return rv;
0N/A}
0N/A
0N/A
0N/A/* -- Filesystem interface -- */
0N/A
0N/A
0N/AJNIEXPORT jobject JNICALL
0N/AJava_java_io_Win32FileSystem_getDriveDirectory(JNIEnv *env, jclass ignored,
0N/A jint drive)
0N/A{
0N/A char buf[_MAX_PATH];
0N/A char *p = _getdcwd(drive, buf, sizeof(buf));
0N/A if (p == NULL) return NULL;
0N/A if (isalpha(*p) && (p[1] == ':')) p += 2;
0N/A return JNU_NewStringPlatform(env, p);
0N/A}
0N/A
0N/A
0N/AJNIEXPORT jint JNICALL
0N/AJava_java_io_Win32FileSystem_listRoots0(JNIEnv *env, jclass ignored)
0N/A{
0N/A return GetLogicalDrives();
0N/A}
0N/A
0N/AJNIEXPORT jlong JNICALL
0N/AJava_java_io_Win32FileSystem_getSpace0(JNIEnv *env, jobject this,
0N/A jobject file, jint t)
0N/A{
0N/A jlong rv = 0L;
0N/A
0N/A WITH_NATIVE_PATH(env, file, ids.path, path) {
0N/A ULARGE_INTEGER totalSpace, freeSpace, usableSpace;
0N/A if (GetDiskFreeSpaceEx(path, &usableSpace, &totalSpace, &freeSpace)) {
0N/A switch(t) {
0N/A case java_io_FileSystem_SPACE_TOTAL:
0N/A rv = long_to_jlong(totalSpace.QuadPart);
0N/A break;
0N/A case java_io_FileSystem_SPACE_FREE:
0N/A rv = long_to_jlong(freeSpace.QuadPart);
0N/A break;
0N/A case java_io_FileSystem_SPACE_USABLE:
0N/A rv = long_to_jlong(usableSpace.QuadPart);
0N/A break;
0N/A default:
0N/A assert(0);
0N/A }
0N/A }
0N/A } END_NATIVE_PATH(env, path);
0N/A return rv;
0N/A}