Skip to content

Commit

Permalink
Added FileInfo-API
Browse files Browse the repository at this point in the history
Added EasyFileInfo to wrap the result of DokanyFileSystem#getFileInformation (ByHandleFileInformation)
and Added FindFileInfo to wrap the result of DokanyFileSystem#findFiles (WinBase.WIN32_FIND_DATA) to aid in creating a wrapper ("EasyDokanFileSystem") for DokanyFileSystem
Added AbstractFileInfo as common base class for FileInfos (like EasyFileInfo and FindFileInfo)
Added DefaultFileTimePolicy to help in returning valid FileTimes to Dokan if unavailable to AbstractFileInfo

This commit is part of my effort to fix dokan-java's issue 32 (dokan-dev#32): Adding wrappers for high-level programming
  • Loading branch information
JaniruTEC committed May 7, 2020
1 parent 64f66e4 commit caf890c
Show file tree
Hide file tree
Showing 4 changed files with 413 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package dev.dokan.dokan_java.constants.dokan_java;

/**
* [TO BE REPLACED WITH LICENSE NOTE]
*/
public enum DefaultFileTimePolicy {

STATIC_YEAR_1601,
STATIC_YEAR_1970,
INHERIT_ELSE_1601,
INHERIT_ELSE_1970

}
166 changes: 166 additions & 0 deletions src/main/java/dev/dokan/dokan_java/wrappers/AbstractFileInfo.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
package dev.dokan.dokan_java.wrappers;

import dev.dokan.dokan_java.constants.dokan_java.DefaultFileTimePolicy;
import dev.dokan.dokan_java.constants.microsoft.FileAttribute;
import dev.dokan.dokan_java.structure.EnumIntegerSet;

import java.nio.file.attribute.FileTime;
import java.util.concurrent.atomic.AtomicInteger;

public class AbstractFileInfo {

//See field by same name in com.sun.jna.platform.win32.WinBase.FILETIME;
private final static long WINDOWS_EPOCH_0 = -11644473600000L;
private final static long UNIX_EPOCH_0 = 0;

private final static FileTime YEAR_1601 = FileTime.fromMillis(WINDOWS_EPOCH_0);
private final static FileTime YEAR_1970 = FileTime.fromMillis(UNIX_EPOCH_0);

private final AtomicInteger fileAttributes;

private FileTime creationTime;
private FileTime lastAccessTime;
private FileTime lastWriteTime;

private DefaultFileTimePolicy fileTimePolicy = DefaultFileTimePolicy.INHERIT_ELSE_1970;
private long fileSize;

public AbstractFileInfo(EnumIntegerSet<FileAttribute> attributes) {
this(attributes.isEmpty() ? FileAttribute.NORMAL.getMask() : attributes.toInt());
}

public AbstractFileInfo(int attributes) {
this.fileAttributes = new AtomicInteger(attributes);
}

public int getFlags() {
return this.fileAttributes.get();
}

public void setFlags(int flags) {
this.fileAttributes.set(flags);
}

public EnumIntegerSet<FileAttribute> getFileAttributes() {
return EnumIntegerSet.enumSetFromInt(this.fileAttributes.get(), FileAttribute.values());
}

public boolean getFlag(FileAttribute flag) {
return (this.fileAttributes.get() & flag.getMask()) != 0;
}

public boolean setFlag(FileAttribute flag) {
return updateFlag(flag, true);
}

public boolean unsetFlag(FileAttribute flag) {
return updateFlag(flag, false);
}

public boolean updateFlag(FileAttribute flag, boolean value) {
int prev = this.fileAttributes.getAndUpdate(current -> current & (value ? flag.getMask() : ~flag.getMask()));
return (prev & flag.getMask()) != 0;
}

public void setTimes(long creationTime, long lastAccessTime, long lastWriteTime) {
setCreationTime(creationTime);
setLastAccessTime(lastAccessTime);
setLastWriteTime(lastWriteTime);
}

public void setTimes(FileTime creationTime, FileTime lastAccessTime, FileTime lastWriteTime) {
setCreationTime(creationTime);
setLastAccessTime(lastAccessTime);
setLastWriteTime(lastWriteTime);
}

public FileTime getStaticCreationTime() {
return this.creationTime;
}

public FileTime getCreationTime() {
if(this.creationTime != null) {
return this.creationTime;
}
return getAlternateTime();
}

public void setCreationTime(FileTime creationTime) {
this.creationTime = creationTime;
}

public void setCreationTime(long millis) {
setCreationTime(FileTime.fromMillis(millis));
}

public FileTime getStaticLastWriteTime() {
return this.lastWriteTime;
}

public FileTime getLastWriteTime() {
if(this.lastWriteTime != null) {
return this.lastWriteTime;
}
return getAlternateTime();
}

public void setLastWriteTime(FileTime lastWriteTime) {
this.lastWriteTime = lastWriteTime;
}

public void setLastWriteTime(long millis) {
setLastWriteTime(FileTime.fromMillis(millis));
}

public FileTime getStaticLastAccessTime() {
return this.lastAccessTime;
}

public FileTime getLastAccessTime() {
if(this.lastAccessTime != null) {
return this.lastAccessTime;
}
return getAlternateTime();
}

public void setLastAccessTime(FileTime lastAccessTime) {
this.lastAccessTime = lastAccessTime;
}

public void setLastAccessTime(long millis) {
setLastAccessTime(FileTime.fromMillis(millis));
}

public long getFileSize() {
return this.fileSize;
}

public void setFileSize(long fileSize) {
this.fileSize = fileSize;
}

private FileTime getAlternateTime() {
if(this.fileTimePolicy == DefaultFileTimePolicy.STATIC_YEAR_1601) {
return YEAR_1601;
}
if(this.fileTimePolicy == DefaultFileTimePolicy.STATIC_YEAR_1970) {
return YEAR_1970;
}

//--> Inheritance
//#1 Priority: Last write Time
if(this.lastWriteTime != null) {
return this.lastWriteTime;
}
//#2 Priority: Creation Time
if(this.creationTime != null) {
return this.creationTime;
}
//#3 Priority: Access Time
if(this.lastAccessTime != null) {
return this.lastAccessTime;
}
//#4 Resort to default time by policy
return this.fileTimePolicy == DefaultFileTimePolicy.INHERIT_ELSE_1601 ? YEAR_1601 : YEAR_1970;
}
}
87 changes: 87 additions & 0 deletions src/main/java/dev/dokan/dokan_java/wrappers/EasyFileInfo.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package dev.dokan.dokan_java.wrappers;

