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);
+
}