Read root path attributes by IdeaWin32

This commit is contained in:
Roman Shevchenko
2012-07-26 21:28:26 +02:00
parent aa87be5f96
commit 8bf4f5f2ef
7 changed files with 158 additions and 64 deletions
Binary file not shown.
Binary file not shown.
+14 -5
View File
@@ -142,15 +142,24 @@ 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) {
WIN32_FIND_DATA data;
HANDLE h = FindFileInner(env, path, &data);
bool isDrive = false;
if (env->GetStringLength(path) == 2) {
const jchar* str = env->GetStringChars(path, NULL);
isDrive = (str[1] == ':');
env->ReleaseStringChars(path, str);
}
if (h == INVALID_HANDLE_VALUE) {
if (GetLastError() != ERROR_ACCESS_DENIED) {
WIN32_FIND_DATA data;
HANDLE h = INVALID_HANDLE_VALUE;
if (!isDrive) {
h = FindFileInner(env, path, &data);
if (h == INVALID_HANDLE_VALUE && GetLastError() != ERROR_ACCESS_DENIED) {
return NULL;
}
}
// there is a chance that directory listing is denied but direct file access will succeed
if (h == INVALID_HANDLE_VALUE) {
WIN32_FILE_ATTRIBUTE_DATA attrData;
const jchar* str = env->GetStringChars(path, 0);
BOOL res = GetFileAttributesEx((LPCWSTR)str, GetFileExInfoStandard, &attrData);
@@ -15,13 +15,13 @@
*/
package com.intellij.openapi.vfs.local;
import com.intellij.execution.configurations.GeneralCommandLine;
import com.intellij.openapi.application.AccessToken;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.Ref;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.io.IoTestUtil;
import com.intellij.openapi.vfs.*;
import com.intellij.openapi.vfs.impl.local.FileWatcher;
import com.intellij.openapi.vfs.newvfs.BulkFileListener;
@@ -417,35 +417,16 @@ public class FileWatcherTest extends PlatformLangTestCase {
return;
}
final Set<Character> roots = ContainerUtil.map2Set(File.listRoots(), new Function<File, Character>() {
@Override
public Character fun(File root) {
return root.getPath().toLowerCase(Locale.US).charAt(0);
}
});
char subst = 0;
for (char c = 'e'; c <= 'z'; c++) {
if (!roots.contains(c)) {
subst = c;
break;
}
}
assertFalse("Occupied: " + roots.toString(), subst == 0);
final File targetDir = FileUtil.createTempDirectory("top.", null);
final File subDir = FileUtil.createTempDirectory(targetDir, "sub.", null);
final File file = FileUtil.createTempFile(subDir, "test.", ".txt", true, false);
final int rv = new GeneralCommandLine("subst", subst + ":", targetDir.getAbsolutePath()).createProcess().waitFor();
assertEquals(0, rv);
final String substRoot = (subst + ":").toUpperCase(Locale.US);
VirtualDirectoryImpl.allowRootAccess(substRoot);
final VirtualFile vfsRoot = myFileSystem.findFileByPath(substRoot);
assertNotNull(substRoot, vfsRoot);
final File rootFile = IoTestUtil.createSubst(targetDir.getAbsolutePath());
VirtualDirectoryImpl.allowRootAccess(rootFile.getPath());
final VirtualFile vfsRoot = myFileSystem.findFileByIoFile(rootFile);
try {
final File substDir = new File(substRoot, subDir.getName());
assertNotNull(rootFile.getPath(), vfsRoot);
final File substDir = new File(rootFile, subDir.getName());
final File substFile = new File(substDir, file.getName());
refresh(targetDir);
refresh(substDir);
@@ -476,10 +457,12 @@ public class FileWatcherTest extends PlatformLangTestCase {
}
finally {
delete(targetDir);
new GeneralCommandLine("subst", subst + ":", "/d").createProcess().waitFor();
((NewVirtualFile)vfsRoot).markDirty();
myFileSystem.refresh(false);
VirtualDirectoryImpl.disallowRootAccess(substRoot);
IoTestUtil.deleteSubst(rootFile.getPath());
if (vfsRoot != null) {
((NewVirtualFile)vfsRoot).markDirty();
myFileSystem.refresh(false);
}
VirtualDirectoryImpl.disallowRootAccess(rootFile.getPath());
}
}
@@ -97,22 +97,33 @@ public class IdeaWin32 {
@Nullable
public FileInfo getInfo(@NotNull final String path) {
return getInfo0(unc(path));
return getInfo0(path(path));
}
@Nullable
public String resolveSymLink(@NotNull final String path) {
final String result = resolveSymLink0(unc(path));
final String result = resolveSymLink0(path(path));
return result != null && result.startsWith(PATH_PREFIX) ? result.substring(PREFIX_SIZE) : result;
}
@Nullable
public FileInfo[] listChildren(@NotNull final String path) {
return listChildren0(unc(path) + PATH_SUFFIX);
return listChildren0(path(path) + PATH_SUFFIX);
}
private static String unc(final String path) {
return path.length() < MAX_PATH ? path : PATH_PREFIX + path;
private static String path(final String path) {
final int length = path.length();
if (length > 0 && path.charAt(length - 1) == '\\' || length >= MAX_PATH) {
final StringBuilder sb = new StringBuilder(path);
while (sb.length() > 0 && sb.charAt(sb.length() - 1) == '\\') {
sb.deleteCharAt(sb.length() - 1);
}
if (sb.length() >= MAX_PATH) {
sb.insert(0, PATH_PREFIX);
}
return sb.toString();
}
return path;
}
private native FileInfo getInfo0(String path);
@@ -26,6 +26,7 @@ import org.junit.BeforeClass;
import org.junit.Test;
import java.io.File;
import java.util.Arrays;
import static org.junit.Assert.*;
import static org.junit.Assume.assumeTrue;
@@ -67,12 +68,7 @@ public class FileAttributesReadingTest {
final File file = FileUtil.createTempFile(myTempDirectory, "test.", ".txt", true);
FileUtil.writeToFile(file, myTestData);
final FileAttributes attributes = getAttributes(file);
assertEquals(FileAttributes.Type.FILE, attributes.type);
assertEquals(0, attributes.flags);
assertEquals(myTestData.length, attributes.length);
assertTimestampEquals(file.lastModified(), attributes.lastModified);
assertTrue(attributes.isWritable());
assertFileAttributes(file);
}
@Test
@@ -83,8 +79,34 @@ public class FileAttributesReadingTest {
assertEquals(FileAttributes.Type.DIRECTORY, attributes.type);
assertEquals(0, attributes.flags);
assertEquals(file.length(), attributes.length);
assertTimestampEquals(file.lastModified(), attributes.lastModified);
assertTimestampsEqual(file.lastModified(), attributes.lastModified);
assertTrue(attributes.isWritable());
if (SystemInfo.isWindows) {
assertDirectoriesEqual(file);
}
}
@Test
public void root() throws Exception {
final File file = new File(SystemInfo.isWindows ? "C:\\" : "/");
final FileAttributes attributes = getAttributes(file);
assertEquals(FileAttributes.Type.DIRECTORY, attributes.type);
if (SystemInfo.isWindows) {
assertDirectoriesEqual(file);
}
}
@Test
public void badNames() throws Exception {
final File file = FileUtil.createTempFile(myTempDirectory, "test.", ".txt", true);
FileUtil.writeToFile(file, myTestData);
assertFileAttributes(new File(file.getPath() + StringUtil.repeat(File.separator, 3)));
assertFileAttributes(new File(file.getPath().replace(File.separator, StringUtil.repeat(File.separator, 3))));
assertFileAttributes(new File(file.getPath().replace(File.separator, File.separator + "." + File.separator)));
assertFileAttributes(new File(myTempDirectory,
File.separator + ".." + File.separator + myTempDirectory.getName() + File.separator + file.getName()));
}
@Test
@@ -113,7 +135,7 @@ public class FileAttributesReadingTest {
assertEquals(FileAttributes.Type.FILE, attributes.type);
assertEquals(FileAttributes.SYM_LINK, attributes.flags);
assertEquals(myTestData.length, attributes.length);
assertTimestampEquals(file.lastModified(), attributes.lastModified);
assertTimestampsEqual(file.lastModified(), attributes.lastModified);
assertFalse(attributes.isWritable());
final String target = FileSystemUtil.resolveSymLink(link);
@@ -135,7 +157,7 @@ public class FileAttributesReadingTest {
assertEquals(FileAttributes.Type.FILE, attributes.type);
assertEquals(FileAttributes.SYM_LINK, attributes.flags);
assertEquals(myTestData.length, attributes.length);
assertTimestampEquals(file.lastModified(), attributes.lastModified);
assertTimestampsEqual(file.lastModified(), attributes.lastModified);
assertFalse(attributes.isWritable());
final String target = FileSystemUtil.resolveSymLink(link2);
@@ -155,7 +177,7 @@ public class FileAttributesReadingTest {
assertEquals(FileAttributes.Type.DIRECTORY, attributes.type);
assertEquals(FileAttributes.SYM_LINK, attributes.flags);
assertEquals(file.length(), attributes.length);
assertTimestampEquals(file.lastModified(), attributes.lastModified);
assertTimestampsEqual(file.lastModified(), attributes.lastModified);
if (SystemInfo.isUnix) assertFalse(attributes.isWritable());
final String target = FileSystemUtil.resolveSymLink(link);
@@ -209,7 +231,7 @@ public class FileAttributesReadingTest {
assertEquals(FileAttributes.Type.FILE, attributes.type);
assertEquals(FileAttributes.HIDDEN, attributes.flags);
assertEquals(file.length(), attributes.length);
assertTimestampEquals(file.lastModified(), attributes.lastModified);
assertTimestampsEqual(file.lastModified(), attributes.lastModified);
}
@Test
@@ -231,19 +253,25 @@ public class FileAttributesReadingTest {
assertTrue(file.exists());
FileUtil.writeToFile(file, myTestData);
final FileAttributes attributes = getAttributes(file);
assertEquals(FileAttributes.Type.FILE, attributes.type);
assertEquals(0, attributes.flags);
assertEquals(myTestData.length, attributes.length);
assertTimestampEquals(file.lastModified(), attributes.lastModified);
assertTrue(attributes.isWritable());
assertFileAttributes(file);
if (SystemInfo.isWindows) {
final String[] list1 = dir.list();
assertNotNull(list1);
final FileInfo[] list2 = IdeaWin32.getInstance().listChildren(dir.getPath());
assertNotNull(list2);
assertEquals(list1.length + 2, list2.length);
assertDirectoriesEqual(dir);
}
}
@Test
public void subst() throws Exception {
assumeTrue(SystemInfo.isWindows);
FileUtil.createTempFile(myTempDirectory, "test.", ".txt", true); // just to populate a directory
final File substRoot = IoTestUtil.createSubst(myTempDirectory.getPath());
try {
final FileAttributes attributes = getAttributes(substRoot);
assertEquals(FileAttributes.Type.DIRECTORY, attributes.type);
assertDirectoriesEqual(substRoot);
}
finally {
IoTestUtil.deleteSubst(substRoot.getPath());
}
}
@@ -255,10 +283,29 @@ public class FileAttributesReadingTest {
return attributes;
}
private static void assertTimestampEquals(final long expected, final long actual) {
private static void assertFileAttributes(@NotNull final File file) {
final FileAttributes attributes = getAttributes(file);
assertEquals(FileAttributes.Type.FILE, attributes.type);
assertEquals(0, attributes.flags);
assertEquals(file.length(), attributes.length);
assertTimestampsEqual(file.lastModified(), attributes.lastModified);
assertTrue(attributes.isWritable());
}
private static void assertTimestampsEqual(final long expected, final long actual) {
final long roundedExpected = (expected / 1000) * 1000;
final long roundedActual = (actual / 1000) * 1000;
assertEquals("expected: " + expected + ", actual: " + actual,
roundedExpected, roundedActual);
}
private static void assertDirectoriesEqual(@NotNull final File dir) {
final String[] list1 = dir.list();
assertNotNull(list1);
final FileInfo[] list2 = IdeaWin32.getInstance().listChildren(dir.getPath());
assertNotNull(list2);
if (list1.length + 2 != list2.length) {
assertEquals(Arrays.toString(list1), Arrays.toString(list2));
}
}
}
@@ -17,6 +17,8 @@ package com.intellij.openapi.util.io;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.util.Function;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import java.io.BufferedReader;
@@ -24,9 +26,10 @@ import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.Locale;
import java.util.Set;
import static org.junit.Assert.*;
import static org.junit.Assert.assertEquals;
public class IoTestUtil {
private IoTestUtil() { }
@@ -92,6 +95,47 @@ public class IoTestUtil {
return junctionFile;
}
public static File createSubst(@NotNull final String target) throws InterruptedException, IOException {
assertTrue(SystemInfo.isWindows);
final File targetFile = new File(target);
assertTrue(targetFile.getPath(), targetFile.isDirectory());
final String substRoot = getFirstFreeDriveLetter() + ":";
final ProcessBuilder command = new ProcessBuilder("subst", substRoot, target);
final int res = runCommand(command);
assertEquals(command.command().toString(), 0, res);
final File rootFile = new File(substRoot);
assertTrue("target=" + target + ", subst=" + rootFile, rootFile.isDirectory());
return rootFile;
}
public static void deleteSubst(@NotNull final String substRoot) throws InterruptedException, IOException {
runCommand(new ProcessBuilder("subst", substRoot, "/d"));
}
private static char getFirstFreeDriveLetter() {
final Set<Character> roots = ContainerUtil.map2Set(File.listRoots(), new Function<File, Character>() {
@Override
public Character fun(File root) {
return root.getPath().toUpperCase(Locale.US).charAt(0);
}
});
char drive = 0;
for (char c = 'E'; c <= 'Z'; c++) {
if (!roots.contains(c)) {
drive = c;
break;
}
}
assertFalse("Occupied: " + roots.toString(), drive == 0);
return drive;
}
private static File getFullLinkPath(final String link) {
final boolean isAbsolute = SystemInfo.isUnix && StringUtil.startsWithChar(link, '/') ||
SystemInfo.isWindows && link.matches("^[c-zC-Z]:[/\\\\].*$");