Skip to content

Commit

Permalink
Fix listing file attributes in IdeaWin32
Browse files Browse the repository at this point in the history
  • Loading branch information
trespasserw committed Aug 30, 2012
1 parent e9d05e1 commit b2ddcc7
Show file tree
Hide file tree
Showing 6 changed files with 102 additions and 57 deletions.
Binary file modified bin/win/IdeaWin32.dll
Binary file not shown.
Binary file modified bin/win/IdeaWin64.dll
Binary file not shown.
104 changes: 55 additions & 49 deletions native/IdeaWin32/IdeaWin32.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,6 @@ static jclass getFileInfoClass(JNIEnv *env) {
return env->FindClass("com/intellij/openapi/util/io/win32/FileInfo");
}

static HANDLE FindFileInner(JNIEnv *env, jstring path, LPWIN32_FIND_DATA lpData) {
const jchar* str = env->GetStringChars(path, 0);
const HANDLE h = FindFirstFile((LPCWSTR)str, lpData);
env->ReleaseStringChars(path, str);
return h;
}

static bool CopyObjectArray(JNIEnv *env, jobjectArray dst, jobjectArray src, jint count) {
for (int i = 0; i < count; i++) {
jobject p = env->GetObjectArrayElement(src, i);
Expand Down Expand Up @@ -142,11 +135,12 @@ JNIEXPORT void JNICALL Java_com_intellij_openapi_util_io_win32_IdeaWin32_initIDs


JNIEXPORT jobject JNICALL Java_com_intellij_openapi_util_io_win32_IdeaWin32_getInfo0(JNIEnv *env, jobject method, jstring path) {
const jchar* pathStr = env->GetStringChars(path, 0);

WIN32_FILE_ATTRIBUTE_DATA attrData;
const jchar* str = env->GetStringChars(path, 0);
BOOL res = GetFileAttributesEx((LPCWSTR)str, GetFileExInfoStandard, &attrData);
env->ReleaseStringChars(path, str);
BOOL res = GetFileAttributesEx((LPCWSTR)pathStr, GetFileExInfoStandard, &attrData);
if (!res) {
env->ReleaseStringChars(path, pathStr);
return NULL;
}

Expand All @@ -159,7 +153,7 @@ JNIEXPORT jobject JNICALL Java_com_intellij_openapi_util_io_win32_IdeaWin32_getI

if (IS_SET(attrData.dwFileAttributes, FILE_ATTRIBUTE_REPARSE_POINT)) {
WIN32_FIND_DATA findData;
HANDLE h = FindFileInner(env, path, &findData);
HANDLE h = FindFirstFile((LPCWSTR)pathStr, &findData);
if (h != INVALID_HANDLE_VALUE) {
FindClose(h);
data.dwFileAttributes = findData.dwFileAttributes;
Expand All @@ -170,6 +164,8 @@ JNIEXPORT jobject JNICALL Java_com_intellij_openapi_util_io_win32_IdeaWin32_getI
}
}

env->ReleaseStringChars(path, pathStr);

jclass fileInfoClass = getFileInfoClass(env);
if (fileInfoClass == NULL) {
return NULL;
Expand All @@ -184,58 +180,65 @@ JNIEXPORT jstring JNICALL Java_com_intellij_openapi_util_io_win32_IdeaWin32_reso
return NULL; // XP
}

WIN32_FIND_DATA data;
HANDLE h = FindFileInner(env, path, &data);
if (h == INVALID_HANDLE_VALUE) {
return NULL;
}
FindClose(h);

if (!IS_SET(data.dwFileAttributes, FILE_ATTRIBUTE_REPARSE_POINT) || !IS_SET(data.dwReserved0, IO_REPARSE_TAG_SYMLINK)) {
return NULL;
}

const jchar* str = env->GetStringChars(path, 0);
HANDLE th = CreateFile((LPCWSTR)str, 0, FILE_SHARE_ATTRIBUTES, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
env->ReleaseStringChars(path, str);
if (th == INVALID_HANDLE_VALUE) {
return NULL;
}

const jchar* pathStr = env->GetStringChars(path, 0);
jstring result = NULL;

TCHAR name[MAX_PATH];
DWORD len = __GetFinalPathNameByHandle(th, name, MAX_PATH, 0);
if (len > 0) {
if (len < MAX_PATH) {
result = env->NewString((jchar *)name, len);
}
else {
TCHAR *name = (TCHAR *)malloc(sizeof(TCHAR) * (len + 1));
if (name != NULL) {
len = __GetFinalPathNameByHandle(th, name, len, 0);
WIN32_FIND_DATA data;
HANDLE h = FindFirstFile((LPCWSTR)pathStr, &data);
if (h != INVALID_HANDLE_VALUE) {
FindClose(h);

if (IS_SET(data.dwFileAttributes, FILE_ATTRIBUTE_REPARSE_POINT) && IS_SET(data.dwReserved0, IO_REPARSE_TAG_SYMLINK)) {
HANDLE th = CreateFile((LPCWSTR)pathStr, 0, FILE_SHARE_ATTRIBUTES, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
if (th != INVALID_HANDLE_VALUE) {
TCHAR name[MAX_PATH];
DWORD len = __GetFinalPathNameByHandle(th, name, MAX_PATH, 0);
if (len > 0) {
result = env->NewString((jchar *)name, len);
if (len < MAX_PATH) {
result = env->NewString((jchar *)name, len);
}
else {
TCHAR *name = (TCHAR *)malloc(sizeof(TCHAR) * (len + 1));
if (name != NULL) {
len = __GetFinalPathNameByHandle(th, name, len, 0);
if (len > 0) {
result = env->NewString((jchar *)name, len);
}
free(name);
}
}
}
free(name);
CloseHandle(th);

}
}
}

CloseHandle(th);
env->ReleaseStringChars(path, pathStr);
return result;
}


JNIEXPORT jobjectArray JNICALL Java_com_intellij_openapi_util_io_win32_IdeaWin32_listChildren0(JNIEnv *env, jobject method, jstring path) {
WIN32_FIND_DATA data;
HANDLE h = FindFileInner(env, path, &data);
if (h == INVALID_HANDLE_VALUE) {
jclass fileInfoClass = getFileInfoClass(env);
if (fileInfoClass == NULL) {
return NULL;
}

jclass fileInfoClass = getFileInfoClass(env);
if (fileInfoClass == NULL) {
size_t pathLen = env->GetStringLength(path) + 3;
wchar_t* pathStr = (wchar_t *)malloc(pathLen * sizeof(wchar_t));
if (pathStr == NULL) {
return NULL;
}
const jchar* str = env->GetStringChars(path, 0);
wcscpy_s(pathStr, pathLen, (LPCWSTR)str);
wcscat_s(pathStr, pathLen, L"\\*");
env->ReleaseStringChars(path, str);

WIN32_FIND_DATA data;
HANDLE h = FindFirstFile((LPCWSTR)pathStr, &data);
if (h == INVALID_HANDLE_VALUE) {
free(pathStr);
return NULL;
}

Expand All @@ -261,17 +264,20 @@ JNIEXPORT jobjectArray JNICALL Java_com_intellij_openapi_util_io_win32_IdeaWin32
}
while (FindNextFile(h, &data));

FindClose(h);
free(pathStr);
FindClose(h);

old = rv;
rv = env->NewObjectArray(len, fileInfoClass, NULL);
if (rv == NULL || !CopyObjectArray(env, rv, old, len)) {
goto error;
}

return rv;

error:
FindClose(h);
free(pathStr);
FindClose(h);
return NULL;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,11 +109,14 @@ public void testCircularLink() throws Exception {
assertEquals(upDir.getPath(), upLinkVFile.getCanonicalPath());
assertVisitedPaths(upDir.getPath(), upLinkVFile.getPath());

final File nestedLinksFile = new File(upDir.getPath() + StringUtil.repeat(File.separator + upLinkFile.getName(), 4));
assertTrue(nestedLinksFile.getPath(), nestedLinksFile.isDirectory());
final VirtualFile nestedLinksVFile = refreshAndFind(nestedLinksFile);
assertNotNull(nestedLinksFile.getPath(), nestedLinksVFile);
assertEquals(upLinkVFile.getCanonicalFile(), nestedLinksVFile.getCanonicalFile());
final File repeatedLinksFile = new File(upDir.getPath() + StringUtil.repeat(File.separator + upLinkFile.getName(), 4));
assertTrue(repeatedLinksFile.getPath(), repeatedLinksFile.isDirectory());
final VirtualFile repeatedLinksVFile = refreshAndFind(repeatedLinksFile);
assertNotNull(repeatedLinksFile.getPath(), repeatedLinksVFile);
assertTrue(repeatedLinksVFile.isSymLink());
assertTrue(repeatedLinksVFile.isDirectory());
assertEquals(upDir.getPath(), repeatedLinksVFile.getCanonicalPath());
assertEquals(upLinkVFile.getCanonicalFile(), repeatedLinksVFile.getCanonicalFile());
}

public void testMutualRecursiveLinks() throws Exception {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ public class IdeaWin32 {

private static final String PATH_PREFIX = "\\\\?\\";
private static final int PREFIX_SIZE = PATH_PREFIX.length();
private static final String PATH_SUFFIX = "\\*.*";
private static final int MAX_PATH = 260;

private static final IdeaWin32 ourInstance;
Expand Down Expand Up @@ -111,7 +110,7 @@ public String resolveSymLink(@NotNull final String path) {
@Nullable
public FileInfo[] listChildren(@NotNull final String path) {
LogUtil.debug(LOG, "list(%s)", path);
return listChildren0(path(path) + PATH_SUFFIX);
return listChildren0(path(path));
}

private static String path(final String path) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,22 @@ public void missingLink() throws Exception {
assertNull(target);
}

@Test
public void selfLink() throws Exception {
assumeTrue(SystemInfo.areSymLinksSupported);

final File dir = FileUtil.createTempDirectory(myTempDirectory, "test.", ".dir");
final File link = IoTestUtil.createTempLink(dir.getPath(), new File(dir, "link").getPath());

final FileAttributes attributes = getAttributes(link);
assertEquals(FileAttributes.Type.DIRECTORY, attributes.type);
assertEquals(FileAttributes.SYM_LINK, attributes.flags);
assertTimestampsEqual(dir.lastModified(), attributes.lastModified);

final String target = FileSystemUtil.resolveSymLink(link);
assertEquals(dir.getPath(), target);
}

@Test
public void junction() throws Exception {
assumeTrue(SystemInfo.isWindows);
Expand Down Expand Up @@ -235,7 +251,7 @@ public void wellHiddenFile() throws Exception {
final File file = new File("C:\\Documents and Settings\\desktop.ini");
assumeTrue(file.exists());

final FileAttributes attributes = getAttributes(file);
final FileAttributes attributes = getAttributes(file, false);
assertEquals(FileAttributes.Type.FILE, attributes.type);
assertEquals(FileAttributes.HIDDEN, attributes.flags);
assertEquals(file.length(), attributes.length);
Expand Down Expand Up @@ -302,9 +318,30 @@ public void hardLink() throws Exception {

@NotNull
private static FileAttributes getAttributes(@NotNull final File file) {
return getAttributes(file, true);
}

@NotNull
private static FileAttributes getAttributes(@NotNull final File file, final boolean checkList) {
final FileAttributes attributes = FileSystemUtil.getAttributes(file);
assertNotNull(attributes);
System.out.println(attributes);

if (SystemInfo.isWindows && checkList) {
final String parent = file.getParent();
if (parent != null) {
final FileInfo[] infos = IdeaWin32.getInstance().listChildren(parent);
assertNotNull(infos);
for (FileInfo info : infos) {
if (file.getName().equals(info.getName())) {
assertEquals(attributes, info.toFileAttributes());
return attributes;
}
}
fail(file + " not listed");
}
}

return attributes;
}

Expand Down

0 comments on commit b2ddcc7

Please sign in to comment.