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..f37a72add76 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,7 +2,7 @@ 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)" Bundle-Localization: fragment diff --git a/resources/bundles/org.eclipse.core.filesystem.linux.x86_64/os/linux/x86_64/libunixfile_1_0_0.so b/resources/bundles/org.eclipse.core.filesystem.linux.x86_64/os/linux/x86_64/libunixfile_1_0_0.so index 9067085dfac..cdf1e343618 100755 Binary files a/resources/bundles/org.eclipse.core.filesystem.linux.x86_64/os/linux/x86_64/libunixfile_1_0_0.so and b/resources/bundles/org.eclipse.core.filesystem.linux.x86_64/os/linux/x86_64/libunixfile_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..3141d7d51dd 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 @@ -18,7 +18,7 @@ ../../ org.eclipse.core.filesystem.linux.x86_64 - 1.2.400-SNAPSHOT + 1.2.500-SNAPSHOT eclipse-plugin diff --git a/resources/bundles/org.eclipse.core.filesystem/natives/unix/unixfile.c b/resources/bundles/org.eclipse.core.filesystem/natives/unix/unixfile.c index a23a89aa67a..395a495ecee 100644 --- a/resources/bundles/org.eclipse.core.filesystem/natives/unix/unixfile.c +++ b/resources/bundles/org.eclipse.core.filesystem/natives/unix/unixfile.c @@ -20,6 +20,8 @@ #include #include #include +#include +#include #if defined MACOSX #include @@ -38,6 +40,14 @@ static jfieldID attrs_st_mtime_msec; /* Only filled on MACOSX. */ static jfieldID attrs_st_flags; +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_unix_UnixFileNatives_initializeStructStatFieldIDs * Method: initializeStructStatFieldIDs @@ -51,6 +61,9 @@ JNIEXPORT jint JNICALL Java_org_eclipse_core_internal_filesystem_local_unix_Unix attrs_st_mode = (*env)->GetFieldID(env, structStatClass, "st_mode", "I"); attrs_st_size = (*env)->GetFieldID(env, structStatClass, "st_size", "J"); attrs_st_mtime = (*env)->GetFieldID(env, structStatClass, "st_mtime", "J"); + errno_fieldID = (*env)->GetFieldID(env, structStatClass, "errno", "I"); + nameFieldId = (*env)->GetFieldID(env, structStatClass, "name", "Ljava/lang/String;"); + linkFieldId = (*env)->GetFieldID(env, structStatClass, "linkFile", "Ljava/lang/String;"); #ifdef MACOSX attrs_st_flags = (*env)->GetFieldID(env, structStatClass, "st_flags", "J"); @@ -80,17 +93,37 @@ jbyte* getByteArray(JNIEnv *env, jbyteArray target) } /* - * Fills StructStat object with data from struct stat. + * Copy object array contents using java.lang.System.arraycopy. */ -jint convertStatToObject(JNIEnv *env, struct stat info, jobject stat_object) +jint copyObjectArray(JNIEnv *env, jobject source, jobject target, jsize length) { - jclass cls; - jfieldID fid; - jboolean readOnly; + 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; + } - cls = (*env)->GetObjectClass(env, stat_object); - if (cls == 0) 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 StructStat 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); @@ -100,6 +133,9 @@ jint convertStatToObject(JNIEnv *env, struct stat info, jobject stat_object) 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); + #ifndef MACOSX if (attrs_st_mtime_msec == 0) return -1; (*env)->SetLongField(env, stat_object, attrs_st_mtime_msec, (info.st_mtim.tv_nsec / (1000 * 1000))); @@ -165,10 +201,10 @@ JNIEXPORT jint JNICALL Java_org_eclipse_core_internal_filesystem_local_unix_Unix struct stat info; name = (char*) getByteArray(env, path); - code = stat(name, &info); + code = fstatat(AT_FDCWD, name, &info, 0); free(name); if (code != -1) - return convertStatToObject(env, info, buf); + return convertStatToObject(env, info, 0, buf); else return code; } @@ -186,10 +222,10 @@ JNIEXPORT jint JNICALL Java_org_eclipse_core_internal_filesystem_local_unix_Unix struct stat info; name = (char*) getByteArray(env, path); - code = lstat(name, &info); + code = fstatat(AT_FDCWD, name, &info, AT_SYMLINK_NOFOLLOW); free(name); if (code != -1) - return convertStatToObject(env, info, buf); + return convertStatToObject(env, info, 0, buf); else return code; } @@ -329,3 +365,300 @@ JNIEXPORT jint JNICALL Java_org_eclipse_core_internal_filesystem_local_unix_Unix free(flag); return ret; } + +JNIEXPORT jobjectArray JNICALL Java_org_eclipse_core_internal_filesystem_local_unix_UnixFileNatives_listDir + (JNIEnv *env, jclass, jbyteArray path) +{ + char *name; + DIR *dir = NULL; + int directoryFd; + jsize arrayLength; + int count = 0; + int i; + struct dirent *entry; + jobjectArray namesArray; + jobjectArray result = NULL; + jclass stringClass; + + stringClass = (*env)->FindClass(env, "java/lang/String"); + if (stringClass == NULL) { + return NULL; + } + namesArray = (*env)->NewObjectArray(env, INITIAL_LIST_ARRAY_SIZE, stringClass, NULL); + if (namesArray == NULL) { + return NULL; + } + arrayLength = INITIAL_LIST_ARRAY_SIZE; + + name = (char*) getByteArray(env, path); + dir = opendir(name); + free(name); + if (dir == NULL) { + goto cleanup; + } + directoryFd = dirfd(dir); + if (directoryFd == -1) { + goto cleanup; + } + while ((entry = readdir(dir)) != NULL) { + jstring nameString = NULL; + 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, stringClass, 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 to the names array */ + nameString = (*env)->NewStringUTF(env, entry->d_name); + if (nameString == NULL) { + goto cleanup; + } + + (*env)->SetObjectArrayElement(env, namesArray, count, nameString); + if ((*env)->ExceptionCheck(env)) { + (*env)->DeleteLocalRef(env, nameString); + goto cleanup; + } + (*env)->DeleteLocalRef(env, nameString); + + count++; + } + + result = (*env)->NewObjectArray(env, count, stringClass, NULL); + if (result == 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, result, i, existingName); + (*env)->DeleteLocalRef(env, existingName); + if ((*env)->ExceptionCheck(env)) { + goto cleanup; + } + } + +cleanup: + if (dir != NULL) { + closedir(dir); + } + return result; +} + +JNIEXPORT jobjectArray JNICALL Java_org_eclipse_core_internal_filesystem_local_unix_UnixFileNatives_listDirAndGetFileInfos + (JNIEnv *env, jclass, jbyteArray path) +{ + char *name; + DIR *dir = NULL; + int directoryFd; + jsize arrayLength; + int count = 0; + int i; + struct dirent *entry; + jclass structStatClass; + jmethodID structStatCtor; + jobjectArray statArray = NULL; + jobjectArray resultStatsArray = NULL; + jobjectArray result = NULL; + + structStatClass = (*env)->FindClass(env, "org/eclipse/core/internal/filesystem/local/unix/StructStat"); + if (structStatClass == NULL) { + return NULL; + } + + statArray = (*env)->NewObjectArray(env, INITIAL_LIST_ARRAY_SIZE, structStatClass, NULL); + if (statArray == NULL) { + return NULL; + } + arrayLength = INITIAL_LIST_ARRAY_SIZE; + + structStatCtor = (*env)->GetMethodID(env, structStatClass, "", "()V"); + if (structStatCtor == NULL) { + return NULL; + } + name = (char*) getByteArray(env, path); + 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; + jstring nameString = 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, structStatClass, 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, structStatClass, structStatCtor); + 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]; + jstring linkString = NULL; + 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'; + } else if (statErrno == 0) { + statErrno = errno; + } + + if (linkPathLen >= 0) { + linkString = (*env)->NewStringUTF(env, linkPath); + } else { + linkString = (*env)->NewStringUTF(env, ""); + } + + if (linkString == NULL) { + (*env)->DeleteLocalRef(env, statObject); + goto cleanup; + } + (*env)->SetObjectField(env, statObject, linkFieldId, linkString); + (*env)->DeleteLocalRef(env, linkString); + if ((*env)->ExceptionCheck(env)) { + (*env)->DeleteLocalRef(env, statObject); + goto cleanup; + } + } + + if (convertStatToObject(env, st, statErrno, statObject) != 0) { + (*env)->DeleteLocalRef(env, statObject); + goto cleanup; + } + + (*env)->SetObjectArrayElement(env, statArray, count, statObject); + if ((*env)->ExceptionCheck(env)) { + (*env)->DeleteLocalRef(env, statObject); + goto cleanup; + } + + nameString = (*env)->NewStringUTF(env, entry->d_name); + if (nameString == NULL) { + (*env)->DeleteLocalRef(env, statObject); + goto cleanup; + } + + (*env)->SetObjectField(env, statObject, nameFieldId, nameString); + if ((*env)->ExceptionCheck(env)) { + (*env)->DeleteLocalRef(env, nameString); + (*env)->DeleteLocalRef(env, statObject); + goto cleanup; + } + (*env)->DeleteLocalRef(env, nameString); + (*env)->DeleteLocalRef(env, statObject); + + count++; + } + + resultStatsArray = (*env)->NewObjectArray(env, count, structStatClass, 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/unixfile.h b/resources/bundles/org.eclipse.core.filesystem/natives/unix/unixfile.h index 8fc4a836457..d6f427faed8 100644 --- a/resources/bundles/org.eclipse.core.filesystem/natives/unix/unixfile.h +++ b/resources/bundles/org.eclipse.core.filesystem/natives/unix/unixfile.h @@ -27,7 +27,7 @@ jbyte* getByteArray(JNIEnv *, jbyteArray); /* * Fills StructStat object with data from struct stat. */ -jint convertStatToObject(JNIEnv *, struct stat, jobject); +jint convertStatToObject(JNIEnv *, struct stat, int errnoValue, jobject); /* DO NOT EDIT THIS FILE - it is machine generated */ @@ -119,6 +119,22 @@ JNIEXPORT jbyteArray JNICALL Java_org_eclipse_core_internal_filesystem_local_uni JNIEXPORT jint JNICALL Java_org_eclipse_core_internal_filesystem_local_unix_UnixFileNatives_getflag (JNIEnv *, jclass, jbyteArray); +/* + * Class: org_eclipse_core_internal_filesystem_local_unix_UnixFileNatives + * Method: listDir + * Signature: ([B)[Ljava/lang/String; + */ +JNIEXPORT jobjectArray JNICALL Java_org_eclipse_core_internal_filesystem_local_unix_UnixFileNatives_listDir + (JNIEnv *, jclass, jbyteArray); + +/* + * Class: org_eclipse_core_internal_filesystem_local_unix_UnixFileNatives + * Method: listDirAndGetFileInfos + * Signature: ([B)[Lorg/eclipse/core/internal/filesystem/local/unix/StructStat; + */ +JNIEXPORT jobjectArray JNICALL Java_org_eclipse_core_internal_filesystem_local_unix_UnixFileNatives_listDirAndGetFileInfos + (JNIEnv *, jclass, jbyteArray); + #ifdef __cplusplus } #endif diff --git a/resources/bundles/org.eclipse.core.filesystem/src/org/eclipse/core/internal/filesystem/local/LocalFile.java b/resources/bundles/org.eclipse.core.filesystem/src/org/eclipse/core/internal/filesystem/local/LocalFile.java index f2bda5e0584..3fc03131d99 100644 --- a/resources/bundles/org.eclipse.core.filesystem/src/org/eclipse/core/internal/filesystem/local/LocalFile.java +++ b/resources/bundles/org.eclipse.core.filesystem/src/org/eclipse/core/internal/filesystem/local/LocalFile.java @@ -135,10 +135,14 @@ private void checkTargetIsNotWritable(File target, Throwable exception) throws C } } + @Override + public IFileInfo[] childInfos(int options, IProgressMonitor monitor) { + return LocalFileNativesManager.listDirectoryAndGetFileInfos(filePath); + } + @Override public String[] childNames(int options, IProgressMonitor monitor) { - String[] names = file.list(); - return (names == null ? EMPTY_STRING_ARRAY : names); + return LocalFileNativesManager.listDirectoryNames(filePath); } @Override 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 9900dfe253f..89ab0df082e 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 @@ -87,4 +87,12 @@ public static boolean putFileInfo(String fileName, IFileInfo info, int options) return HANDLER.putFileInfo(fileName, info, options); } + public static IFileInfo[] listDirectoryAndGetFileInfos(String fileName) { + return HANDLER.listDirectoryAndGetFileInfos(fileName); + } + + public static String[] listDirectoryNames(String fileName) { + return HANDLER.listDirectoryNames(fileName); + } + } diff --git a/resources/bundles/org.eclipse.core.filesystem/src/org/eclipse/core/internal/filesystem/local/NativeHandler.java b/resources/bundles/org.eclipse.core.filesystem/src/org/eclipse/core/internal/filesystem/local/NativeHandler.java index 3e144fe6b79..6ea955cd605 100644 --- a/resources/bundles/org.eclipse.core.filesystem/src/org/eclipse/core/internal/filesystem/local/NativeHandler.java +++ b/resources/bundles/org.eclipse.core.filesystem/src/org/eclipse/core/internal/filesystem/local/NativeHandler.java @@ -13,6 +13,7 @@ *******************************************************************************/ package org.eclipse.core.internal.filesystem.local; +import java.io.File; import org.eclipse.core.filesystem.IFileInfo; import org.eclipse.core.filesystem.provider.FileInfo; @@ -25,4 +26,21 @@ public abstract class NativeHandler { public abstract FileInfo fetchFileInfo(String fileName); public abstract boolean putFileInfo(String fileName, IFileInfo info, int options); + + protected static final String[] EMPTY_STRING_ARRAY = {}; + + public String[] listDirectoryNames(String fileName) { + String[] names = new File(fileName).list(); + return names == null ? EMPTY_STRING_ARRAY : names; + } + + public IFileInfo[] listDirectoryAndGetFileInfos(String fileName) { + var directoryContents = listDirectoryNames(fileName); + var result = new IFileInfo[directoryContents.length]; + for (int i = 0; i < directoryContents.length; i++) { + result[i] = fetchFileInfo(fileName + File.separator + directoryContents[i]); + } + return result; + } + } 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 e53ba661727..2a7e112254f 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,6 +14,7 @@ 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; /** @@ -21,6 +22,7 @@ * and is used by JNI calls wrapping OS file related functions. */ public class StructStat { + private static final int ENOENT = 2; // errno value for "No such file or directory" private static final boolean USE_MILLISECOND_RESOLUTION = Boolean.parseBoolean(System.getProperty("eclipse.filesystem.useNatives.modificationTimestampMillisecondsResolution", "true")); //$NON-NLS-1$ //$NON-NLS-2$ @@ -29,10 +31,20 @@ 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(); - info.setExists(true); + if (errno != 0 && errno != ENOENT) { + info.setError(IFileInfo.IO_ERROR); + return info; + } + info.setExists(errno != ENOENT); + if (name != null) { + info.setName(name); + } info.setLength(st_size); long lastModified = (st_mtime * 1_000); if (USE_MILLISECOND_RESOLUTION) { @@ -42,6 +54,12 @@ 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/UnixFileHandler.java b/resources/bundles/org.eclipse.core.filesystem/src/org/eclipse/core/internal/filesystem/local/unix/UnixFileHandler.java index c13ae00f851..2ca8f50269d 100644 --- a/resources/bundles/org.eclipse.core.filesystem/src/org/eclipse/core/internal/filesystem/local/unix/UnixFileHandler.java +++ b/resources/bundles/org.eclipse.core.filesystem/src/org/eclipse/core/internal/filesystem/local/unix/UnixFileHandler.java @@ -21,6 +21,17 @@ * Native handler that delegates to UnixFileNatives */ public class UnixFileHandler extends NativeHandler { + + @Override + public String[] listDirectoryNames(String fileName) { + return UnixFileNatives.listDirectoryNames(fileName); + } + + @Override + public IFileInfo[] listDirectoryAndGetFileInfos(String fileName) { + return UnixFileNatives.listDirectoryAndGetFileInfos(fileName); + } + @Override public int getSupportedAttributes() { return UnixFileNatives.getSupportedAttributes(); 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 5b030b14543..b446b41e784 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 @@ -21,7 +21,9 @@ 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.*; +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; @@ -35,6 +37,8 @@ public abstract class UnixFileNatives { private static final boolean usingNatives; private static final int libattr; + protected static final String[] EMPTY_STRING_ARRAY = {}; + static { boolean _usingNatives = false; int _libattr = 0; @@ -76,27 +80,51 @@ public static int getSupportedAttributes() { return ret; } + public static String[] listDirectoryNames(String pathName) { + byte[] name = fileNameToBytes(pathName); + String[] result = listDir(name); + if (result == null) { + return EMPTY_STRING_ARRAY; + } + return result; + } + + public static IFileInfo[] listDirectoryAndGetFileInfos(String pathName) { + byte[] name = fileNameToBytes(pathName); + StructStat[] 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); StructStat stat = new StructStat(); - if (lstat(name, stat) == 0) { - if ((stat.st_mode & UnixFileFlags.S_IFMT) == UnixFileFlags.S_IFLNK) { - if (stat(name, stat) == 0) { - info = stat.toFileInfo(); - } else { + 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(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! info = new FileInfo(); if (getErrno() != ENOENT) { info.setError(IFileInfo.IO_ERROR); } } - info.setAttribute(EFS.ATTRIBUTE_SYMLINK, true); + info.setAttribute(EFS.ATTRIBUTE_SYMLINK, true); // set symlink attribute byte target[] = new byte[UnixFileFlags.PATH_MAX]; int length = readlink(name, target, target.length); - if (length > 0) { + if (length > 0) { // set target of the link info.setStringAttribute(EFS.ATTRIBUTE_LINK_TARGET, bytesToFileName(target, length)); } - } else { + } else { // regular file or directory info = stat.toFileInfo(); } } else { @@ -231,4 +259,8 @@ private static boolean isSupported(int attr) { private static final native int getflag(byte[] buf); + private static final native String[] listDir(byte[] path); + + private static final native StructStat[] listDirAndGetFileInfos(byte[] path); + }