diff --git a/resources/bundles/org.eclipse.core.filesystem.linux.x86_64/META-INF/MANIFEST.MF b/resources/bundles/org.eclipse.core.filesystem.linux.x86_64/META-INF/MANIFEST.MF index ada3f4f2eeb..c87b4505a56 100644 --- a/resources/bundles/org.eclipse.core.filesystem.linux.x86_64/META-INF/MANIFEST.MF +++ b/resources/bundles/org.eclipse.core.filesystem.linux.x86_64/META-INF/MANIFEST.MF @@ -2,8 +2,8 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %fragmentName Bundle-SymbolicName: org.eclipse.core.filesystem.linux.x86_64; singleton:=true -Bundle-Version: 1.2.400.qualifier +Bundle-Version: 1.2.500.qualifier Bundle-Vendor: %providerName -Fragment-Host: org.eclipse.core.filesystem;bundle-version="[1.7.200,2.0.0)" +Fragment-Host: org.eclipse.core.filesystem;bundle-version="[1.11.500,2.0.0)" Bundle-Localization: fragment Eclipse-PlatformFilter: (& (osgi.os=linux) (osgi.arch=x86_64)) diff --git a/resources/bundles/org.eclipse.core.filesystem.linux.x86_64/os/linux/x86_64/libfastlinuxfile_1_0_0.so b/resources/bundles/org.eclipse.core.filesystem.linux.x86_64/os/linux/x86_64/libfastlinuxfile_1_0_0.so new file mode 100644 index 00000000000..dcb1925e3a6 Binary files /dev/null and b/resources/bundles/org.eclipse.core.filesystem.linux.x86_64/os/linux/x86_64/libfastlinuxfile_1_0_0.so differ diff --git a/resources/bundles/org.eclipse.core.filesystem.linux.x86_64/pom.xml b/resources/bundles/org.eclipse.core.filesystem.linux.x86_64/pom.xml index 1d83bb509fd..f54da5cba35 100644 --- a/resources/bundles/org.eclipse.core.filesystem.linux.x86_64/pom.xml +++ b/resources/bundles/org.eclipse.core.filesystem.linux.x86_64/pom.xml @@ -5,7 +5,7 @@ are made available under the terms of the Eclipse Distribution License v1.0 which accompanies this distribution, and is available at http://www.eclipse.org/org/documents/edl-v10.php - + Contributors: Igor Fedorenko - initial implementation --> @@ -18,7 +18,7 @@ ../../ org.eclipse.core.filesystem.linux.x86_64 - 1.2.400-SNAPSHOT + 1.2.500-SNAPSHOT eclipse-plugin @@ -42,12 +42,16 @@ - - - - - - + + + + + + + + + + diff --git a/resources/bundles/org.eclipse.core.filesystem/natives/unix/fastlinux/Makefile b/resources/bundles/org.eclipse.core.filesystem/natives/unix/fastlinux/Makefile new file mode 100644 index 00000000000..13c720d773f --- /dev/null +++ b/resources/bundles/org.eclipse.core.filesystem/natives/unix/fastlinux/Makefile @@ -0,0 +1,42 @@ +#****************************************************************************** +# Copyright (c) 2010 IBM Corporation and others. +# +# This program and the accompanying materials +# are made available under the terms of the Eclipse Public License 2.0 +# which accompanies this distribution, and is available at +# https://www.eclipse.org/legal/epl-2.0/ +# +# SPDX-License-Identifier: EPL-2.0 +# +# Contributors: +# IBM Corporation - initial API and implementation +#******************************************************************************/ +# +# makefile for libfastlinuxfile_1_0_0.so + +CORE.C = fastlinuxfile.c +CORE.O = fastlinuxfile.o +LIB_NAME = libfastlinuxfile.so +LIB_NAME_FULL = libfastlinuxfile_1_0_0.so + +#Set this to be your OS type +OS_TYPE = linux + +#Set this to be the location of your JRE +ifeq (${JAVA_HOME},) + JAVA_HOME = /usr/lib/jvm/java-17/ +endif + +JDK_INCLUDE = -I ${JAVA_HOME}/include -I ${JAVA_HOME}/include/${OS_TYPE} +OPT_FLAGS=-O2 -g -s -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 + +core: + gcc $(OPT_FLAGS) -fPIC -c $(JDK_INCLUDE) -o $(CORE.O) $(CORE.C) + gcc $(OPT_FLAGS) -shared -Wl,-soname,$(LIB_NAME) -o $(LIB_NAME_FULL) $(CORE.O) -lc + +clean: + rm -f $(CORE.O) $(LIB_NAME_FULL) + +install: core + rm -f ../../../../org.eclipse.core.filesystem.linux.x86_64/os/linux/x86_64/libfastlinuxfile_1_0_0.so + mv libfastlinuxfile_1_0_0.so ../../../../org.eclipse.core.filesystem.linux.x86_64/os/linux/x86_64/ diff --git a/resources/bundles/org.eclipse.core.filesystem/natives/unix/fastlinux/fastlinuxfile.c b/resources/bundles/org.eclipse.core.filesystem/natives/unix/fastlinux/fastlinuxfile.c new file mode 100644 index 00000000000..7e10ff47ac0 --- /dev/null +++ b/resources/bundles/org.eclipse.core.filesystem/natives/unix/fastlinux/fastlinuxfile.c @@ -0,0 +1,578 @@ +/******************************************************************************* + * Copyright (c) 2010 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "fastlinuxfile.h" + +/* The lstat stat field st_mode. */ +static jfieldID attrs_st_mode; +/* The lstat stat field st_size. */ +static jfieldID attrs_st_size; +/* The lstat stat field st_mtime_sec. */ +static jfieldID attrs_st_mtime; +/* The lstat stat field st_mtime_nsec divided by 1 000 000. */ +static jfieldID attrs_st_mtime_msec; + +static jfieldID errno_fieldID; + +static jfieldID nameFieldId; + +static jfieldID linkFieldId; + +static const jsize INITIAL_LIST_ARRAY_SIZE = 100; + +/* + * Class: Java_org_eclipse_core_internal_filesystem_local_linux_LinuxFileNatives_initializeLinuxStructStatFieldIDs + * Method: initializeLinuxStructStatFieldIDs + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_org_eclipse_core_internal_filesystem_local_linux_LinuxFileNatives_initializeLinuxStructStatFieldIDs + (JNIEnv *env, jclass clazz) +{ + jclass LinuxStructStatClass = (*env)->FindClass(env, "org/eclipse/core/internal/filesystem/local/linux/LinuxStructStat"); + if (LinuxStructStatClass == NULL) { + return; /* exception already pending */ + } + attrs_st_mode = (*env)->GetFieldID(env, LinuxStructStatClass, "st_mode", "I"); + attrs_st_size = (*env)->GetFieldID(env, LinuxStructStatClass, "st_size", "J"); + attrs_st_mtime = (*env)->GetFieldID(env, LinuxStructStatClass, "st_mtime", "J"); + errno_fieldID = (*env)->GetFieldID(env, LinuxStructStatClass, "errno", "I"); + nameFieldId = (*env)->GetFieldID(env, LinuxStructStatClass, "name", "[B"); + linkFieldId = (*env)->GetFieldID(env, LinuxStructStatClass, "linkFile", "[B"); + attrs_st_mtime_msec = (*env)->GetFieldID(env, LinuxStructStatClass, "st_mtime_msec", "J"); +} + +/* + * Get a null-terminated byte array from a java byte array. The returned bytearray + * needs to be freed when not used anymore. Use free(result) to do that. + */ +jbyte* getByteArray(JNIEnv *env, jbyteArray target) +{ + unsigned int len; + jbyte *temp, *result; + + temp = (*env)->GetByteArrayElements(env, target, 0); + len = (*env)->GetArrayLength(env, target); + result = malloc((len + 1) * sizeof(jbyte)); + if (result != NULL) { + memcpy(result, temp, len * sizeof(jbyte)); + result[len] = '\0'; + } + (*env)->ReleaseByteArrayElements(env, target, temp, 0); + return result; +} + +/* + * Copy object array contents using java.lang.System.arraycopy. + */ +jint copyObjectArray(JNIEnv *env, jobject source, jobject target, jsize length) +{ + jclass systemClass; + jmethodID arraycopyMethod; + + systemClass = (*env)->FindClass(env, "java/lang/System"); + if (systemClass == NULL) { + return -1; + } + arraycopyMethod = (*env)->GetStaticMethodID(env, systemClass, "arraycopy", "(Ljava/lang/Object;ILjava/lang/Object;II)V"); + if (arraycopyMethod == NULL) { + (*env)->DeleteLocalRef(env, systemClass); + return -1; + } + + (*env)->CallStaticVoidMethod(env, systemClass, arraycopyMethod, source, 0, target, 0, length); + (*env)->DeleteLocalRef(env, systemClass); + if ((*env)->ExceptionCheck(env)){ + return -1; + } + + return 0; +} + +/* + * Fills LinuxStructStat object with data from struct stat. + */ +jint convertStatToObject(JNIEnv *env, struct stat info, int errnoValue, jobject stat_object) +{ + if (attrs_st_mode == 0) return -1; + (*env)->SetIntField(env, stat_object, attrs_st_mode, info.st_mode); + + if (attrs_st_size == 0) return -1; + (*env)->SetLongField(env, stat_object, attrs_st_size, info.st_size); + + if (attrs_st_mtime == 0) return -1; + (*env)->SetLongField(env, stat_object, attrs_st_mtime, info.st_mtime); + + if (errno_fieldID == 0) return -1; + (*env)->SetIntField(env, stat_object, errno_fieldID, errnoValue); + + if (attrs_st_mtime_msec == 0) return -1; + (*env)->SetLongField(env, stat_object, attrs_st_mtime_msec, (info.st_mtim.tv_nsec / (1000 * 1000))); + + return 0; +} + +/* + * Class: org_eclipse_core_internal_filesystem_local_linux_LinuxFileNatives + * Method: chmod + * Signature: ([BI)I + */ +JNIEXPORT jint JNICALL Java_org_eclipse_core_internal_filesystem_local_linux_LinuxFileNatives_chmod + (JNIEnv *env, jclass clazz, jbyteArray path, jint mode) +{ + int code; + char *name; + + name = (char*) getByteArray(env, path); + if (name == NULL) { + return -1; + } + code = chmod(name, mode); + free(name); + return code; +} + +/* + * Class: org_eclipse_core_internal_filesystem_local_linux_LinuxFileNatives + * Method: stat + * Signature: ([BLorg/eclipse/core/internal/filesystem/local/linux/LinuxStructStat;)I + */ +JNIEXPORT jint JNICALL Java_org_eclipse_core_internal_filesystem_local_linux_LinuxFileNatives_stat + (JNIEnv *env, jclass clazz, jbyteArray path, jobject buf) +{ + jint code; + char *name; + struct stat info = {0}; + + name = (char*) getByteArray(env, path); + if (name == NULL) { + return -1; + } + code = fstatat(AT_FDCWD, name, &info, 0); + free(name); + return convertStatToObject(env, info, code == 0 ? 0 : errno, buf); +} + +/* + * Class: org_eclipse_core_internal_filesystem_local_linux_LinuxFileNatives + * Method: lstat + * Signature: ([BLorg/eclipse/core/internal/filesystem/local/linux/LinuxStructStat;)I + */ +JNIEXPORT jint JNICALL Java_org_eclipse_core_internal_filesystem_local_linux_LinuxFileNatives_lstat + (JNIEnv *env, jclass clazz, jbyteArray path, jobject buf) +{ + jint code; + char *name; + struct stat info = {0}; + + name = (char*) getByteArray(env, path); + if (name == NULL) { + return -1; + } + code = fstatat(AT_FDCWD, name, &info, AT_SYMLINK_NOFOLLOW); + free(name); + return convertStatToObject(env, info, code == 0 ? 0 : errno, buf); +} + +/* + * Class: org_eclipse_core_internal_filesystem_local_linux_LinuxFileNatives + * Method: readlink + * Signature: ([B[BJ)I + */ +JNIEXPORT jint JNICALL Java_org_eclipse_core_internal_filesystem_local_linux_LinuxFileNatives_readlink + (JNIEnv *env, jclass clazz, jbyteArray path, jbyteArray buf, jlong bufsiz) { + jbyte *name; + int len; + char temp[PATH_MAX+1]; + + name = getByteArray(env, path); + if (name == NULL) { + return -1; + } + len = readlink((const char*)name, temp, PATH_MAX); + free(name); + if (len > 0) { + temp[len] = 0; + (*env)->SetByteArrayRegion(env, buf, 0, len, (jbyte*) temp); + } + else { + temp[0] = 0; + (*env)->SetByteArrayRegion(env, buf, 0, 0, (jbyte*) temp); + } + return len; +} + +/* + * Class: org_eclipse_core_internal_filesystem_local_linux_LinuxFileNatives + * Method: getflag + * Signature: ([B)I + */ +JNIEXPORT jint JNICALL Java_org_eclipse_core_internal_filesystem_local_linux_LinuxFileNatives_getflag + (JNIEnv *env, jclass clazz, jbyteArray buf) +{ + char *flag; + jint ret = -1; + + flag = (char*) getByteArray(env, buf); + if (flag == NULL) { + return -1; + } + if (strcmp(flag, "PATH_MAX") == 0) + ret = PATH_MAX; + else if (strcmp(flag, "S_IFMT") == 0) + ret = S_IFMT; + else if (strcmp(flag, "S_IFLNK") == 0) + ret = S_IFLNK; + else if (strcmp(flag, "S_IFDIR") == 0) + ret = S_IFDIR; + else if (strcmp(flag, "S_IRUSR") == 0) + ret = S_IRUSR; + else if (strcmp(flag, "S_IWUSR") == 0) + ret = S_IWUSR; + else if (strcmp(flag, "S_IXUSR") == 0) + ret = S_IXUSR; + else if (strcmp(flag, "S_IRGRP") == 0) + ret = S_IRGRP; + else if (strcmp(flag, "S_IWGRP") == 0) + ret = S_IWGRP; + else if (strcmp(flag, "S_IXGRP") == 0) + ret = S_IXGRP; + else if (strcmp(flag, "S_IROTH") == 0) + ret = S_IROTH; + else if (strcmp(flag, "S_IWOTH") == 0) + ret = S_IWOTH; + else if (strcmp(flag, "S_IXOTH") == 0) + ret = S_IXOTH; + free(flag); + return ret; +} + +JNIEXPORT jobjectArray JNICALL Java_org_eclipse_core_internal_filesystem_local_linux_LinuxFileNatives_listDir + (JNIEnv *env, jclass, jbyteArray path) +{ + char *name; + DIR *dir = NULL; + jsize arrayLength; + int count = 0; + int i; + struct dirent *entry; + jobjectArray namesArray; + jobjectArray resultStatsArray = NULL; + jobjectArray result = NULL; + jclass byteArrayClass; + + byteArrayClass = (*env)->FindClass(env, "[B"); + if (byteArrayClass == NULL) { + return NULL; + } + namesArray = (*env)->NewObjectArray(env, INITIAL_LIST_ARRAY_SIZE, byteArrayClass, NULL); + if (namesArray == NULL) { + return NULL; + } + arrayLength = INITIAL_LIST_ARRAY_SIZE; + + name = (char*) getByteArray(env, path); + if (name == NULL) { + goto cleanup; + } + dir = opendir(name); + free(name); + if (dir == NULL) { + goto cleanup; + } + while ((entry = readdir(dir)) != NULL) { + jbyteArray nameBytes; + jsize nameLen; + jobjectArray grownArray; + + /* Skip . and .. */ + if (entry->d_name[0] == '.' && + (entry->d_name[1] == '\0' || + (entry->d_name[1] == '.' && entry->d_name[2] == '\0'))) { + continue; + } + + if (count >= arrayLength) { + jsize newLength = arrayLength > 0 ? arrayLength * 2 : 1; + + if (newLength < arrayLength) { + goto cleanup; + } + + grownArray = (*env)->NewObjectArray(env, newLength, byteArrayClass, NULL); + if (grownArray == NULL) { + goto cleanup; + } + + if (copyObjectArray(env, namesArray, grownArray, arrayLength) != 0) { + (*env)->DeleteLocalRef(env, grownArray); + goto cleanup; + } + + (*env)->DeleteLocalRef(env, namesArray); + namesArray = grownArray; + arrayLength = newLength; + } + + /* Add the directory entry name as raw bytes to the names array */ + nameLen = (jsize)strlen(entry->d_name); + nameBytes = (*env)->NewByteArray(env, nameLen); + if (nameBytes == NULL) { + goto cleanup; + } + (*env)->SetByteArrayRegion(env, nameBytes, 0, nameLen, (const jbyte*)entry->d_name); + (*env)->SetObjectArrayElement(env, namesArray, count, nameBytes); + (*env)->DeleteLocalRef(env, nameBytes); + if ((*env)->ExceptionCheck(env)) { + goto cleanup; + } + + count++; + } + + resultStatsArray = (*env)->NewObjectArray(env, count, byteArrayClass, NULL); + if (resultStatsArray == NULL) { + goto cleanup; + } + + for (i = 0; i < count; i++) { + jobject existingName = (*env)->GetObjectArrayElement(env, namesArray, i); + if ((*env)->ExceptionCheck(env)) { + goto cleanup; + } + (*env)->SetObjectArrayElement(env, resultStatsArray, i, existingName); + (*env)->DeleteLocalRef(env, existingName); + if ((*env)->ExceptionCheck(env)) { + goto cleanup; + } + } + + result = resultStatsArray; + resultStatsArray = NULL; + +cleanup: + if (dir != NULL) { + closedir(dir); + } + if (namesArray != NULL) { + (*env)->DeleteLocalRef(env, namesArray); + } + if (resultStatsArray != NULL) { + (*env)->DeleteLocalRef(env, resultStatsArray); + } + return result; +} + +JNIEXPORT jobjectArray JNICALL Java_org_eclipse_core_internal_filesystem_local_linux_LinuxFileNatives_listDirAndGetFileInfos + (JNIEnv *env, jclass, jbyteArray path) +{ + char *name; + DIR *dir = NULL; + int directoryFd; + jsize arrayLength; + int count = 0; + int i; + struct dirent *entry; + jclass LinuxStructStatClass; + jmethodID LinuxStructStatCtor; + jobjectArray statArray = NULL; + jobjectArray resultStatsArray = NULL; + jobjectArray result = NULL; + + LinuxStructStatClass = (*env)->FindClass(env, "org/eclipse/core/internal/filesystem/local/linux/LinuxStructStat"); + if (LinuxStructStatClass == NULL) { + return NULL; + } + + statArray = (*env)->NewObjectArray(env, INITIAL_LIST_ARRAY_SIZE, LinuxStructStatClass, NULL); + if (statArray == NULL) { + return NULL; + } + arrayLength = INITIAL_LIST_ARRAY_SIZE; + + LinuxStructStatCtor = (*env)->GetMethodID(env, LinuxStructStatClass, "", "()V"); + if (LinuxStructStatCtor == NULL) { + goto cleanup; + } + name = (char*) getByteArray(env, path); + if (name == NULL) { + goto cleanup; + } + dir = opendir(name); + free(name); + if (dir == NULL) { + goto cleanup; + } + directoryFd = dirfd(dir); + if (directoryFd == -1) { + goto cleanup; + } + while ((entry = readdir(dir)) != NULL) { + struct stat st; + jobject statObject = NULL; + int statErrno = 0; + + /* Skip . and .. */ + if (entry->d_name[0] == '.' && + (entry->d_name[1] == '\0' || + (entry->d_name[1] == '.' && entry->d_name[2] == '\0'))) { + continue; + } + + if (count >= arrayLength) { + jsize newLength = arrayLength > 0 ? arrayLength * 2 : 1; + jobjectArray grownStatArray; + + if (newLength < arrayLength) { + goto cleanup; + } + + grownStatArray = (*env)->NewObjectArray(env, newLength, LinuxStructStatClass, NULL); + if (grownStatArray == NULL) { + goto cleanup; + } + + if (copyObjectArray(env, statArray, grownStatArray, arrayLength) != 0) { + (*env)->DeleteLocalRef(env, grownStatArray); + goto cleanup; + } + + (*env)->DeleteLocalRef(env, statArray); + + statArray = grownStatArray; + arrayLength = newLength; + } + + statObject = (*env)->NewObject(env, LinuxStructStatClass, LinuxStructStatCtor); + if (statObject == NULL) { + goto cleanup; + } + + /* Collect file stats. Keep processing even if stat/readlink fails. */ + if (fstatat(directoryFd, entry->d_name, &st, AT_SYMLINK_NOFOLLOW) != 0) { + memset(&st, 0, sizeof(st)); + statErrno = errno; + } else if (S_ISLNK(st.st_mode)) { + char linkPath[PATH_MAX + 1]; + jbyteArray linkBytes; + jsize linkLen; + ssize_t linkPathLen; + + /* Follow symlink and update stat for further processing. */ + if (fstatat(directoryFd, entry->d_name, &st, 0) != 0) { + memset(&st, 0, sizeof(st)); + statErrno = errno; + } + + /* Read link target if possible. */ + linkPathLen = readlinkat(directoryFd, entry->d_name, linkPath, PATH_MAX); + if (linkPathLen >= 0) { + linkPath[linkPathLen] = '\0'; + } + + linkLen = (linkPathLen >= 0) ? (jsize)linkPathLen : 0; + linkBytes = (*env)->NewByteArray(env, linkLen); + if (linkBytes == NULL) { + (*env)->DeleteLocalRef(env, statObject); + goto cleanup; + } + if (linkLen > 0) { + (*env)->SetByteArrayRegion(env, linkBytes, 0, linkLen, (const jbyte*)linkPath); + } + (*env)->SetObjectField(env, statObject, linkFieldId, linkBytes); + (*env)->DeleteLocalRef(env, linkBytes); + if ((*env)->ExceptionCheck(env)) { + (*env)->DeleteLocalRef(env, statObject); + goto cleanup; + } + } + + if (convertStatToObject(env, st, statErrno, statObject) != 0) { + (*env)->DeleteLocalRef(env, statObject); + goto cleanup; + } + + { + jbyteArray nameBytes; + jsize nameLen = (jsize)strlen(entry->d_name); + nameBytes = (*env)->NewByteArray(env, nameLen); + if (nameBytes == NULL) { + (*env)->DeleteLocalRef(env, statObject); + goto cleanup; + } + (*env)->SetByteArrayRegion(env, nameBytes, 0, nameLen, (const jbyte*)entry->d_name); + (*env)->SetObjectField(env, statObject, nameFieldId, nameBytes); + (*env)->DeleteLocalRef(env, nameBytes); + if ((*env)->ExceptionCheck(env)) { + (*env)->DeleteLocalRef(env, statObject); + goto cleanup; + } + } + + (*env)->SetObjectArrayElement(env, statArray, count, statObject); + if ((*env)->ExceptionCheck(env)) { + (*env)->DeleteLocalRef(env, statObject); + goto cleanup; + } + (*env)->DeleteLocalRef(env, statObject); + + count++; + } + + resultStatsArray = (*env)->NewObjectArray(env, count, LinuxStructStatClass, NULL); + if (resultStatsArray == NULL) { + goto cleanup; + } + + for (i = 0; i < count; i++) { + jobject existingStat = (*env)->GetObjectArrayElement(env, statArray, i); + if ((*env)->ExceptionCheck(env)) { + if (existingStat != NULL) { + (*env)->DeleteLocalRef(env, existingStat); + } + goto cleanup; + } + + (*env)->SetObjectArrayElement(env, resultStatsArray, i, existingStat); + (*env)->DeleteLocalRef(env, existingStat); + if ((*env)->ExceptionCheck(env)) { + goto cleanup; + } + } + + result = resultStatsArray; + resultStatsArray = NULL; + +cleanup: + if (dir != NULL) { + closedir(dir); + } + if (statArray != NULL) { + (*env)->DeleteLocalRef(env, statArray); + } + if (resultStatsArray != NULL) { + (*env)->DeleteLocalRef(env, resultStatsArray); + } + return result; +} \ No newline at end of file diff --git a/resources/bundles/org.eclipse.core.filesystem/natives/unix/fastlinux/fastlinuxfile.h b/resources/bundles/org.eclipse.core.filesystem/natives/unix/fastlinux/fastlinuxfile.h new file mode 100644 index 00000000000..ab59f9e5e85 --- /dev/null +++ b/resources/bundles/org.eclipse.core.filesystem/natives/unix/fastlinux/fastlinuxfile.h @@ -0,0 +1,105 @@ +/******************************************************************************* + * Copyright (c) 2010 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +#include + +/* + * Get a null-terminated byte array from a java byte array. The returned bytearray + * needs to be freed when not used anymore. Use free(result) to do that. + */ +jbyte* getByteArray(JNIEnv *, jbyteArray); + +/* + * Fills LinuxStructStat object with data from struct stat. + */ +jint convertStatToObject(JNIEnv *, struct stat, int errnoValue, jobject); + +/* DO NOT EDIT THIS FILE - it is machine generated */ + +/* Header for class org_eclipse_core_internal_filesystem_local_linux_LinuxFileNatives */ + +#ifndef _Included_org_eclipse_core_internal_filesystem_local_linux_LinuxFileNatives +#define _Included_org_eclipse_core_internal_filesystem_local_linux_LinuxFileNatives +#ifdef __cplusplus +extern "C" { +#endif +#undef org_eclipse_core_internal_filesystem_local_linux_LinuxFileNatives_ENOENT +#define org_eclipse_core_internal_filesystem_local_linux_LinuxFileNatives_ENOENT 2L +/* + * Class: org_eclipse_core_internal_filesystem_local_linux_LinuxFileNatives + * Method: initializeLinuxStructStatFieldIDs + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_org_eclipse_core_internal_filesystem_local_linux_LinuxFileNatives_initializeLinuxStructStatFieldIDs + (JNIEnv *, jclass); + +/* + * Class: org_eclipse_core_internal_filesystem_local_linux_LinuxFileNatives + * Method: chmod + * Signature: ([BI)I + */ +JNIEXPORT jint JNICALL Java_org_eclipse_core_internal_filesystem_local_linux_LinuxFileNatives_chmod + (JNIEnv *, jclass, jbyteArray, jint); + +/* + * Class: org_eclipse_core_internal_filesystem_local_linux_LinuxFileNatives + * Method: stat + * Signature: ([BLorg/eclipse/core/internal/filesystem/local/linux/LinuxStructStat;)I + */ +JNIEXPORT jint JNICALL Java_org_eclipse_core_internal_filesystem_local_linux_LinuxFileNatives_stat + (JNIEnv *, jclass, jbyteArray, jobject); + +/* + * Class: org_eclipse_core_internal_filesystem_local_linux_LinuxFileNatives + * Method: lstat + * Signature: ([BLorg/eclipse/core/internal/filesystem/local/linux/LinuxStructStat;)I + */ +JNIEXPORT jint JNICALL Java_org_eclipse_core_internal_filesystem_local_linux_LinuxFileNatives_lstat + (JNIEnv *, jclass, jbyteArray, jobject); + +/* + * Class: org_eclipse_core_internal_filesystem_local_linux_LinuxFileNatives + * Method: readlink + * Signature: ([B[BJ)I + */ +JNIEXPORT jint JNICALL Java_org_eclipse_core_internal_filesystem_local_linux_LinuxFileNatives_readlink + (JNIEnv *, jclass, jbyteArray, jbyteArray, jlong); + +/* + * Class: org_eclipse_core_internal_filesystem_local_linux_LinuxFileNatives + * Method: getflag + * Signature: ([B)I + */ +JNIEXPORT jint JNICALL Java_org_eclipse_core_internal_filesystem_local_linux_LinuxFileNatives_getflag + (JNIEnv *, jclass, jbyteArray); + +/* + * Class: org_eclipse_core_internal_filesystem_local_linux_LinuxFileNatives + * Method: listDir + * Signature: ([B)[[B + */ +JNIEXPORT jobjectArray JNICALL Java_org_eclipse_core_internal_filesystem_local_linux_LinuxFileNatives_listDir + (JNIEnv *, jclass, jbyteArray); + +/* + * Class: org_eclipse_core_internal_filesystem_local_linux_LinuxFileNatives + * Method: listDirAndGetFileInfos + * Signature: ([B)[Lorg/eclipse/core/internal/filesystem/local/linux/LinuxStructStat; + */ +JNIEXPORT jobjectArray JNICALL Java_org_eclipse_core_internal_filesystem_local_linux_LinuxFileNatives_listDirAndGetFileInfos + (JNIEnv *, jclass, jbyteArray); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/resources/bundles/org.eclipse.core.filesystem/src/org/eclipse/core/internal/filesystem/local/LocalFileNativesManager.java b/resources/bundles/org.eclipse.core.filesystem/src/org/eclipse/core/internal/filesystem/local/LocalFileNativesManager.java index 89ab0df082e..8a9fe40831f 100644 --- a/resources/bundles/org.eclipse.core.filesystem/src/org/eclipse/core/internal/filesystem/local/LocalFileNativesManager.java +++ b/resources/bundles/org.eclipse.core.filesystem/src/org/eclipse/core/internal/filesystem/local/LocalFileNativesManager.java @@ -18,6 +18,8 @@ import java.util.Set; import org.eclipse.core.filesystem.IFileInfo; import org.eclipse.core.filesystem.provider.FileInfo; +import org.eclipse.core.internal.filesystem.local.linux.LinuxFileHandler; +import org.eclipse.core.internal.filesystem.local.linux.LinuxFileNatives; import org.eclipse.core.internal.filesystem.local.nio.DefaultHandler; import org.eclipse.core.internal.filesystem.local.nio.PosixHandler; import org.eclipse.core.internal.filesystem.local.unix.UnixFileHandler; @@ -38,7 +40,9 @@ */ public class LocalFileNativesManager { public static final boolean PROPERTY_USE_NATIVE_DEFAULT = true; + public static final boolean PROPERTY_USE_FAST_LINUX_NATIVES_DEFAULT = true; public static final String PROPERTY_USE_NATIVES = "eclipse.filesystem.useNatives"; //$NON-NLS-1$ + public static final String PROPERTY_USE_FAST_LINUX_NATIVES = "eclipse.filesystem.useFastLinuxNatives"; //$NON-NLS-1$ private static NativeHandler HANDLER; static { @@ -49,16 +53,21 @@ public class LocalFileNativesManager { * reset the usage of native to the system default */ public static void reset() { - setUsingNative(Boolean.parseBoolean(System.getProperty(PROPERTY_USE_NATIVES, String.valueOf(PROPERTY_USE_NATIVE_DEFAULT)))); + setUsingNative(Boolean.parseBoolean(System.getProperty(PROPERTY_USE_NATIVES, String.valueOf(PROPERTY_USE_NATIVE_DEFAULT))), + Boolean.parseBoolean(System.getProperty(PROPERTY_USE_FAST_LINUX_NATIVES, String.valueOf(PROPERTY_USE_FAST_LINUX_NATIVES_DEFAULT)))); } /** * Try to set the usage of natives to the provided value * @return true if natives are used as result of this call false otherwise */ - public static boolean setUsingNative(boolean useNatives) { + public static boolean setUsingNative(boolean useNatives, boolean useFastLinuxNatives) { boolean nativesAreUsed; - if (useNatives && !Platform.OS.isWindows() && UnixFileNatives.isUsingNatives()) { + if (useNatives && useFastLinuxNatives && Platform.OS.isLinux() && Platform.ARCH_X86_64.equals(Platform.getOSArch()) && LinuxFileNatives.isUsingNatives()) { + // Linux x86_64 architecture supports faster (bulk) file info fetching. + HANDLER = new LinuxFileHandler(); + nativesAreUsed = true; + } else if (useNatives && !Platform.OS.isWindows() && UnixFileNatives.isUsingNatives()) { HANDLER = new UnixFileHandler(); nativesAreUsed = true; } else { diff --git a/resources/bundles/org.eclipse.core.filesystem/src/org/eclipse/core/internal/filesystem/local/linux/LinuxFileFlags.java b/resources/bundles/org.eclipse.core.filesystem/src/org/eclipse/core/internal/filesystem/local/linux/LinuxFileFlags.java new file mode 100644 index 00000000000..8cb5fc5cbfc --- /dev/null +++ b/resources/bundles/org.eclipse.core.filesystem/src/org/eclipse/core/internal/filesystem/local/linux/LinuxFileFlags.java @@ -0,0 +1,88 @@ +/******************************************************************************* + * Copyright (c) 2010 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.core.internal.filesystem.local.linux; + +public class LinuxFileFlags { + + static { + PATH_MAX = LinuxFileNatives.getFlag("PATH_MAX"); //$NON-NLS-1$ + S_IFMT = LinuxFileNatives.getFlag("S_IFMT"); //$NON-NLS-1$ + S_IFLNK = LinuxFileNatives.getFlag("S_IFLNK"); //$NON-NLS-1$ + S_IFDIR = LinuxFileNatives.getFlag("S_IFDIR"); //$NON-NLS-1$ + S_IRUSR = LinuxFileNatives.getFlag("S_IRUSR"); //$NON-NLS-1$ + S_IWUSR = LinuxFileNatives.getFlag("S_IWUSR"); //$NON-NLS-1$ + S_IXUSR = LinuxFileNatives.getFlag("S_IXUSR"); //$NON-NLS-1$ + S_IRGRP = LinuxFileNatives.getFlag("S_IRGRP"); //$NON-NLS-1$ + S_IWGRP = LinuxFileNatives.getFlag("S_IWGRP"); //$NON-NLS-1$ + S_IXGRP = LinuxFileNatives.getFlag("S_IXGRP"); //$NON-NLS-1$ + S_IROTH = LinuxFileNatives.getFlag("S_IROTH"); //$NON-NLS-1$ + S_IWOTH = LinuxFileNatives.getFlag("S_IWOTH"); //$NON-NLS-1$ + S_IXOTH = LinuxFileNatives.getFlag("S_IXOTH"); //$NON-NLS-1$ + } + + /** + * chars in a path name including nul + */ + public static final int PATH_MAX; + + /** + * bitmask for the file type bitfields + */ + public static final int S_IFMT; + /** + * symbolic link + */ + public static final int S_IFLNK; + /** + * directory + */ + public static final int S_IFDIR; + /** + * owner has read permission + */ + public static final int S_IRUSR; + /** + * owner has write permission + */ + public static final int S_IWUSR; + /** + * owner has execute permission + */ + public static final int S_IXUSR; + /** + * group has read permission + */ + public static final int S_IRGRP; + /** + * group has write permission + */ + public static final int S_IWGRP; + /** + * group has execute permission + */ + public static final int S_IXGRP; + /** + * others have read permission + */ + public static final int S_IROTH; + /** + * others have write permission + */ + public static final int S_IWOTH; + /** + * others have execute permission + */ + public static final int S_IXOTH; + +} diff --git a/resources/bundles/org.eclipse.core.filesystem/src/org/eclipse/core/internal/filesystem/local/linux/LinuxFileHandler.java b/resources/bundles/org.eclipse.core.filesystem/src/org/eclipse/core/internal/filesystem/local/linux/LinuxFileHandler.java new file mode 100644 index 00000000000..d739286efcd --- /dev/null +++ b/resources/bundles/org.eclipse.core.filesystem/src/org/eclipse/core/internal/filesystem/local/linux/LinuxFileHandler.java @@ -0,0 +1,48 @@ +/******************************************************************************* + * Copyright (c) 2012, 2015 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.core.internal.filesystem.local.linux; + +import org.eclipse.core.filesystem.IFileInfo; +import org.eclipse.core.filesystem.provider.FileInfo; +import org.eclipse.core.internal.filesystem.local.NativeHandler; + +/** + * Native handler that delegates to LinuxFileNatives + */ +public class LinuxFileHandler extends NativeHandler { + @Override + public int getSupportedAttributes() { + return LinuxFileNatives.getSupportedAttributes(); + } + + @Override + public FileInfo fetchFileInfo(String fileName) { + return LinuxFileNatives.fetchFileInfo(fileName); + } + + @Override + public boolean putFileInfo(String fileName, IFileInfo info, int options) { + return LinuxFileNatives.putFileInfo(fileName, info, options); + } + + @Override + public String[] listDirectoryNames(String fileName) { + return LinuxFileNatives.listDirectoryNames(fileName); + } + + @Override + public IFileInfo[] listDirectoryAndGetFileInfos(String fileName) { + return LinuxFileNatives.listDirectoryAndGetFileInfos(fileName); + } +} diff --git a/resources/bundles/org.eclipse.core.filesystem/src/org/eclipse/core/internal/filesystem/local/linux/LinuxFileNatives.java b/resources/bundles/org.eclipse.core.filesystem/src/org/eclipse/core/internal/filesystem/local/linux/LinuxFileNatives.java new file mode 100644 index 00000000000..a50462736e2 --- /dev/null +++ b/resources/bundles/org.eclipse.core.filesystem/src/org/eclipse/core/internal/filesystem/local/linux/LinuxFileNatives.java @@ -0,0 +1,234 @@ +/******************************************************************************* + * Copyright (c) 2010, 2017 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + * Sergey Prigogin (Google) - ongoing development + *******************************************************************************/ +package org.eclipse.core.internal.filesystem.local.linux; + +import static org.eclipse.core.internal.filesystem.local.linux.LinuxFileFlags.PATH_MAX; +import static org.eclipse.core.internal.filesystem.local.linux.LinuxFileFlags.S_IFLNK; +import static org.eclipse.core.internal.filesystem.local.linux.LinuxFileFlags.S_IFMT; +import static org.eclipse.core.internal.filesystem.local.linux.LinuxFileFlags.S_IRGRP; +import static org.eclipse.core.internal.filesystem.local.linux.LinuxFileFlags.S_IROTH; +import static org.eclipse.core.internal.filesystem.local.linux.LinuxFileFlags.S_IRUSR; +import static org.eclipse.core.internal.filesystem.local.linux.LinuxFileFlags.S_IWGRP; +import static org.eclipse.core.internal.filesystem.local.linux.LinuxFileFlags.S_IWOTH; +import static org.eclipse.core.internal.filesystem.local.linux.LinuxFileFlags.S_IWUSR; +import static org.eclipse.core.internal.filesystem.local.linux.LinuxFileFlags.S_IXGRP; +import static org.eclipse.core.internal.filesystem.local.linux.LinuxFileFlags.S_IXOTH; +import static org.eclipse.core.internal.filesystem.local.linux.LinuxFileFlags.S_IXUSR; + +import java.io.File; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.util.Enumeration; +import org.eclipse.core.filesystem.EFS; +import org.eclipse.core.filesystem.IFileInfo; +import org.eclipse.core.filesystem.provider.FileInfo; +import org.eclipse.core.internal.filesystem.FileSystemAccess; +import org.eclipse.core.internal.filesystem.Messages; +import org.eclipse.core.internal.filesystem.Policy; +import org.eclipse.core.internal.filesystem.local.Convert; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.osgi.util.NLS; + +public abstract class LinuxFileNatives { + private static final String LIBRARY_NAME = "fastlinuxfile_1_0_0"; //$NON-NLS-1$ + private static final int ENOENT = LinuxStructStat.ENOENT; // errno value for "No such file or directory" + + private static final boolean usingNatives; + protected static final String[] EMPTY_STRING_ARRAY = {}; + + static { + boolean _usingNatives = false; + try { + System.loadLibrary(LIBRARY_NAME); + _usingNatives = true; + initializeLinuxStructStatFieldIDs(); + } catch (UnsatisfiedLinkError e) { + if (isLibraryPresent()) { + logMissingNativeLibrary(e); + } + } finally { + usingNatives = _usingNatives; + } + } + + private static boolean isLibraryPresent() { + String libName = System.mapLibraryName(LIBRARY_NAME); + Enumeration entries = FileSystemAccess.findEntries("/", libName, true); //$NON-NLS-1$ + return entries != null && entries.hasMoreElements(); + } + + private static void logMissingNativeLibrary(UnsatisfiedLinkError e) { + String libName = System.mapLibraryName(LIBRARY_NAME); + String message = NLS.bind(Messages.couldNotLoadLibrary, libName); + Policy.log(IStatus.INFO, message, e); + } + + public static int getSupportedAttributes() { + if (!usingNatives) { + return -1; + } + int ret = EFS.ATTRIBUTE_READ_ONLY | EFS.ATTRIBUTE_EXECUTABLE | EFS.ATTRIBUTE_SYMLINK | EFS.ATTRIBUTE_LINK_TARGET | EFS.ATTRIBUTE_OWNER_READ | EFS.ATTRIBUTE_OWNER_WRITE | EFS.ATTRIBUTE_OWNER_EXECUTE | EFS.ATTRIBUTE_GROUP_READ | EFS.ATTRIBUTE_GROUP_WRITE | EFS.ATTRIBUTE_GROUP_EXECUTE | EFS.ATTRIBUTE_OTHER_READ | EFS.ATTRIBUTE_OTHER_WRITE | EFS.ATTRIBUTE_OTHER_EXECUTE; + return ret; + } + + public static String[] listDirectoryNames(String pathName) { + byte[] name = fileNameToBytes(pathName); + byte[][] result = listDir(name); + if (result == null) { + return EMPTY_STRING_ARRAY; + } + String[] names = new String[result.length]; + for (int i = 0; i < result.length; i++) { + names[i] = Convert.fromPlatformBytes(result[i], result[i].length); + } + return names; + } + + public static IFileInfo[] listDirectoryAndGetFileInfos(String pathName) { + byte[] name = fileNameToBytes(pathName); + LinuxStructStat[] stats = listDirAndGetFileInfos(name); + if (stats == null) { + return new IFileInfo[0]; + } + int count = stats.length; + IFileInfo[] infos = new IFileInfo[count]; + for (int i = 0; i < count; i++) { + var st = stats[i].toFileInfo(); + infos[i] = st; + } + return infos; + } + + public static FileInfo fetchFileInfo(String fileName) { + FileInfo info = null; + byte[] name = fileNameToBytes(fileName); + LinuxStructStat stat = new LinuxStructStat(); + if (lstat(name, stat) == 0 || stat.errno == ENOENT) { // lstat fills errno even on failure + if (stat.errno == ENOENT) { + // file does not exist + info = new FileInfo(); + } else if ((stat.st_mode & S_IFMT) == S_IFLNK) { // it's a link! + LinuxStructStat targetStat = new LinuxStructStat(); + if (stat(name, targetStat) == 0) { // get the information about the file the link points to + info = targetStat.toFileInfo(); // store the target file stats in info + } else { // invalid link target + info = new FileInfo(); + if (targetStat.errno != ENOENT) { + info.setError(IFileInfo.IO_ERROR); + } + } + info.setAttribute(EFS.ATTRIBUTE_SYMLINK, true); // set symlink attribute + byte target[] = new byte[PATH_MAX]; + int length = readlink(name, target, target.length); + if (length > 0) { // set target of the link + info.setStringAttribute(EFS.ATTRIBUTE_LINK_TARGET, bytesToFileName(target, length)); + } + } else { // regular file or directory + info = stat.toFileInfo(); + } + } else { + info = new FileInfo(); + if (stat.errno != ENOENT) { + info.setError(IFileInfo.IO_ERROR); + } + } + + if (info.getName().isEmpty()) { + // If the file system is case insensitive, we don't know the real name of the file. + // Since obtaining the real name in such situation is pretty expensive, we use the name + // passed as a parameter, which may differ by case from the real name of the file + // if the file system is case insensitive. + info.setName(new File(fileName).getName()); + } + return info; + } + + public static boolean putFileInfo(String fileName, IFileInfo info, int options) { + int code = 0; + byte[] name = fileNameToBytes(fileName); + if (name == null) { + return false; + } + + // Change permissions + int mode = 0; + if (info.getAttribute(EFS.ATTRIBUTE_OWNER_READ)) { + mode |= S_IRUSR; + } + if (info.getAttribute(EFS.ATTRIBUTE_OWNER_WRITE)) { + mode |= S_IWUSR; + } + if (info.getAttribute(EFS.ATTRIBUTE_OWNER_EXECUTE)) { + mode |= S_IXUSR; + } + if (info.getAttribute(EFS.ATTRIBUTE_GROUP_READ)) { + mode |= S_IRGRP; + } + if (info.getAttribute(EFS.ATTRIBUTE_GROUP_WRITE)) { + mode |= S_IWGRP; + } + if (info.getAttribute(EFS.ATTRIBUTE_GROUP_EXECUTE)) { + mode |= S_IXGRP; + } + if (info.getAttribute(EFS.ATTRIBUTE_OTHER_READ)) { + mode |= S_IROTH; + } + if (info.getAttribute(EFS.ATTRIBUTE_OTHER_WRITE)) { + mode |= S_IWOTH; + } + if (info.getAttribute(EFS.ATTRIBUTE_OTHER_EXECUTE)) { + mode |= S_IXOTH; + } + code |= chmod(name, mode); + + return code == 0; + } + + public static boolean isUsingNatives() { + return usingNatives; + } + + public static int getFlag(String flag) { + if (!usingNatives) { + return -1; + } + return getflag(flag.getBytes(StandardCharsets.US_ASCII)); + } + + private static byte[] fileNameToBytes(String fileName) { + return Convert.toPlatformBytes(fileName); + } + + private static String bytesToFileName(byte[] buf, int length) { + return Convert.fromPlatformBytes(buf, length); + } + + private static final native void initializeLinuxStructStatFieldIDs(); + + private static final native int chmod(byte[] path, int mode); + + private static final native int stat(byte[] path, LinuxStructStat buf); + + private static final native int lstat(byte[] path, LinuxStructStat buf); + + private static final native int readlink(byte[] path, byte[] buf, long bufsiz); + + private static final native int getflag(byte[] buf); + + private static final native byte[][] listDir(byte[] path); + + private static final native LinuxStructStat[] listDirAndGetFileInfos(byte[] path); + +} diff --git a/resources/bundles/org.eclipse.core.filesystem/src/org/eclipse/core/internal/filesystem/local/linux/LinuxStructStat.java b/resources/bundles/org.eclipse.core.filesystem/src/org/eclipse/core/internal/filesystem/local/linux/LinuxStructStat.java new file mode 100644 index 00000000000..09da16f50e5 --- /dev/null +++ b/resources/bundles/org.eclipse.core.filesystem/src/org/eclipse/core/internal/filesystem/local/linux/LinuxStructStat.java @@ -0,0 +1,94 @@ +/******************************************************************************* + * Copyright (c) 2010 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.core.internal.filesystem.local.linux; + +import org.eclipse.core.filesystem.EFS; +import org.eclipse.core.filesystem.IFileInfo; +import org.eclipse.core.filesystem.provider.FileInfo; +import org.eclipse.core.internal.filesystem.local.Convert; + +/** + * This class mirrors relevant fields of native struct stat + * and is used by JNI calls wrapping OS file related functions. + */ +public class LinuxStructStat { + /** errno value for "No such file or directory" */ + public static final int ENOENT = 2; + + private static final boolean USE_MILLISECOND_RESOLUTION = Boolean.parseBoolean(System.getProperty("eclipse.filesystem.useNatives.modificationTimestampMillisecondsResolution", "true")); //$NON-NLS-1$ //$NON-NLS-2$ + + public int st_mode; + public long st_size; + public long st_mtime; + public long st_mtime_msec; // millisecond component of the file timestamp + public int errno; + public byte[] name; + public byte[] linkFile; // Filled target for symbolic links + + public FileInfo toFileInfo() { + FileInfo info = new FileInfo(); + if (name != null) { + info.setName(Convert.fromPlatformBytes(name, name.length)); + } + if (errno != 0 && errno != ENOENT) { + info.setError(IFileInfo.IO_ERROR); + return info; + } + info.setExists(errno != ENOENT); + info.setLength(st_size); + long lastModified = (st_mtime * 1_000); + if (USE_MILLISECOND_RESOLUTION) { + lastModified += st_mtime_msec; + } + info.setLastModified(lastModified); + if ((st_mode & LinuxFileFlags.S_IFMT) == LinuxFileFlags.S_IFDIR) { + info.setDirectory(true); + } + if (linkFile != null) { + info.setAttribute(EFS.ATTRIBUTE_SYMLINK, true); + if (linkFile.length > 0) { + info.setStringAttribute(EFS.ATTRIBUTE_LINK_TARGET, Convert.fromPlatformBytes(linkFile, linkFile.length)); + } + } + if ((st_mode & LinuxFileFlags.S_IRUSR) == 0) { // Set to true in FileInfo constructor + info.setAttribute(EFS.ATTRIBUTE_OWNER_READ, false); + } + if ((st_mode & LinuxFileFlags.S_IWUSR) == 0) { // Set to true in FileInfo constructor + info.setAttribute(EFS.ATTRIBUTE_OWNER_WRITE, false); + } + if ((st_mode & LinuxFileFlags.S_IXUSR) != 0) { + info.setAttribute(EFS.ATTRIBUTE_OWNER_EXECUTE, true); + } + if ((st_mode & LinuxFileFlags.S_IRGRP) != 0) { + info.setAttribute(EFS.ATTRIBUTE_GROUP_READ, true); + } + if ((st_mode & LinuxFileFlags.S_IWGRP) != 0) { + info.setAttribute(EFS.ATTRIBUTE_GROUP_WRITE, true); + } + if ((st_mode & LinuxFileFlags.S_IXGRP) != 0) { + info.setAttribute(EFS.ATTRIBUTE_GROUP_EXECUTE, true); + } + if ((st_mode & LinuxFileFlags.S_IROTH) != 0) { + info.setAttribute(EFS.ATTRIBUTE_OTHER_READ, true); + } + if ((st_mode & LinuxFileFlags.S_IWOTH) != 0) { + info.setAttribute(EFS.ATTRIBUTE_OTHER_WRITE, true); + } + if ((st_mode & LinuxFileFlags.S_IXOTH) != 0) { + info.setAttribute(EFS.ATTRIBUTE_OTHER_EXECUTE, true); + } + return info; + } + +} diff --git a/resources/bundles/org.eclipse.core.filesystem/src/org/eclipse/core/internal/filesystem/local/unix/StructStat.java b/resources/bundles/org.eclipse.core.filesystem/src/org/eclipse/core/internal/filesystem/local/unix/StructStat.java index 598575ab16f..22dbf3573d7 100644 --- a/resources/bundles/org.eclipse.core.filesystem/src/org/eclipse/core/internal/filesystem/local/unix/StructStat.java +++ b/resources/bundles/org.eclipse.core.filesystem/src/org/eclipse/core/internal/filesystem/local/unix/StructStat.java @@ -14,7 +14,6 @@ package org.eclipse.core.internal.filesystem.local.unix; import org.eclipse.core.filesystem.EFS; -import org.eclipse.core.filesystem.IFileInfo; import org.eclipse.core.filesystem.provider.FileInfo; /** @@ -32,20 +31,10 @@ public class StructStat { public long st_mtime; public long st_mtime_msec; // millisecond component of the file timestamp, filled on Linux systems public long st_flags; // Filled only on Mac OS X - public int errno; - public String name; - public String linkFile; // Filled target for symbolic links public FileInfo toFileInfo() { FileInfo info = new FileInfo(); - if (errno != 0 && errno != ENOENT) { - info.setError(IFileInfo.IO_ERROR); - return info; - } - info.setExists(errno != ENOENT); - if (name != null) { - info.setName(name); - } + info.setExists(true); info.setLength(st_size); long lastModified = (st_mtime * 1_000); if (USE_MILLISECOND_RESOLUTION) { @@ -55,12 +44,6 @@ public FileInfo toFileInfo() { if ((st_mode & UnixFileFlags.S_IFMT) == UnixFileFlags.S_IFDIR) { info.setDirectory(true); } - if (linkFile != null) { - info.setAttribute(EFS.ATTRIBUTE_SYMLINK, true); - if (!linkFile.isEmpty()) { - info.setStringAttribute(EFS.ATTRIBUTE_LINK_TARGET, linkFile); - } - } if ((st_flags & (UnixFileFlags.UF_IMMUTABLE | UnixFileFlags.SF_IMMUTABLE)) != 0) { info.setAttribute(EFS.ATTRIBUTE_IMMUTABLE, true); } diff --git a/resources/bundles/org.eclipse.core.filesystem/src/org/eclipse/core/internal/filesystem/local/unix/UnixFileNatives.java b/resources/bundles/org.eclipse.core.filesystem/src/org/eclipse/core/internal/filesystem/local/unix/UnixFileNatives.java index ddb3cc9a947..c69c79b2421 100644 --- a/resources/bundles/org.eclipse.core.filesystem/src/org/eclipse/core/internal/filesystem/local/unix/UnixFileNatives.java +++ b/resources/bundles/org.eclipse.core.filesystem/src/org/eclipse/core/internal/filesystem/local/unix/UnixFileNatives.java @@ -14,6 +14,21 @@ *******************************************************************************/ package org.eclipse.core.internal.filesystem.local.unix; +import static org.eclipse.core.internal.filesystem.local.unix.UnixFileFlags.PATH_MAX; +import static org.eclipse.core.internal.filesystem.local.unix.UnixFileFlags.SF_IMMUTABLE; +import static org.eclipse.core.internal.filesystem.local.unix.UnixFileFlags.S_IFLNK; +import static org.eclipse.core.internal.filesystem.local.unix.UnixFileFlags.S_IFMT; +import static org.eclipse.core.internal.filesystem.local.unix.UnixFileFlags.S_IRGRP; +import static org.eclipse.core.internal.filesystem.local.unix.UnixFileFlags.S_IROTH; +import static org.eclipse.core.internal.filesystem.local.unix.UnixFileFlags.S_IRUSR; +import static org.eclipse.core.internal.filesystem.local.unix.UnixFileFlags.S_IWGRP; +import static org.eclipse.core.internal.filesystem.local.unix.UnixFileFlags.S_IWOTH; +import static org.eclipse.core.internal.filesystem.local.unix.UnixFileFlags.S_IWUSR; +import static org.eclipse.core.internal.filesystem.local.unix.UnixFileFlags.S_IXGRP; +import static org.eclipse.core.internal.filesystem.local.unix.UnixFileFlags.S_IXOTH; +import static org.eclipse.core.internal.filesystem.local.unix.UnixFileFlags.S_IXUSR; +import static org.eclipse.core.internal.filesystem.local.unix.UnixFileFlags.UF_IMMUTABLE; + import java.io.File; import java.net.URL; import java.nio.charset.StandardCharsets; @@ -83,7 +98,7 @@ public static FileInfo fetchFileInfo(String fileName) { byte[] name = fileNameToBytes(fileName); StructStat stat = new StructStat(); if (lstat(name, stat) == 0) { // return information about the link itself if the file is a symbolic link - if ((stat.st_mode & UnixFileFlags.S_IFMT) == UnixFileFlags.S_IFLNK) { // it a link! + if ((stat.st_mode & S_IFMT) == S_IFLNK) { // it a link! if (stat(name, stat) == 0) { // get the information about the file the link points to info = stat.toFileInfo(); // store the target file stats in info } else { // invalid link target! @@ -93,7 +108,7 @@ public static FileInfo fetchFileInfo(String fileName) { } } info.setAttribute(EFS.ATTRIBUTE_SYMLINK, true); // set symlink attribute - byte target[] = new byte[UnixFileFlags.PATH_MAX]; + byte target[] = new byte[PATH_MAX]; int length = readlink(name, target, target.length); if (length > 0) { // set target of the link info.setStringAttribute(EFS.ATTRIBUTE_LINK_TARGET, bytesToFileName(target, length)); @@ -131,8 +146,8 @@ public static boolean putFileInfo(String fileName, IFileInfo info, int options) StructStat stat = new StructStat(); if (stat(name, stat) == 0) { long flags = stat.st_flags; - flags &= ~UnixFileFlags.SF_IMMUTABLE; - flags &= ~UnixFileFlags.UF_IMMUTABLE; + flags &= ~SF_IMMUTABLE; + flags &= ~UF_IMMUTABLE; code |= chflags(name, (int) flags); } } @@ -140,31 +155,31 @@ public static boolean putFileInfo(String fileName, IFileInfo info, int options) // Change permissions int mode = 0; if (info.getAttribute(EFS.ATTRIBUTE_OWNER_READ)) { - mode |= UnixFileFlags.S_IRUSR; + mode |= S_IRUSR; } if (info.getAttribute(EFS.ATTRIBUTE_OWNER_WRITE)) { - mode |= UnixFileFlags.S_IWUSR; + mode |= S_IWUSR; } if (info.getAttribute(EFS.ATTRIBUTE_OWNER_EXECUTE)) { - mode |= UnixFileFlags.S_IXUSR; + mode |= S_IXUSR; } if (info.getAttribute(EFS.ATTRIBUTE_GROUP_READ)) { - mode |= UnixFileFlags.S_IRGRP; + mode |= S_IRGRP; } if (info.getAttribute(EFS.ATTRIBUTE_GROUP_WRITE)) { - mode |= UnixFileFlags.S_IWGRP; + mode |= S_IWGRP; } if (info.getAttribute(EFS.ATTRIBUTE_GROUP_EXECUTE)) { - mode |= UnixFileFlags.S_IXGRP; + mode |= S_IXGRP; } if (info.getAttribute(EFS.ATTRIBUTE_OTHER_READ)) { - mode |= UnixFileFlags.S_IROTH; + mode |= S_IROTH; } if (info.getAttribute(EFS.ATTRIBUTE_OTHER_WRITE)) { - mode |= UnixFileFlags.S_IWOTH; + mode |= S_IWOTH; } if (info.getAttribute(EFS.ATTRIBUTE_OTHER_EXECUTE)) { - mode |= UnixFileFlags.S_IXOTH; + mode |= S_IXOTH; } code |= chmod(name, mode); @@ -173,7 +188,7 @@ public static boolean putFileInfo(String fileName, IFileInfo info, int options) StructStat stat = new StructStat(); if (stat(name, stat) == 0) { long flags = stat.st_flags; - flags |= UnixFileFlags.UF_IMMUTABLE; + flags |= UF_IMMUTABLE; code |= chflags(name, (int) flags); } } diff --git a/resources/tests/org.eclipse.core.tests.resources/META-INF/MANIFEST.MF b/resources/tests/org.eclipse.core.tests.resources/META-INF/MANIFEST.MF index 4c0d18e2363..e7c73a23e09 100644 --- a/resources/tests/org.eclipse.core.tests.resources/META-INF/MANIFEST.MF +++ b/resources/tests/org.eclipse.core.tests.resources/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: Eclipse Core Tests Resources Bundle-SymbolicName: org.eclipse.core.tests.resources; singleton:=true -Bundle-Version: 3.11.1300.qualifier +Bundle-Version: 3.11.1400.qualifier Bundle-Vendor: Eclipse.org Export-Package: org.eclipse.core.tests.filesystem, org.eclipse.core.tests.internal.alias, diff --git a/resources/tests/org.eclipse.core.tests.resources/pom.xml b/resources/tests/org.eclipse.core.tests.resources/pom.xml index 22616439ded..1b96a3106a3 100644 --- a/resources/tests/org.eclipse.core.tests.resources/pom.xml +++ b/resources/tests/org.eclipse.core.tests.resources/pom.xml @@ -18,7 +18,7 @@ 4.41.0-SNAPSHOT org.eclipse.core.tests.resources - 3.11.1300-SNAPSHOT + 3.11.1400-SNAPSHOT eclipse-test-plugin diff --git a/resources/tests/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/resources/perf/BenchFileStore.java b/resources/tests/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/resources/perf/BenchFileStore.java index 2ace865f6dd..bc469137c09 100644 --- a/resources/tests/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/resources/perf/BenchFileStore.java +++ b/resources/tests/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/resources/perf/BenchFileStore.java @@ -22,6 +22,7 @@ import org.eclipse.core.filesystem.IFileStore; import org.eclipse.core.internal.filesystem.local.LocalFileNativesManager; import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.Platform; import org.eclipse.core.tests.harness.PerformanceTestRunner; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -81,22 +82,40 @@ protected void test() { @Test public void testStoreExitsNative() throws Throwable{ - withNatives(true, () -> { + withNatives(true, false, () -> { new StoreTestRunner(true).run(getClass(), testInfo.getDisplayName(), REPEATS, LOOP_SIZE); }); } + @Test + public void testStoreExitsNative_Linux() throws Throwable { + if (Platform.OS.isLinux() && Platform.ARCH_X86_64.equals(Platform.getOSArch())) { + withNatives(true, true, () -> { + new StoreTestRunner(true).run(getClass(), testInfo.getDisplayName(), REPEATS, LOOP_SIZE); + }); + } + } + @Test public void testStoreNotExitsNative() throws Throwable { - withNatives(true, () -> { + withNatives(true, false, () -> { new StoreTestRunner(false).run(getClass(), testInfo.getDisplayName(), REPEATS, LOOP_SIZE); }); } + @Test + public void testStoreNotExitsNative_Linux() throws Throwable { + if (Platform.OS.isLinux() && Platform.ARCH_X86_64.equals(Platform.getOSArch())) { + withNatives(true, true, () -> { + new StoreTestRunner(false).run(getClass(), testInfo.getDisplayName(), REPEATS, LOOP_SIZE); + }); + } + } + @Test public void testStoreExitsNio() throws Throwable { - withNatives(false, () -> { + withNatives(false, false, () -> { new StoreTestRunner(true).run(getClass(), testInfo.getDisplayName(), REPEATS, LOOP_SIZE); }); @@ -104,14 +123,15 @@ public void testStoreExitsNio() throws Throwable { @Test public void testStoreNotExitsNio() throws Throwable { - withNatives(false, () -> { + withNatives(false, false, () -> { new StoreTestRunner(false).run(getClass(), testInfo.getDisplayName(), REPEATS, LOOP_SIZE); }); } - private static void withNatives(boolean natives, Executable runnable) throws Throwable { + private static void withNatives(boolean natives, boolean useFastLinuxNatives, Executable runnable) + throws Throwable { try { - assertEquals(natives, LocalFileNativesManager.setUsingNative(natives), + assertEquals(natives, LocalFileNativesManager.setUsingNative(natives, useFastLinuxNatives), "can't set natives to the desired value"); runnable.execute(); } finally {