Use fileAttributes to get more attributes in one go

On Windows the length reported by FileAttributes is the size
of the target file (a bug, I guess) rather than the link,
so we read the linke and look at the length of the link instead.

Bug: 353771
Change-Id: I834b06d0447f84379612b8c9190fa77093617595
Signed-off-by: Matthias Sohn <matthias.sohn@sap.com>
This commit is contained in:
Robin Rosenberg 2014-01-23 06:07:12 +01:00 committed by Matthias Sohn
parent 2852b6a07d
commit 14cd43e6df
7 changed files with 267 additions and 49 deletions

View File

@ -46,8 +46,6 @@
import java.io.File;
import java.io.IOException;
import org.eclipse.jgit.util.FS;
/**
* FS implementation for Java7 on unix like systems
*/
@ -150,4 +148,12 @@ public String readSymLink(File path) throws IOException {
public void createSymLink(File path, String target) throws IOException {
FileUtil.createSymLink(path, target);
}
/**
* @since 3.3
*/
@Override
public Attributes getAttributes(File path) {
return FileUtil.getFileAttributesPosix(this, path);
}
}

View File

@ -151,4 +151,12 @@ public String readSymLink(File path) throws IOException {
public void createSymLink(File path, String target) throws IOException {
FileUtil.createSymLink(path, target);
}
/**
* @since 3.3
*/
@Override
public Attributes getAttributes(File path) {
return FileUtil.getFileAttributesBasic(this, path);
}
}

View File

@ -127,4 +127,12 @@ public String readSymLink(File path) throws IOException {
public void createSymLink(File path, String target) throws IOException {
FileUtil.createSymLink(path, target);
}
/**
* @since 3.3
*/
@Override
public Attributes getAttributes(File path) {
return FileUtil.getFileAttributesBasic(this, path);
}
}

View File

