One-shot fIle attributes reading

This commit is contained in:
Roman Shevchenko
2012-07-20 20:31:24 +02:00
parent 8d41b95c52
commit ff9bfb9672
10 changed files with 428 additions and 120 deletions
@@ -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);
}
}
@@ -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);
}
}
@@ -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;
}
}