001package org.unix4j.unix.ls; 002 003import org.unix4j.line.SimpleLine; 004import org.unix4j.processor.LineProcessor; 005import org.unix4j.util.FileUtil; 006import org.unix4j.util.StringUtil; 007 008import java.io.File; 009import java.io.IOException; 010import java.nio.file.Files; 011import java.nio.file.attribute.PosixFileAttributeView; 012import java.nio.file.attribute.PosixFilePermission; 013import java.util.Calendar; 014import java.util.List; 015import java.util.Locale; 016import java.util.Set; 017 018/** 019 * Formatter for long file output including permissions, owner, size etc. An 020 * example output with long format looks like this: 021 * 022 * <pre> 023 * -rw-r--r--@ 1 myself geeks 1.6K May 8 23:20 EFMTool Test Case.zip 024 * -rw-r--r-- 1 myself myself 2.6M May 5 2011 EM_FX_RANK_2011-1.pages 025 * -rw-r--r-- 1 myself geeks 466K May 5 2011 EM_FX_RANK_2011-1.pdf 026 * -rw-r--r-- 1 myself geeks 1.3M May 5 2011 EM_FX_RANK_2011.pdf 027 * -rw-r--r--@ 1 myself geeks 118M Apr 11 2011 PS_AIO_07_B110_USW_Full_Mac_WW_11.dmg 028 * drwxrwxrwx 5 myself geeks 170B Mar 6 2011 Private Tax 029 * -rw-r--r-- 1 myself myself 37M Apr 26 2011 Scanned Image 111160000.pdf 030 * -rw-r--r-- 1 myself mysel 37M Apr 26 2011 Scanned Image 111160008.pdf 031 * drwxrwxrwx 9 myself geeks 306B Apr 19 2011 aevum 032 * drwxr-xr-x 3 myself geeks 102B Dec 21 2011 baby 033 * drwxr-xr-x 4 myself geeks 136B May 18 2011 bills 034 * drwxrwxrwx 17 myself geeks 578B Jun 15 11:21 cv 035 * </pre> 036 */ 037final class LsFormatterLong implements LsFormatter { 038 039 private final ThreadLocal<Calendar> calendar = ThreadLocal.withInitial(Calendar::getInstance); 040 private final ThreadLocal<Integer> maxSizeStringLength = ThreadLocal.withInitial(() -> Integer.valueOf(0)); 041 042 @Override 043 public boolean writeFormatted(File relativeTo, File file, LsArguments args, LineProcessor output) { 044 return output.processLine( 045 new SimpleLine( 046 getFilePermissions(file, args) + ' ' + 047 getOwner(file, args) + ' ' + 048 getGroup(file, args) + ' ' + 049 getSize(file, args) + ' ' + 050 getDateTime(file, args) + ' ' + 051 getName(relativeTo, file, args) 052 ) 053 ); 054 } 055 056 LsFormatterLong(List<File> directoryFiles, LsArguments args) { 057 maxSizeStringLength.set(calculateMaxSizeStringLength(directoryFiles, args)); 058 } 059 060 private String getOwner(File file, LsArguments args) { 061 try { 062 final String owner = Files.getOwner(file.toPath()).getName(); 063 return StringUtil.fixSizeString(7, true, owner); 064 } catch (IOException e) { 065 return StringUtil.fixSizeString(7, true, "???"); 066 } 067 } 068 069 private String getGroup(File file, LsArguments args) { 070 try { 071 final PosixFileAttributeView view = Files.getFileAttributeView(file.toPath(), PosixFileAttributeView.class); 072 final String group = view.readAttributes().group().getName(); 073 return StringUtil.fixSizeString(7, true, group); 074 } catch (Exception e) { 075 return StringUtil.fixSizeString(7, true, "???"); 076 } 077 } 078 079 private String getFilePermissions(File file, LsArguments args) { 080 try { 081 final Set<PosixFilePermission> perms = Files.getPosixFilePermissions(file.toPath()); 082 return (file.isDirectory() ? "d" : "-") + 083 (perms.contains(PosixFilePermission.OWNER_READ) ? 'r' : '-') + 084 (perms.contains(PosixFilePermission.OWNER_WRITE) ? 'w' : '-') + 085 (perms.contains(PosixFilePermission.OWNER_EXECUTE) ? 'x' : '-') + 086 (perms.contains(PosixFilePermission.GROUP_READ) ? 'r' : '-') + 087 (perms.contains(PosixFilePermission.GROUP_WRITE) ? 'w' : '-') + 088 (perms.contains(PosixFilePermission.GROUP_EXECUTE) ? 'x' : '-') + 089 (perms.contains(PosixFilePermission.OTHERS_READ) ? 'r' : '-') + 090 (perms.contains(PosixFilePermission.OTHERS_WRITE) ? 'w' : '-') + 091 (perms.contains(PosixFilePermission.OTHERS_EXECUTE) ? 'x' : '-'); 092 } catch (Exception e) { 093 final boolean r = file.canRead(); 094 final boolean w = file.canWrite(); 095 final boolean x = file.canExecute(); 096 return (file.isDirectory() ? "d" : "-") + 097 //owner 098 (r ? 'r' : '-') + 099 (w ? 'w' : '-') + 100 (x ? 'x' : '-') + 101 //group 102 (r ? '.' : '-') + 103 (w ? '.' : '-') + 104 (x ? '.' : '-') + 105 //other 106 (r ? '.' : '-') + 107 (w ? '.' : '-') + 108 (x ? '.' : '-'); 109 } 110 } 111 112 private long getLastModifiedMS(File file, LsArguments args) { 113 try { 114 return Files.getLastModifiedTime(file.toPath()).toMillis(); 115 } catch (Exception e) { 116 return file.lastModified(); 117 } 118 } 119 120 private String getDateTime(File file, LsArguments args) { 121 final Calendar cal = calendar.get(); 122 cal.setTimeInMillis(System.currentTimeMillis());//set current date to get current year below 123 final int curYear = cal.get(Calendar.YEAR); 124 cal.setTimeInMillis(getLastModifiedMS(file, args)); 125 final int fileYear = cal.get(Calendar.YEAR); 126 final String month = cal.getDisplayName(Calendar.MONTH, Calendar.SHORT, Locale.getDefault()); 127 128 final String sM = StringUtil.fixSizeString(3, true, month); 129 final String sD = StringUtil.fixSizeString(2, false, ' ', cal.get(Calendar.DAY_OF_MONTH)); 130 if (curYear == fileYear) { 131 final String sHou = StringUtil.fixSizeString(2, false, '0', cal.get(Calendar.HOUR_OF_DAY)); 132 final String sMin = StringUtil.fixSizeString(2, false, '0', cal.get(Calendar.MINUTE)); 133 return sM + ' ' + sD + ' ' + sHou + ':' + sMin; 134 } else { 135 final String sY = StringUtil.fixSizeString(5, false, ' ', fileYear); 136 return sM + ' ' + sD + ' ' + sY; 137 } 138 } 139 140 protected String getName(File relativeTo, File file, LsArguments args) { 141 return FileUtil.getRelativePath(relativeTo, file); 142 } 143 144 private String getSize(File file, LsArguments args) { 145 long size; 146 try { 147 size = Files.size(file.toPath()); 148 } catch (Exception e) { 149 size = file.length(); 150 } 151 final String sizeString = LsCommand.getSizeString(args, size); 152 return StringUtil.fixSizeString(maxSizeStringLength.get(), false, sizeString); 153 } 154 155 private static int calculateMaxSizeStringLength(List<File> directoryFiles, LsArguments args) { 156 int maxSizeStringLength = 0; 157 for (final File f : directoryFiles) { 158 if (f.isFile()) { 159 if (f.isFile()) { 160 final String sizeString = LsCommand.getSizeString(args, f.length()); 161 maxSizeStringLength = Math.max(maxSizeStringLength, sizeString.length()); 162 } 163 } 164 } 165 return maxSizeStringLength; 166 } 167}