| /* | |
| * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. | |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| * | |
| * This code is free software; you can redistribute it and/or modify it | |
| * under the terms of the GNU General Public License version 2 only, as | |
| * published by the Free Software Foundation. | |
| * | |
| * This code is distributed in the hope that it will be useful, but WITHOUT | |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| * version 2 for more details (a copy is included in the LICENSE file that | |
| * accompanied this code). | |
| * | |
| * You should have received a copy of the GNU General Public License version | |
| * 2 along with this work; if not, write to the Free Software Foundation, | |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| * | |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| * or visit www.oracle.com if you need additional information or have any | |
| * questions. | |
| */ | |
| #include <stdlib.h> | |
| #include "jni.h" | |
| #include "jni_util.h" | |
| #ifdef WINDOWS | |
| #include <windows.h> | |
| #include <fileapi.h> | |
| #include <winerror.h> | |
| #else | |
| #include <errno.h> | |
| #include <string.h> | |
| #if __APPLE__ | |
| #include <sys/param.h> | |
| #include <sys/mount.h> | |
| #else | |
| #include <sys/statfs.h> | |
| #endif | |
| #endif | |
| #ifdef __cplusplus | |
| extern "C" { | |
| #endif | |
| #ifdef WINDOWS | |
| jboolean initialized = JNI_FALSE; | |
| BOOL(WINAPI * pfnGetDiskSpaceInformation)(LPCWSTR, LPVOID) = NULL; | |
| #endif | |
| // | |
| // root the root of the volume | |
| // sizes[0] total size: number of bytes in the volume | |
| // sizes[1] total space: number of bytes visible to the caller | |
| // sizes[2] free space: number of free bytes in the volume | |
| // sizes[3] usable space: number of bytes available to the caller | |
| // | |
| JNIEXPORT jboolean JNICALL | |
| Java_GetXSpace_getSpace0 | |
| (JNIEnv *env, jclass cls, jstring root, jlongArray sizes) | |
| { | |
| jboolean totalSpaceIsEstimated = JNI_FALSE; | |
| jlong array[4]; | |
| const jchar* strchars = (*env)->GetStringChars(env, root, NULL); | |
| if (strchars == NULL) { | |
| JNU_ThrowByNameWithLastError(env, "java/lang/RuntimeException", | |
| "GetStringChars"); | |
| return JNI_FALSE; | |
| } | |
| #ifdef WINDOWS | |
| if (initialized == JNI_FALSE) { | |
| initialized = JNI_TRUE; | |
| HMODULE hmod = GetModuleHandleW(L"kernel32"); | |
| if (hmod != NULL) { | |
| *(FARPROC*)&pfnGetDiskSpaceInformation = | |
| GetProcAddress(hmod, "GetDiskSpaceInformationW"); | |
| } | |
| } | |
| LPCWSTR path = (LPCWSTR)strchars; | |
| if (pfnGetDiskSpaceInformation != NULL) { | |
| // use GetDiskSpaceInformationW | |
| DISK_SPACE_INFORMATION diskSpaceInfo; | |
| BOOL hres = pfnGetDiskSpaceInformation(path, &diskSpaceInfo); | |
| (*env)->ReleaseStringChars(env, root, strchars); | |
| if (FAILED(hres)) { | |
| JNU_ThrowByNameWithLastError(env, "java/lang/RuntimeException", | |
| "GetDiskSpaceInformationW"); | |
| return totalSpaceIsEstimated; | |
| } | |
| ULONGLONG bytesPerAllocationUnit = | |
| diskSpaceInfo.SectorsPerAllocationUnit*diskSpaceInfo.BytesPerSector; | |
| array[0] = (jlong)(diskSpaceInfo.ActualTotalAllocationUnits* | |
| bytesPerAllocationUnit); | |
| array[1] = (jlong)(diskSpaceInfo.CallerTotalAllocationUnits* | |
| bytesPerAllocationUnit); | |
| array[2] = (jlong)(diskSpaceInfo.ActualAvailableAllocationUnits* | |
| bytesPerAllocationUnit); | |
| array[3] = (jlong)(diskSpaceInfo.CallerAvailableAllocationUnits* | |
| bytesPerAllocationUnit); | |
| } else { | |
| totalSpaceIsEstimated = JNI_TRUE; | |
| // if GetDiskSpaceInformationW is unavailable ("The specified | |
| // procedure could not be found"), fall back to GetDiskFreeSpaceExW | |
| ULARGE_INTEGER freeBytesAvailable; | |
| ULARGE_INTEGER totalNumberOfBytes; | |
| ULARGE_INTEGER totalNumberOfFreeBytes; | |
| BOOL hres = GetDiskFreeSpaceExW(path, &freeBytesAvailable, | |
| &totalNumberOfBytes, &totalNumberOfFreeBytes); | |
| (*env)->ReleaseStringChars(env, root, strchars); | |
| if (FAILED(hres)) { | |
| JNU_ThrowByNameWithLastError(env, "java/lang/RuntimeException", | |
| "GetDiskFreeSpaceExW"); | |
| return totalSpaceIsEstimated; | |
| } | |
| // If quotas are in effect, it is impossible to obtain the volume size, | |
| // so estimate it as free + used = free + (visible - available) | |
| ULONGLONG used = totalNumberOfBytes.QuadPart - freeBytesAvailable.QuadPart; | |
| array[0] = (jlong)(totalNumberOfFreeBytes.QuadPart + used); | |
| array[1] = (jlong)totalNumberOfBytes.QuadPart; | |
| array[2] = (jlong)totalNumberOfFreeBytes.QuadPart; | |
| array[3] = (jlong)freeBytesAvailable.QuadPart; | |
| } | |
| #else | |
| int len = (int)(*env)->GetStringLength(env, root); | |
| char* chars = (char*)malloc((len + 1)*sizeof(char)); | |
| if (chars == NULL) { | |
| (*env)->ReleaseStringChars(env, root, strchars); | |
| JNU_ThrowByNameWithLastError(env, "java/lang/RuntimeException", | |
| "malloc"); | |
| return JNI_FALSE; | |
| } | |
| for (int i = 0; i < len; i++) { | |
| chars[i] = (char)strchars[i]; | |
| } | |
| chars[len] = '\0'; | |
| (*env)->ReleaseStringChars(env, root, strchars); | |
| struct statfs buf; | |
| int result = statfs(chars, &buf); | |
| free(chars); | |
| if (result < 0) { | |
| JNU_ThrowByNameWithLastError(env, "java/lang/RuntimeException", | |
| strerror(errno)); | |
| return totalSpaceIsEstimated; | |
| } | |
| array[0] = (jlong)(buf.f_blocks*buf.f_bsize); | |
| array[1] = array[0]; // number visible is the same as the total size | |
| array[2] = (jlong)(buf.f_bfree*buf.f_bsize); | |
| array[3] = (jlong)(buf.f_bavail*buf.f_bsize); | |
| #endif | |
| (*env)->SetLongArrayRegion(env, sizes, 0, 4, array); | |
| return totalSpaceIsEstimated; | |
| } | |
| JNIEXPORT jboolean JNICALL | |
| Java_GetXSpace_isCDDrive | |
| (JNIEnv *env, jclass cls, jstring root) | |
| { | |
| #ifdef WINDOWS | |
| const jchar* strchars = (*env)->GetStringChars(env, root, NULL); | |
| if (strchars == NULL) { | |
| JNU_ThrowByNameWithLastError(env, "java/lang/RuntimeException", | |
| "GetStringChars"); | |
| return JNI_FALSE; | |
| } | |
| LPCWSTR path = (LPCWSTR)strchars; | |
| UINT driveType = GetDriveTypeW(path); | |
| (*env)->ReleaseStringChars(env, root, strchars); | |
| if (driveType != DRIVE_CDROM) { | |
| return JNI_FALSE; | |
| } | |
| return JNI_TRUE; | |
| #else | |
| return JNI_FALSE; | |
| #endif | |
| } | |
| #ifdef __cplusplus | |
| } | |
| #endif |