import dev.dokan.dokan_java.constants.microsoft.FileAttribute;
import dev.dokan.dokan_java.structure.ByHandleFileInformation;
import dev.dokan.dokan_java.structure.EnumIntegerSet;

import java.nio.file.Path;

/**
* [TO BE REPLACED WITH LICENSE NOTE]
*/
public class EasyFileInfo extends AbstractFileInfo {

private final Path path;

private int volumeSerialNumber;
private long fileIndex;
private int numberOfLinks;

public EasyFileInfo(Path path) {
this(path, FileAttribute.NORMAL.getMask());
}

public EasyFileInfo(Path path, EnumIntegerSet<FileAttribute> attributes) {
super(attributes);
this.path = path;
}

public EasyFileInfo(Path path, int attributes) {
super(attributes);
this.path = path;
}

public Path getPath() {
return this.path;
}

public int getVolumeSerialNumber() {
return this.volumeSerialNumber;
}

public void setVolumeSerialNumber(int volumeSerialNumber) {
this.volumeSerialNumber = volumeSerialNumber;
}

public long getFileIndex() {
return this.fileIndex;
}

public void setFileIndex(long fileIndex) {
this.fileIndex = fileIndex;
}

public int getNumberOfLinks() {
return this.numberOfLinks;
}

public void setNumberOfLinks(int numberOfLinks) {
this.numberOfLinks = numberOfLinks;
}

public ByHandleFileInformation toByHandleFileInformation() {
return toByHandleFileInformation(this.path);
}

public ByHandleFileInformation toByHandleFileInformation(Path pathOverride) {
ByHandleFileInformation info = new ByHandleFileInformation(pathOverride,
getFlags(),
getCreationTime(),
getLastAccessTime(),
getLastWriteTime(),
this.volumeSerialNumber,
getFileSize(),
this.fileIndex);
info.nNumberOfLinks = this.numberOfLinks;

return info;
}

public void copyTo(ByHandleFileInformation byHandleFileInformation) {
copyTo(byHandleFileInformation, this.path);
}

public void copyTo(ByHandleFileInformation byHandleFileInformation, Path pathOverride) {
toByHandleFileInformation(pathOverride).copyTo(byHandleFileInformation); //That's not the most efficient way to do this, but it's less prone to human error
}
}
Loading

0 comments on commit caf890c

Please sign in to comment.