mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
One-shot fIle attributes reading
This commit is contained in:
@@ -308,7 +308,7 @@ public class JarHandlerBase {
|
||||
public FileAttributes getAttributes(@NotNull final VirtualFile file) {
|
||||
synchronized (lock) {
|
||||
final JarFile.JarEntry entry = convertToEntry(file);
|
||||
return entry != null ? new FileAttributes(entry.isDirectory(), false, false, entry.getSize(), entry.getTime(), false) : null;
|
||||
return entry != null ? new FileAttributes(entry.isDirectory(), false, false, false, entry.getSize(), entry.getTime(), false) : null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -382,6 +382,6 @@ public class TempFileSystem extends NewVirtualFileSystem {
|
||||
final FSItem item = convert(file);
|
||||
if (item == null) return null;
|
||||
final long length = item instanceof FSFile ? ((FSFile)item).myContent.length : 0;
|
||||
return new FileAttributes(item.isDirectory(), false, false, length, item.myTimestamp, item.myWritable);
|
||||
return new FileAttributes(item.isDirectory(), false, false, false, length, item.myTimestamp, item.myWritable);
|
||||
}
|
||||
}
|
||||
|
||||
+3
-3
@@ -20,7 +20,6 @@ import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.util.SystemInfo;
|
||||
import com.intellij.openapi.util.io.FileAttributes;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.vfs.LocalFileSystem;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.openapi.vfs.impl.local.LocalFileSystemBase;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
@@ -222,9 +221,10 @@ public class Win32LocalFileSystem extends LocalFileSystemBase {
|
||||
if (fileInfo == null) return null;
|
||||
|
||||
final boolean isDirectory = isSet(fileInfo.attributes, Win32Kernel.FILE_ATTRIBUTE_DIRECTORY);
|
||||
final boolean isSymlink = isSet(fileInfo.attributes, Win32Kernel.FILE_ATTRIBUTE_REPARSE_POINT);
|
||||
final boolean isSpecial = isSet(fileInfo.attributes, Win32Kernel.FILE_ATTRIBUTE_DEVICE);
|
||||
final boolean isSymlink = isSet(fileInfo.attributes, Win32Kernel.FILE_ATTRIBUTE_REPARSE_POINT);
|
||||
final boolean isHidden = isSet(fileInfo.attributes, Win32Kernel.FILE_ATTRIBUTE_HIDDEN);
|
||||
final boolean isWritable = !isSet(fileInfo.attributes, Win32Kernel.FILE_ATTRIBUTE_READONLY);
|
||||
return new FileAttributes(isDirectory, isSymlink, isSpecial, fileInfo.length, fileInfo.timestamp, isWritable);
|
||||
return new FileAttributes(isDirectory, isSpecial, isSymlink, isHidden, fileInfo.length, fileInfo.timestamp, isWritable);
|
||||
}
|
||||
}
|
||||
|
||||
+2
-29
@@ -15,13 +15,10 @@
|
||||
*/
|
||||
package com.intellij.openapi.vfs.local;
|
||||
|
||||
import com.intellij.execution.ExecutionException;
|
||||
import com.intellij.execution.configurations.GeneralCommandLine;
|
||||
import com.intellij.openapi.application.AccessToken;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.util.SystemInfo;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vfs.LocalFileSystem;
|
||||
import com.intellij.openapi.vfs.VfsUtilCore;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
@@ -30,6 +27,8 @@ import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import static com.intellij.openapi.util.io.IoTestUtil.createTempLink;
|
||||
|
||||
public class SymlinkHandlingTest extends LightPlatformLangTestCase {
|
||||
private LocalFileSystem myFileSystem;
|
||||
|
||||
@@ -265,32 +264,6 @@ public class SymlinkHandlingTest extends LightPlatformLangTestCase {
|
||||
assertEquals(vSubChild, vSubChildRel);
|
||||
}
|
||||
|
||||
// todo[r.sh] use NIO2 API after migration to JDK 7
|
||||
public static File createTempLink(final String target, final String link) throws InterruptedException, ExecutionException {
|
||||
final boolean isAbsolute = SystemInfo.isUnix && StringUtil.startsWithChar(link, '/') ||
|
||||
SystemInfo.isWindows && link.matches("^[c-zC-Z]:[/\\\\].*$");
|
||||
final File linkFile = isAbsolute ? new File(link) : new File(FileUtil.getTempDirectory(), link);
|
||||
assertTrue(link, !linkFile.exists() || linkFile.delete());
|
||||
final File parentDir = linkFile.getParentFile();
|
||||
assertTrue("link=" + link + ", parent=" + parentDir, parentDir != null && (parentDir.isDirectory() || parentDir.mkdirs()));
|
||||
|
||||
final GeneralCommandLine commandLine;
|
||||
if (SystemInfo.isWindows) {
|
||||
commandLine = new File(target).isDirectory()
|
||||
? new GeneralCommandLine("cmd", "/C", "mklink", "/D", linkFile.getAbsolutePath(), target)
|
||||
: new GeneralCommandLine("cmd", "/C", "mklink", linkFile.getAbsolutePath(), target);
|
||||
}
|
||||
else {
|
||||
commandLine = new GeneralCommandLine("ln", "-s", target, linkFile.getAbsolutePath());
|
||||
}
|
||||
final int res = commandLine.createProcess().waitFor();
|
||||
assertEquals(commandLine.getCommandLineString(), 0, res);
|
||||
|
||||
final File targetFile = new File(target);
|
||||
assertEquals("target=" + target + ", link=" + linkFile, targetFile.exists(), linkFile.exists());
|
||||
return linkFile;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private VirtualFile refreshAndFind(final File ioFile) {
|
||||
refresh();
|
||||
|
||||
@@ -18,12 +18,23 @@ package com.intellij.openapi.util.io;
|
||||
import com.intellij.util.StringBuilderSpinAllocator;
|
||||
import org.intellij.lang.annotations.MagicConstant;
|
||||
|
||||
import static com.intellij.util.BitUtil.isSet;
|
||||
import static com.intellij.util.BitUtil.notSet;
|
||||
|
||||
/**
|
||||
* @version 11.1
|
||||
* @see FileSystemUtil#getAttributes(String)
|
||||
*/
|
||||
@SuppressWarnings("OctalInteger")
|
||||
public final class FileAttributes {
|
||||
public static final int DIRECTORY = 0x0001;
|
||||
public static final int SPECIAL = 0x0002;
|
||||
public static final int SYM_LINK = 0x0010;
|
||||
public static final int HIDDEN = 0x0100;
|
||||
|
||||
@MagicConstant(flags = {DIRECTORY, SPECIAL, SYM_LINK, HIDDEN})
|
||||
public @interface FileType { }
|
||||
|
||||
public static final int OWNER_READ = 0400;
|
||||
public static final int OWNER_WRITE = 0200;
|
||||
public static final int OWNER_EXECUTE = 0100;
|
||||
@@ -34,52 +45,99 @@ public final class FileAttributes {
|
||||
public static final int OTHERS_WRITE = 0002;
|
||||
public static final int OTHERS_EXECUTE = 0001;
|
||||
|
||||
@MagicConstant(flags = {
|
||||
OWNER_READ, OWNER_WRITE, OWNER_EXECUTE, GROUP_READ, GROUP_WRITE, GROUP_EXECUTE, OTHERS_READ, OTHERS_WRITE, OTHERS_EXECUTE
|
||||
})
|
||||
@MagicConstant(flags = {OWNER_READ, OWNER_WRITE, OWNER_EXECUTE, GROUP_READ, GROUP_WRITE, GROUP_EXECUTE, OTHERS_READ, OTHERS_WRITE, OTHERS_EXECUTE})
|
||||
public @interface Permissions { }
|
||||
|
||||
public final boolean isFile;
|
||||
public final boolean isDirectory;
|
||||
public final boolean isSymlink;
|
||||
public final boolean isSpecial;
|
||||
|
||||
/** In bytes, 0 for symlinks and special files. */
|
||||
/**
|
||||
* {@linkplain #DIRECTORY} and {@linkplain #SPECIAL} bits are mutually exclusive, none of them set means a regular file.<br/>
|
||||
* {@linkplain #SYM_LINK} bit may be set along with above ones (which then denote a type of a link target).<br/>
|
||||
* {@linkplain #HIDDEN} bit may be only set on Windows.
|
||||
*/
|
||||
@FileType
|
||||
public final int type;
|
||||
|
||||
/**
|
||||
* In bytes, 0 for special files.<br/>
|
||||
* For symlinks - length of a link target.
|
||||
*/
|
||||
public final long length;
|
||||
|
||||
/** In milliseconds (note that actual resolution may be less accurate). */
|
||||
/**
|
||||
* In milliseconds (actual resolution depends on a file system and may be less accurate).<br/>
|
||||
* For symlinks - timestamp of a link target.
|
||||
*/
|
||||
public final long lastModified;
|
||||
|
||||
/** UNIX permission bits (for Windows only OWNER_WRITE matters and OWNER_READ/EXECUTE are always set), or -1 if not supported. */
|
||||
/**
|
||||
* UNIX permission bits (for Windows only OWNER_WRITE matters and OWNER_READ/EXECUTE are always set), or -1 if not supported.<br/>
|
||||
* For symlinks - permissions of a link target.
|
||||
*/
|
||||
@Permissions
|
||||
public final int permissions;
|
||||
|
||||
// todo: hidden flag (?)
|
||||
|
||||
public FileAttributes(final boolean isDirectory,
|
||||
final boolean isSymlink,
|
||||
final boolean isSpecial,
|
||||
final boolean isSymlink,
|
||||
final boolean isHidden,
|
||||
final long length,
|
||||
final long lastModified,
|
||||
final boolean writable) {
|
||||
this(isDirectory, isSymlink, isSpecial, length, lastModified, OWNER_READ | OWNER_EXECUTE | (writable ? OWNER_WRITE : 0));
|
||||
final boolean isWritable) {
|
||||
this(type(isDirectory, isSpecial, isSymlink, isHidden), length, lastModified, OWNER_READ | OWNER_EXECUTE | (isWritable ? OWNER_WRITE : 0));
|
||||
}
|
||||
|
||||
public FileAttributes(final boolean isDirectory,
|
||||
final boolean isSymlink,
|
||||
final boolean isSpecial,
|
||||
final boolean isSymlink,
|
||||
final long length,
|
||||
final long lastModified,
|
||||
@Permissions final int permissions) {
|
||||
this.isFile = !isDirectory && !isSymlink && !isSpecial;
|
||||
this.isDirectory = isDirectory;
|
||||
this.isSymlink = isSymlink;
|
||||
this.isSpecial = isSpecial;
|
||||
this.length = isSymlink || isSpecial ? 0 : length;
|
||||
this(type(isDirectory, isSpecial, isSymlink, false), length, lastModified, permissions);
|
||||
}
|
||||
|
||||
private FileAttributes(@FileType final int type,
|
||||
final long length,
|
||||
final long lastModified,
|
||||
@Permissions final int permissions) {
|
||||
if (isSet(type, DIRECTORY) && isSet(type, SPECIAL)) {
|
||||
throw new IllegalArgumentException("DIRECTORY and SPECIAL bits cannot be set simultaneously");
|
||||
}
|
||||
|
||||
this.type = type;
|
||||
this.length = length;
|
||||
this.lastModified = lastModified;
|
||||
this.permissions = permissions;
|
||||
}
|
||||
|
||||
@FileType
|
||||
private static int type(final boolean isDirectory, final boolean isSpecial, final boolean isSymlink, final boolean isHidden) {
|
||||
@FileType int type = 0;
|
||||
if (isDirectory) type |= DIRECTORY;
|
||||
if (isSpecial) type |= SPECIAL;
|
||||
if (isSymlink) type |= SYM_LINK;
|
||||
if (isHidden) type |= HIDDEN;
|
||||
return type;
|
||||
}
|
||||
|
||||
/** Is {@code true} for files and symlinks to files (see {@linkplain #isRegularFile()}). */
|
||||
public boolean isFile() {
|
||||
return notSet(type, DIRECTORY | SPECIAL);
|
||||
}
|
||||
|
||||
/** Is {@code true} for pure regular files only (see {@linkplain #isFile()}). */
|
||||
public boolean isRegularFile() {
|
||||
return notSet(type, DIRECTORY | SPECIAL | SYM_LINK);
|
||||
}
|
||||
|
||||
public boolean isSymLink() {
|
||||
return isSet(type, SYM_LINK);
|
||||
}
|
||||
|
||||
public boolean isWritable() {
|
||||
return permissions == -1 || isSet(permissions, OWNER_WRITE) || isSet(permissions, GROUP_WRITE) || isSet(permissions, OTHERS_WRITE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
@@ -87,10 +145,7 @@ public final class FileAttributes {
|
||||
|
||||
final FileAttributes that = (FileAttributes)o;
|
||||
|
||||
if (isDirectory != that.isDirectory) return false;
|
||||
if (isFile != that.isFile) return false;
|
||||
if (isSpecial != that.isSpecial) return false;
|
||||
if (isSymlink != that.isSymlink) return false;
|
||||
if (type != that.type) return false;
|
||||
if (lastModified != that.lastModified) return false;
|
||||
if (permissions != that.permissions) return false;
|
||||
if (length != that.length) return false;
|
||||
@@ -100,10 +155,7 @@ public final class FileAttributes {
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = (isFile ? 1 : 0);
|
||||
result = 31 * result + (isDirectory ? 1 : 0);
|
||||
result = 31 * result + (isSymlink ? 1 : 0);
|
||||
result = 31 * result + (isSpecial ? 1 : 0);
|
||||
int result = type;
|
||||
result = 31 * result + (int)(length ^ (length >>> 32));
|
||||
result = 31 * result + (int)(lastModified ^ (lastModified >>> 32));
|
||||
result = 31 * result + permissions;
|
||||
@@ -115,10 +167,10 @@ public final class FileAttributes {
|
||||
final StringBuilder sb = StringBuilderSpinAllocator.alloc();
|
||||
try {
|
||||
sb.append("[type:");
|
||||
if (isFile) sb.append('f');
|
||||
if (isDirectory) sb.append('d');
|
||||
if (isSymlink) sb.append('l');
|
||||
if (isSpecial) sb.append('!');
|
||||
if (isSet(type, DIRECTORY)) sb.append('d');
|
||||
else if (isSet(type, SPECIAL)) sb.append('!');
|
||||
else sb.append('f');
|
||||
if (isSet(type, SYM_LINK)) sb.append('l');
|
||||
|
||||
sb.append(" length:").append(length);
|
||||
|
||||
|
||||
@@ -18,12 +18,14 @@ package com.intellij.openapi.util.io;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.util.SystemInfo;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import com.intellij.util.SystemProperties;
|
||||
import com.sun.jna.Library;
|
||||
import com.sun.jna.Memory;
|
||||
import com.sun.jna.Native;
|
||||
import com.sun.jna.Pointer;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.annotations.TestOnly;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.reflect.Array;
|
||||
@@ -31,47 +33,55 @@ import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.*;
|
||||
|
||||
import static com.intellij.util.BitUtil.isSet;
|
||||
import static com.intellij.util.BitUtil.notSet;
|
||||
|
||||
/**
|
||||
* @version 11.1
|
||||
*/
|
||||
public class FileSystemUtil {
|
||||
public static final String FORCE_USE_NIO2_KEY = "idea.io.use.nio2";
|
||||
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.util.io.FileSystemUtil");
|
||||
|
||||
@NotNull
|
||||
private static final Mediator ourMediator;
|
||||
static {
|
||||
Mediator mediator = null;
|
||||
private static Mediator ourMediator = getMediator();
|
||||
|
||||
private static Mediator getMediator() {
|
||||
final boolean forceUseNio2 = SystemProperties.getBooleanProperty(FORCE_USE_NIO2_KEY, false);
|
||||
final String quickTestPath = SystemInfo.isWindows ? "C:\\" : "/";
|
||||
|
||||
// todo: move IdeaWin32 interface to this package, add mediator
|
||||
|
||||
if (SystemInfo.isLinux || SystemInfo.isMac || SystemInfo.isSolaris || SystemInfo.isFreeBSD) {
|
||||
if (!forceUseNio2 && (SystemInfo.isLinux || SystemInfo.isMac || SystemInfo.isSolaris || SystemInfo.isFreeBSD)) {
|
||||
try {
|
||||
mediator = new JnaUnixMediatorImpl();
|
||||
mediator.getAttributes("/"); // quick test
|
||||
final Mediator mediator = new JnaUnixMediatorImpl();
|
||||
mediator.getAttributes(quickTestPath);
|
||||
return mediator;
|
||||
}
|
||||
catch (Throwable t) {
|
||||
LOG.error(t);
|
||||
mediator = null;
|
||||
LOG.warn(t);
|
||||
}
|
||||
}
|
||||
|
||||
if (mediator == null && SystemInfo.isJavaVersionAtLeast("1.7") && !"1.7.0-ea".equals(SystemInfo.JAVA_VERSION)) {
|
||||
if (SystemInfo.isJavaVersionAtLeast("1.7") && !"1.7.0-ea".equals(SystemInfo.JAVA_VERSION)) {
|
||||
try {
|
||||
mediator = new Jdk7MediatorImpl();
|
||||
mediator.getAttributes("/"); // quick test
|
||||
final Mediator mediator = new Nio2MediatorImpl();
|
||||
mediator.getAttributes(quickTestPath);
|
||||
return mediator;
|
||||
}
|
||||
catch (Throwable t) {
|
||||
LOG.error(t);
|
||||
mediator = null;
|
||||
LOG.warn(t);
|
||||
}
|
||||
}
|
||||
|
||||
if (mediator == null) {
|
||||
// todo: after introducing IdeaWin32 mediator, fail tests at this point, or issue a warning in production
|
||||
mediator = new StandardMediatorImpl();
|
||||
}
|
||||
// todo: after introducing IdeaWin32 mediator, fail tests at this point, or issue a warning in production
|
||||
return new StandardMediatorImpl();
|
||||
}
|
||||
|
||||
ourMediator = mediator;
|
||||
@TestOnly
|
||||
static void resetMediator() {
|
||||
ourMediator = getMediator();
|
||||
}
|
||||
|
||||
private FileSystemUtil() { }
|
||||
@@ -87,14 +97,21 @@ public class FileSystemUtil {
|
||||
return null;
|
||||
}
|
||||
|
||||
@SuppressWarnings("UnusedDeclaration")
|
||||
@Nullable
|
||||
public static FileAttributes getAttributes(@NotNull final File file) {
|
||||
return getAttributes(file.getAbsolutePath());
|
||||
}
|
||||
|
||||
public static boolean isSymLink(@NotNull final String path) {
|
||||
if (SystemInfo.areSymLinksSupported) {
|
||||
final FileAttributes attributes = getAttributes(path);
|
||||
return attributes != null && attributes.isSymlink;
|
||||
return attributes != null && attributes.isSymLink();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@SuppressWarnings("UnusedDeclaration")
|
||||
public static boolean isSymLink(@NotNull final File file) {
|
||||
return isSymLink(file.getAbsolutePath());
|
||||
}
|
||||
@@ -113,6 +130,7 @@ public class FileSystemUtil {
|
||||
return null;
|
||||
}
|
||||
|
||||
@SuppressWarnings("UnusedDeclaration")
|
||||
@Nullable
|
||||
public static String resolveSymLink(@NotNull final File file) {
|
||||
return resolveSymLink(file.getAbsolutePath());
|
||||
@@ -123,6 +141,7 @@ public class FileSystemUtil {
|
||||
return attributes != null ? attributes.permissions : -1;
|
||||
}
|
||||
|
||||
@SuppressWarnings("UnusedDeclaration")
|
||||
public static int getPermissions(@NotNull final File file) {
|
||||
return getPermissions(file.getAbsolutePath());
|
||||
}
|
||||
@@ -154,7 +173,7 @@ public class FileSystemUtil {
|
||||
|
||||
// todo[r.sh] remove reflection after migration to JDK 7
|
||||
@SuppressWarnings("OctalInteger")
|
||||
private static class Jdk7MediatorImpl implements Mediator {
|
||||
private static class Nio2MediatorImpl implements Mediator {
|
||||
private final Object myDefaultFileSystem;
|
||||
private final Method myGetPath;
|
||||
private final Method myIsSymbolicLink;
|
||||
@@ -163,8 +182,9 @@ public class FileSystemUtil {
|
||||
private final Method myReadAttributes;
|
||||
private final Method mySetAttribute;
|
||||
private final Method myToMillis;
|
||||
private final String mySchema;
|
||||
|
||||
private Jdk7MediatorImpl() throws Exception {
|
||||
private Nio2MediatorImpl() throws Exception {
|
||||
myDefaultFileSystem = Class.forName("java.nio.file.FileSystems").getMethod("getDefault").invoke(null);
|
||||
|
||||
myGetPath = Class.forName("java.nio.file.FileSystem").getMethod("getPath", String.class, String[].class);
|
||||
@@ -189,29 +209,33 @@ public class FileSystemUtil {
|
||||
final Class<?> fileTimeClass = Class.forName("java.nio.file.attribute.FileTime");
|
||||
myToMillis = fileTimeClass.getMethod("toMillis");
|
||||
myToMillis.setAccessible(true);
|
||||
|
||||
mySchema = SystemInfo.isWindows ? "dos:*" : "posix:*";
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileAttributes getAttributes(@NotNull final String path) throws Exception {
|
||||
try {
|
||||
final Object pathObj = myGetPath.invoke(myDefaultFileSystem, path, ArrayUtil.EMPTY_STRING_ARRAY);
|
||||
|
||||
Map attributes = (Map)myReadAttributes.invoke(null, pathObj, mySchema, myNoFollowLinkOptions);
|
||||
final Boolean isSymbolicLink = (Boolean)attributes.get("isSymbolicLink");
|
||||
if (isSymbolicLink) {
|
||||
attributes = (Map)myReadAttributes.invoke(null, pathObj, mySchema, myLinkOptions);
|
||||
}
|
||||
|
||||
final boolean isDirectory = (Boolean)attributes.get("isDirectory");
|
||||
final boolean isOther = (Boolean)attributes.get("isOther");
|
||||
final long size = (Long)attributes.get("size");
|
||||
final long lastModified = (Long)myToMillis.invoke(attributes.get("lastModifiedTime"));
|
||||
if (SystemInfo.isWindows) {
|
||||
final Map attributes = (Map)myReadAttributes.invoke(null, pathObj, "dos:*", myNoFollowLinkOptions);
|
||||
return new FileAttributes((Boolean)attributes.get("isDirectory"),
|
||||
(Boolean)attributes.get("isSymbolicLink"),
|
||||
(Boolean)attributes.get("isOther"),
|
||||
(Long)attributes.get("size"),
|
||||
(Long)myToMillis.invoke(attributes.get("lastModifiedTime")),
|
||||
!(Boolean)attributes.get("readonly"));
|
||||
final boolean isHidden = (Boolean)attributes.get("hidden");
|
||||
final boolean isWritable = !(Boolean)attributes.get("readonly");
|
||||
return new FileAttributes(isDirectory, isOther, isSymbolicLink, isHidden, size, lastModified, isWritable);
|
||||
}
|
||||
else {
|
||||
final Map attributes = (Map)myReadAttributes.invoke(null, pathObj, "posix:*", myNoFollowLinkOptions);
|
||||
return new FileAttributes((Boolean)attributes.get("isDirectory"),
|
||||
(Boolean)attributes.get("isSymbolicLink"),
|
||||
(Boolean)attributes.get("isOther"),
|
||||
(Long)attributes.get("size"),
|
||||
(Long)myToMillis.invoke(attributes.get("lastModifiedTime")),
|
||||
decodePermissions(attributes.get("permissions")));
|
||||
final int permissions = decodePermissions(attributes.get("permissions"));
|
||||
return new FileAttributes(isDirectory, isOther, isSymbolicLink, size, lastModified, permissions);
|
||||
}
|
||||
}
|
||||
catch (InvocationTargetException e) {
|
||||
@@ -302,7 +326,9 @@ public class FileSystemUtil {
|
||||
int PERM_MASK = 0777;
|
||||
|
||||
int lstat(String path, Pointer stat);
|
||||
int stat(String path, Pointer stat);
|
||||
int __lxstat64(int ver, String path, Pointer stat);
|
||||
int __xstat64(int ver, String path, Pointer stat);
|
||||
int chmod(String path, int mode);
|
||||
}
|
||||
|
||||
@@ -333,20 +359,26 @@ public class FileSystemUtil {
|
||||
@Override
|
||||
public synchronized FileAttributes getAttributes(@NotNull final String path) throws Exception {
|
||||
mySharedMem.clear();
|
||||
final int res = SystemInfo.isLinux ? myLibC.__lxstat64(0, path, mySharedMem) : myLibC.lstat(path, mySharedMem);
|
||||
if (res == 0) {
|
||||
final int mode = (SystemInfo.isLinux ? mySharedMem.getInt(myModeOffset) : mySharedMem.getShort(myModeOffset)) & LibC.S_MASK;
|
||||
final boolean isDirectory = (mode & LibC.S_IFDIR) == LibC.S_IFDIR;
|
||||
final boolean isSymlink = (mode & LibC.S_IFLNK) == LibC.S_IFLNK;
|
||||
final boolean isSpecial = !isDirectory && !isSymlink && (mode & LibC.S_IFREG) == 0;
|
||||
final long size = mySharedMem.getLong(mySizeOffset);
|
||||
final long mTime1 = SystemInfo.is32Bit ? mySharedMem.getInt(myTimeOffset) : mySharedMem.getLong(myTimeOffset);
|
||||
final long mTime2 = SystemInfo.is32Bit ? mySharedMem.getInt(myTimeOffset + 4) : mySharedMem.getLong(myTimeOffset + 8);
|
||||
final long mTime = mTime1 * 1000 + mTime2 / 1000000;
|
||||
@FileAttributes.Permissions final int permissions = mode & LibC.PERM_MASK;
|
||||
return new FileAttributes(isDirectory, isSymlink, isSpecial, size, mTime, permissions);
|
||||
int res = SystemInfo.isLinux ? myLibC.__lxstat64(0, path, mySharedMem) : myLibC.lstat(path, mySharedMem);
|
||||
if (res != 0) return null;
|
||||
|
||||
int mode = (SystemInfo.isLinux ? mySharedMem.getInt(myModeOffset) : mySharedMem.getShort(myModeOffset)) & LibC.S_MASK;
|
||||
final boolean isSymlink = (mode & LibC.S_IFLNK) == LibC.S_IFLNK;
|
||||
if (isSymlink) {
|
||||
mySharedMem.clear();
|
||||
res = SystemInfo.isLinux ? myLibC.__xstat64(0, path, mySharedMem) : myLibC.stat(path, mySharedMem);
|
||||
if (res != 0) return null;
|
||||
mode = (SystemInfo.isLinux ? mySharedMem.getInt(myModeOffset) : mySharedMem.getShort(myModeOffset)) & LibC.S_MASK;
|
||||
}
|
||||
return null;
|
||||
|
||||
final boolean isDirectory = (mode & LibC.S_IFDIR) == LibC.S_IFDIR;
|
||||
final boolean isSpecial = !isDirectory && (mode & LibC.S_IFREG) == 0;
|
||||
final long size = mySharedMem.getLong(mySizeOffset);
|
||||
final long mTime1 = SystemInfo.is32Bit ? mySharedMem.getInt(myTimeOffset) : mySharedMem.getLong(myTimeOffset);
|
||||
final long mTime2 = SystemInfo.is32Bit ? mySharedMem.getInt(myTimeOffset + 4) : mySharedMem.getLong(myTimeOffset + 8);
|
||||
final long mTime = mTime1 * 1000 + mTime2 / 1000000;
|
||||
@FileAttributes.Permissions final int permissions = mode & LibC.PERM_MASK;
|
||||
return new FileAttributes(isDirectory, isSpecial, isSymlink, size, mTime, permissions);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -364,6 +396,7 @@ public class FileSystemUtil {
|
||||
// from java.io.FileSystem
|
||||
private static final int BA_REGULAR = 0x02;
|
||||
private static final int BA_DIRECTORY = 0x04;
|
||||
private static final int BA_HIDDEN = 0x08;
|
||||
|
||||
private final Object myFileSystem;
|
||||
private final Method myGetBooleanAttributes;
|
||||
@@ -393,16 +426,18 @@ public class FileSystemUtil {
|
||||
if (myFileSystem != null) {
|
||||
final int flags = (Integer)myGetBooleanAttributes.invoke(myFileSystem, file);
|
||||
if (flags != 0) {
|
||||
final boolean isDirectory = (flags & BA_DIRECTORY) != 0;
|
||||
final boolean isSpecial = (flags & (BA_REGULAR | BA_DIRECTORY)) == 0;
|
||||
return new FileAttributes(isDirectory, false, isSpecial, file.length(), file.lastModified(), file.canWrite());
|
||||
final boolean isDirectory = isSet(flags, BA_DIRECTORY);
|
||||
final boolean isSpecial = notSet(flags, BA_REGULAR | BA_DIRECTORY);
|
||||
final boolean isHidden = isSet(flags, BA_HIDDEN);
|
||||
return new FileAttributes(isDirectory, isSpecial, false, isHidden, file.length(), file.lastModified(), file.canWrite());
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (file.exists()) {
|
||||
final boolean isDirectory = file.isDirectory();
|
||||
final boolean isSpecial = !isDirectory && !file.isFile();
|
||||
return new FileAttributes(isDirectory, false, isSpecial, file.length(), file.lastModified(), file.canWrite());
|
||||
final boolean isHidden = file.isHidden();
|
||||
return new FileAttributes(isDirectory, isSpecial, false, isHidden, file.length(), file.lastModified(), file.canWrite());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -19,7 +19,11 @@ package com.intellij.util;
|
||||
* @since 27.03.2012
|
||||
*/
|
||||
public class BitUtil {
|
||||
public static boolean isSet(final int mask, final int flag) {
|
||||
return (mask & flag) == flag;
|
||||
public static boolean isSet(final int value, final int flag) {
|
||||
return (value & flag) == flag;
|
||||
}
|
||||
|
||||
public static boolean notSet(final int value, final int mask) {
|
||||
return (value & mask) == 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright 2000-2012 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.openapi.util.io;
|
||||
|
||||
import com.intellij.openapi.util.SystemInfo;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
|
||||
import static org.junit.Assume.assumeTrue;
|
||||
|
||||
public class FileAttributesNio2ReadingTest extends FileAttributesReadingTest {
|
||||
@BeforeClass
|
||||
public static void setUpClass() throws Exception {
|
||||
System.setProperty(FileSystemUtil.FORCE_USE_NIO2_KEY, "true");
|
||||
FileSystemUtil.resetMediator();
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void tearDownClass() throws Exception {
|
||||
System.setProperty(FileSystemUtil.FORCE_USE_NIO2_KEY, "");
|
||||
FileSystemUtil.resetMediator();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
assumeTrue(SystemInfo.isJavaVersionAtLeast("1.7"));
|
||||
super.setUp();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,147 @@
|
||||
/*
|
||||
* Copyright 2000-2012 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.openapi.util.io;
|
||||
|
||||
import com.intellij.openapi.util.SystemInfo;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.junit.Assume.assumeTrue;
|
||||
|
||||
public class FileAttributesReadingTest {
|
||||
private final byte[] myTestData = new byte[]{'t', 'e', 's', 't'};
|
||||
private File myTempDirectory;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
myTempDirectory = FileUtil.createTempDirectory(getClass().getName(), ".tmp");
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
if (myTempDirectory != null) {
|
||||
FileUtil.delete(myTempDirectory);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void regularFile() throws Exception {
|
||||
final File file = FileUtil.createTempFile(myTempDirectory, "test.", ".txt", true);
|
||||
FileUtil.writeToFile(file, myTestData);
|
||||
|
||||
final FileAttributes attributes = getAttributes(file);
|
||||
assertEquals(0, attributes.type);
|
||||
assertEquals(myTestData.length, attributes.length);
|
||||
assertTimestampEquals(file.lastModified(), attributes.lastModified);
|
||||
assertTrue(attributes.isWritable());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void directory() throws Exception {
|
||||
final File file = FileUtil.createTempDirectory(myTempDirectory, "test.", ".tmp");
|
||||
|
||||
final FileAttributes attributes = getAttributes(file);
|
||||
assertEquals(FileAttributes.DIRECTORY, attributes.type);
|
||||
assertEquals(file.length(), attributes.length);
|
||||
assertTimestampEquals(file.lastModified(), attributes.lastModified);
|
||||
assertTrue(attributes.isWritable());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void special() throws Exception {
|
||||
assumeTrue(SystemInfo.isUnix);
|
||||
final File file = new File("/dev/null");
|
||||
|
||||
final FileAttributes attributes = getAttributes(file);
|
||||
assertEquals(FileAttributes.SPECIAL, attributes.type);
|
||||
assertEquals(0, attributes.length);
|
||||
assertTrue(attributes.isWritable());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void linkToFile() throws Exception {
|
||||
final File file = FileUtil.createTempFile(myTempDirectory, "test.", ".txt", true);
|
||||
FileUtil.writeToFile(file, myTestData);
|
||||
assertTrue(file.setWritable(false, false));
|
||||
assertTrue(file.setLastModified(file.lastModified() - 5000));
|
||||
final File link = IoTestUtil.createTempLink(file.getPath(), new File(myTempDirectory, "link").getPath());
|
||||
|
||||
final FileAttributes attributes = getAttributes(link);
|
||||
assertEquals(FileAttributes.SYM_LINK, attributes.type);
|
||||
assertEquals(myTestData.length, attributes.length);
|
||||
assertTimestampEquals(file.lastModified(), attributes.lastModified);
|
||||
assertFalse(attributes.isWritable());
|
||||
|
||||
final String target = FileSystemUtil.resolveSymLink(link);
|
||||
assertEquals(file.getPath(), target);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doubleLink() throws Exception {
|
||||
final File file = FileUtil.createTempFile(myTempDirectory, "test.", ".txt", true);
|
||||
FileUtil.writeToFile(file, myTestData);
|
||||
assertTrue(file.setWritable(false, false));
|
||||
assertTrue(file.setLastModified(file.lastModified() - 5000));
|
||||
final File link1 = IoTestUtil.createTempLink(file.getPath(), new File(myTempDirectory, "link1").getPath());
|
||||
final File link2 = IoTestUtil.createTempLink(link1.getPath(), new File(myTempDirectory, "link2").getPath());
|
||||
|
||||
final FileAttributes attributes = getAttributes(link2);
|
||||
assertEquals(FileAttributes.SYM_LINK, attributes.type);
|
||||
assertEquals(myTestData.length, attributes.length);
|
||||
assertTimestampEquals(file.lastModified(), attributes.lastModified);
|
||||
assertFalse(attributes.isWritable());
|
||||
|
||||
final String target = FileSystemUtil.resolveSymLink(link2);
|
||||
assertEquals(file.getPath(), target);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void linkToDirectory() throws Exception {
|
||||
final File file = FileUtil.createTempDirectory(myTempDirectory, "test.", ".tmp");
|
||||
assertTrue(file.setWritable(false, false));
|
||||
assertTrue(file.setLastModified(file.lastModified() - 5000));
|
||||
final File link = IoTestUtil.createTempLink(file.getPath(), new File(myTempDirectory, "link").getPath());
|
||||
|
||||
final FileAttributes attributes = getAttributes(link);
|
||||
assertEquals(FileAttributes.DIRECTORY | FileAttributes.SYM_LINK, attributes.type);
|
||||
assertEquals(file.length(), attributes.length);
|
||||
assertTimestampEquals(file.lastModified(), attributes.lastModified);
|
||||
assertFalse(attributes.isWritable());
|
||||
|
||||
final String target = FileSystemUtil.resolveSymLink(link);
|
||||
assertEquals(file.getPath(), target);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static FileAttributes getAttributes(@NotNull final File file) {
|
||||
final FileAttributes attributes = FileSystemUtil.getAttributes(file.getPath());
|
||||
assertNotNull(attributes);
|
||||
System.out.println(attributes);
|
||||
return attributes;
|
||||
}
|
||||
|
||||
private static void assertTimestampEquals(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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright 2000-2012 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.openapi.util.io;
|
||||
|
||||
import com.intellij.openapi.util.SystemInfo;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class IoTestUtil {
|
||||
// todo[r.sh] use NIO2 API after migration to JDK 7
|
||||
public static File createTempLink(final String target, final String link) throws InterruptedException, IOException {
|
||||
final boolean isAbsolute = SystemInfo.isUnix && StringUtil.startsWithChar(link, '/') ||
|
||||
SystemInfo.isWindows && link.matches("^[c-zC-Z]:[/\\\\].*$");
|
||||
final File linkFile = isAbsolute ? new File(link) : new File(FileUtil.getTempDirectory(), link);
|
||||
assertTrue(link, !linkFile.exists() || linkFile.delete());
|
||||
final File parentDir = linkFile.getParentFile();
|
||||
assertTrue("link=" + link + ", parent=" + parentDir, parentDir != null && (parentDir.isDirectory() || parentDir.mkdirs()));
|
||||
|
||||
final ProcessBuilder commandLine;
|
||||
if (SystemInfo.isWindows) {
|
||||
commandLine = new File(target).isDirectory()
|
||||
? new ProcessBuilder("cmd", "/C", "mklink", "/D", linkFile.getAbsolutePath(), target)
|
||||
: new ProcessBuilder("cmd", "/C", "mklink", linkFile.getAbsolutePath(), target);
|
||||
}
|
||||
else {
|
||||
commandLine = new ProcessBuilder("ln", "-s", target, linkFile.getAbsolutePath());
|
||||
}
|
||||
final int res = commandLine.start().waitFor();
|
||||
assertEquals(commandLine.command().toString(), 0, res);
|
||||
|
||||
final File targetFile = new File(target);
|
||||
assertEquals("target=" + target + ", link=" + linkFile, targetFile.exists(), linkFile.exists());
|
||||
return linkFile;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user