package org.xmlsh.util;
import static java.nio.file.attribute.PosixFilePermission.*;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.LinkOption;
import java.nio.file.Path;
import java.nio.file.attribute.BasicFileAttributes;
import java.nio.file.attribute.DosFileAttributes;
import java.nio.file.attribute.FileTime;
import java.nio.file.attribute.PosixFileAttributes;
import java.nio.file.attribute.PosixFilePermission;
import java.nio.file.attribute.UserPrincipal;
import java.util.Collection;
import java.util.Collections;
import java.util.EnumSet;
import java.util.Set;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import lombok.extern.log4j.Log4j2;
@Log4j2
public class UnifiedFileAttributes {
public static enum FileType {
FILE("file"),
DIRECTORY("dir"),
SYMLINK("link"),
OTHER("other") ;
private String name;
FileType( String name){
this.name = name ;
}
public String toString()
{
return name ;
}
};
public static enum MatchFlag {
HIDDEN_SYS,
HIDDEN_NAME,
SYSTEM,
FILES,
DIRECTORIES,
LINKS,
OTHER,
READABLE,
WRITABLE,
EXECUTABLE
}
private PosixFileAttributes posix;
private BasicFileAttributes basic;
private DosFileAttributes dos ;
private Set<PosixFilePermission> posixPermissions;
private Path mPath ;
private boolean bInit = false ;
private boolean bExists = false ;
private LinkOption[] mLinkOpts;
public UnifiedFileAttributes(Path path, LinkOption... followLinks) {
this( path , null , followLinks );
}
public UnifiedFileAttributes(Path path, BasicFileAttributes attrs, LinkOption... followLinks) {
mLogger.entry(path, attrs, followLinks);
mPath = path;
mLinkOpts = followLinks;
setBasic(attrs);
mLogger.exit( );
}
private void init()
{
mLogger.entry();
try {
if( bInit )
return ;
// No basic attrs passed - check existance
if( basic == null ){
// Check if file exists first
if( ! Files.exists(mPath, mLinkOpts))
return ;
basic = FileUtils.getBasicFileAttributes(mPath, mLinkOpts);
}
bExists = true ;
this.posix = FileUtils.getPosixFileAttributes( mPath , mLinkOpts );
this.dos = FileUtils.getDosFileAttributes( mPath , mLinkOpts );
if( posix != null ){
if( basic == null )
basic = posix ;
posixPermissions = Collections.unmodifiableSet(posix.permissions());
}
if( basic == null ){
if( dos != null )
basic = dos ;
}
if(posixPermissions == null && dos != null ){
posixPermissions= FileUtils.emulatePosixFilePermissions(dos , mLinkOpts );
}
if( posixPermissions == null )
posixPermissions= FileUtils.emulatePosixFilePermissions(mPath, mLinkOpts );
} finally {
bInit = true ;
}
mLogger.exit();
}
public boolean hasBasic() {
if( ! bInit ) init() ;
return getBasic() != null ;
}
public boolean hasPosix() {
if( ! bInit ) init() ;
return getPosix() != null ;
}
public boolean hasDos() {
if( ! bInit ) init() ;
return getDos() != null ;
}
public boolean hasAny() {
if( ! bInit ) init() ;
if( ! bExists ) return false ;
return hasBasic() || hasDos() || hasPosix() ;
}
public UserPrincipal owner() {
if( ! bInit ) init() ;
return getPosix().owner();
}
public FileTime lastModifiedTime() {
if( ! bInit ) init() ;
return getBasic().lastModifiedTime();
}
public FileTime lastAccessTime() {
if( ! bInit ) init() ;
return getBasic().lastAccessTime();
}
public FileTime creationTime() {
if( ! bInit ) init() ;
if( ! bExists ) return null; ;
return getBasic().creationTime();
}
public boolean isRegularFile() {
if( ! bInit ) init() ;
if( ! bExists ) return false ;
return getBasic().isRegularFile();
}
public boolean isDirectory() {
if( ! bInit ) init() ;
if( ! bExists ) return false ;
return getBasic().isDirectory();
}
public boolean isSymbolicLink() {
if( ! bInit ) init() ;
if( ! bExists ) return false ;
return getBasic().isSymbolicLink();
}
public boolean isOther() {
if( ! bInit ) init() ;
if( ! bExists ) return true ;
return getBasic().isOther();
}
public long size() {
if( ! bInit ) init() ;
if( ! bExists ) return -1;
return getBasic().size();
}
public Object fileKey() {
if( ! bInit ) init() ;
if( ! bExists ) return null ;
return getBasic().fileKey();
}
public boolean isArchive() {
if( ! bInit ) init() ;
if( ! bExists ) return false ;
return
(getDos() == null) ? false : getDos().isArchive();
}
public boolean isSystem() {
if( ! bInit ) init() ;
if( ! bExists ) return false ;
return
(getDos() == null) ? false : getDos().isSystem();
}
public boolean isReadOnly() {
if( ! bInit ) init() ;
if( ! bExists ) return false ;
if( hasDos() )
return getDos().isReadOnly();
if( hasPosix()){
Set<PosixFilePermission> perms = getPosix().permissions();
return !( perms.contains(OWNER_WRITE ) ||
perms.contains(GROUP_WRITE ) ||
perms.contains(OTHERS_WRITE ) );
}
return false ;
}
public Set<PosixFilePermission> getPermissions() {
if( ! bInit ) init() ;
return Collections.unmodifiableSet(posixPermissions);
}
public boolean isHidden() {
if( ! bInit ) init() ;
if( ! bExists ) return false ;
if( getDos() != null && getDos().isHidden())
return true ;
try {
if( Files.isHidden(mPath))
return true ;
} catch (IOException e) {
FileUtils.mLogger.catching(e);
// try by name
}
return false ;
}
public boolean isHiddenName() {
return FileUtils.isHiddenName( mPath );
}
public UnifiedFileAttributes.FileType getFileType() {
if( ! bInit ) init() ;
if( ! bExists ) return FileType.OTHER;
if( isDirectory() )
return FileType.DIRECTORY ;
if( isRegularFile() )
return FileType.FILE ;
if( isOther() )
return FileType.OTHER ;
if( isSymbolicLink())
return FileType.SYMLINK ;
return FileType.OTHER ;
}
public boolean canRead() {
return Files.isReadable(mPath);
}
public boolean canWrite() {
return Files.isWritable(mPath);
}
public boolean canExecute() {
return Files.isExecutable(mPath);
}
public Path getPath() {
return mPath ;
}
public DosFileAttributes getDos() {
if( ! bInit ) init() ;
return dos;
}
private void setDos(DosFileAttributes dos) {
this.dos = dos;
}
public BasicFileAttributes getBasic() {
if( ! bInit ) init() ;
return basic;
}
private void setBasic(BasicFileAttributes basic) {
this.basic = basic;
}
public PosixFileAttributes getPosix() {
if( ! bInit ) init() ;
return posix;
}
private void setPosix(PosixFileAttributes posix) {
this.posix = posix;
}
public boolean isFlagMatch( MatchFlag flag )
{
if( ! bInit ) init() ;
if( ! bExists ) return false ;
switch( flag ){
case DIRECTORIES :
return isDirectory();
case EXECUTABLE:
return canExecute();
case FILES:
return isRegularFile();
case HIDDEN_NAME:
return isHiddenName();
case HIDDEN_SYS:
return isHidden();
case LINKS:
return isSymbolicLink();
case OTHER:
return isOther();
case READABLE:
return canRead();
case SYSTEM:
return isSymbolicLink();
case WRITABLE:
return canRead();
default:
return false ;
}
}
public boolean isAnyFlagMatch( EnumSet<MatchFlag> flags )
{
mLogger.entry( flags );
if( ! bInit ) init() ;
if( ! bExists )
return mLogger.exit(false );
for( MatchFlag flag : flags )
if( isFlagMatch(flag))
return mLogger.exit(true );
return mLogger.exit(false );
}
}