@ -47,15 +47,33 @@
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.LinkOption;
import java.nio.file.NoSuchFileException;
import java.nio.file.Path;
import java.nio.file.attribute.BasicFileAttributeView;
import java.nio.file.attribute.BasicFileAttributes;
import java.nio.file.attribute.FileTime;
import java.nio.file.attribute.PosixFileAttributeView;
import java.nio.file.attribute.PosixFileAttributes;
import java.nio.file.attribute.PosixFilePermission;
import java.text.Normalizer;
import java.text.Normalizer.Form;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.util.FS.Attributes;
class FileUtil {
static class Java7BasicAttributes extends Attributes {
Java7BasicAttributes(FS fs, File fPath, boolean exists,
boolean isDirectory, boolean isExecutable,
boolean isSymbolicLink, boolean isRegularFile,
long creationTime, long lastModifiedTime, long length) {
super(fs, fPath, exists, isDirectory, isExecutable, isSymbolicLink,
isRegularFile, creationTime, lastModifiedTime, length);
}
}
static String readSymlink(File path) throws IOException {
Path nioPath = path.toPath();
Path target = Files.readSymbolicLink(nioPath);
@ -145,4 +163,63 @@ public static void delete(File path) throws IOException {
Files.delete(nioPath);
}
static Attributes getFileAttributesBasic(FS fs, File path) {
try {
Path nioPath = path.toPath();
BasicFileAttributes readAttributes = nioPath
.getFileSystem()
.provider()
.getFileAttributeView(nioPath,
BasicFileAttributeView.class,
LinkOption.NOFOLLOW_LINKS).readAttributes();
Attributes attributes = new FileUtil.Java7BasicAttributes(fs, path,
true,
readAttributes.isDirectory(),
fs.supportsExecute() ? path.canExecute() : false,
readAttributes.isSymbolicLink(),
readAttributes.isRegularFile(), //
readAttributes.creationTime().toMillis(), //
readAttributes.lastModifiedTime().toMillis(),
readAttributes.isSymbolicLink() ? Constants
.encode(FileUtils.readSymLink(path)).length
: readAttributes.size());
return attributes;
} catch (NoSuchFileException e) {
return new FileUtil.Java7BasicAttributes(fs, path, false, false,
false, false, false, 0L, 0L, 0L);
} catch (IOException e) {
return new Attributes(path, fs);
}
}
static Attributes getFileAttributesPosix(FS fs, File path) {
try {
Path nioPath = path.toPath();
PosixFileAttributes readAttributes = nioPath
.getFileSystem()
.provider()
.getFileAttributeView(nioPath,
PosixFileAttributeView.class,
LinkOption.NOFOLLOW_LINKS).readAttributes();
Attributes attributes = new FileUtil.Java7BasicAttributes(
fs,
path,
true, //
readAttributes.isDirectory(), //
readAttributes.permissions().contains(
PosixFilePermission.OWNER_EXECUTE),
readAttributes.isSymbolicLink(),
readAttributes.isRegularFile(), //
readAttributes.creationTime().toMillis(), //
readAttributes.lastModifiedTime().toMillis(),
readAttributes.size());
return attributes;
} catch (NoSuchFileException e) {
return new FileUtil.Java7BasicAttributes(fs, path, false, false,
false, false, false, 0L, 0L, 0L);
} catch (IOException e) {
return new Attributes(path, fs);
}
}
}

View File

@ -95,7 +95,7 @@ public FileTreeIteratorWithTimeControl(File f, FS fs,
@Override
public AbstractTreeIterator createSubtreeIterator(final ObjectReader reader) {
return new FileTreeIteratorWithTimeControl(this,
((FileEntry) current()).file, fs, modTimes);
((FileEntry) current()).getFile(), fs, modTimes);
}
@Override

View File

@ -132,7 +132,7 @@ protected FileTreeIterator(final WorkingTreeIterator p, final File root,
@Override
public AbstractTreeIterator createSubtreeIterator(final ObjectReader reader)
throws IncorrectObjectTypeException, IOException {
return new FileTreeIterator(this, ((FileEntry) current()).file, fs);
return new FileTreeIterator(this, ((FileEntry) current()).getFile(), fs);
}
private Entry[] entries() {
@ -149,13 +149,9 @@ private Entry[] entries() {
* Wrapper for a standard Java IO file
*/
static public class FileEntry extends Entry {
final File file;
private final FileMode mode;
private long length = -1;
private long lastModified;
private FS.Attributes attributes;
private FS fs;
@ -168,27 +164,17 @@ static public class FileEntry extends Entry {
* file system
*/
public FileEntry(final File f, FS fs) {
file = f;
this.fs = fs;
@SuppressWarnings("hiding")
FileMode mode = null;
try {
if (fs.isSymLink(f)) {
mode = FileMode.SYMLINK;
} else if (fs.isDirectory(f)) {
if (fs.exists(new File(f, Constants.DOT_GIT)))
mode = FileMode.GITLINK;
else
mode = FileMode.TREE;
} else if (fs.canExecute(file))
mode = FileMode.EXECUTABLE_FILE;
attributes = fs.getAttributes(f);
if (attributes.isDirectory()) {
if (new File(f, Constants.DOT_GIT).exists())
mode = FileMode.GITLINK;
else
mode = FileMode.REGULAR_FILE;
} catch (IOException e) {
mode = FileMode.MISSING;
}
this.mode = mode;
mode = FileMode.TREE;
} else if (attributes.isExecutable())
mode = FileMode.EXECUTABLE_FILE;
else
mode = FileMode.REGULAR_FILE;
}
@Override
@ -198,40 +184,27 @@ public FileMode getMode() {
@Override
public String getName() {
return file.getName();
return attributes.getName();
}
@Override
public long getLength() {
if (length < 0) {
try {
length = fs.length(file);
} catch (IOException e) {
length = 0;
}
}
return length;
return attributes.getLength();
}
@Override
public long getLastModified() {
if (lastModified == 0) {
try {
lastModified = fs.lastModified(file);
} catch (IOException e) {
lastModified = 0;
}
}
return lastModified;
return attributes.getLastModifiedTime();
}
@Override
public InputStream openInputStream() throws IOException {
if (fs.isSymLink(file))
return new ByteArrayInputStream(fs.readSymLink(file).getBytes(
if (fs.isSymLink(getFile()))
return new ByteArrayInputStream(fs.readSymLink(getFile())
.getBytes(
Constants.CHARACTER_ENCODING));
else
return new FileInputStream(file);
return new FileInputStream(getFile());
}
/**
@ -240,7 +213,7 @@ public InputStream openInputStream() throws IOException {
* @return the underlying file of this entry
*/
public File getFile() {
return file;
return attributes.getFile();
}
}

View File

@ -634,4 +634,150 @@ private static class Holder<V> {
this.value = value;
}
}
/**
* File attributes we typically care for.
*
* @since 3.3
*/
public static class Attributes {
/**
* @return true if this are the attributes of a directory
*/
public boolean isDirectory() {
return isDirectory;
}
/**
* @return true if this are the attributes of an executable file
*/
public boolean isExecutable() {
return isExecutable;
}
/**
* @return true if this are the attributes of a symbolic link
*/
public boolean isSymbolicLink() {
return isSymbolicLink;
}
/**
* @return true if this are the attributes of a regular file
*/
public boolean isRegularFile() {
return isRegularFile;
}
/**
* @return the time when the file was created
*/
public long getCreationTime() {
return creationTime;
}
/**
* @return the time (milliseconds since 1970-01-01) when this object was
* last modified
*/
public long getLastModifiedTime() {
return lastModifiedTime;
}
private boolean isDirectory;
private boolean isSymbolicLink;
private boolean isRegularFile;
private long creationTime;
private long lastModifiedTime;
private boolean isExecutable;
private File file;
private boolean exists;
/**
* file length
*/
protected long length = -1;
FS fs;
Attributes(FS fs, File file, boolean exists, boolean isDirectory,
boolean isExecutable, boolean isSymbolicLink,
boolean isRegularFile, long creationTime,
long lastModifiedTime, long length) {
this.fs = fs;
this.file = file;
this.exists = exists;
this.isDirectory = isDirectory;
this.isExecutable = isExecutable;
this.isSymbolicLink = isSymbolicLink;
this.isRegularFile = isRegularFile;
this.creationTime = creationTime;
this.lastModifiedTime = lastModifiedTime;
this.length = length;
}
/**
* Constructor when there are issues with reading
*
* @param fs
* @param path
*/
public Attributes(File path, FS fs) {
this.file = path;
this.fs = fs;
}
/**
* @return length of this file object
*/
public long getLength() {
if (length == -1)
return length = file.length();
return length;
}
/**
* @return the filename
*/
public String getName() {
return file.getName();
}
/**
* @return the file the attributes apply to
*/
public File getFile() {
return file;
}
boolean exists() {
return exists;
}
}
/**
* @param path
* @return the file attributes we care for
* @since 3.3
*/
public Attributes getAttributes(File path) {
boolean isDirectory = isDirectory(path);
boolean isFile = !isDirectory && path.isFile();
assert path.exists() == isDirectory || isFile;
boolean exists = isDirectory || isFile;
boolean canExecute = exists && !isDirectory && canExecute(path);
boolean isSymlink = false;
long lastModified = exists ? path.lastModified() : 0L;
long createTime = 0L;
return new Attributes(this, path, exists, isDirectory, canExecute,
isSymlink, isFile, createTime, lastModified, -1);
}
}