in-fs: permissions and extended attributes
authorFrantišek Kučera <franta-hg@frantovo.cz>
Wed, 29 Oct 2014 02:03:14 +0100
changeset 10602739f60b1ec
parent 105 e62a3e498212
child 107 c5a987931ef9
in-fs: permissions and extended attributes
java/alt2xml-in-fs/src/cz/frantovo/alt2xml/in/fs/ExtendedAttribute.java
java/alt2xml-in-fs/src/cz/frantovo/alt2xml/in/fs/Reader.java
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/java/alt2xml-in-fs/src/cz/frantovo/alt2xml/in/fs/ExtendedAttribute.java	Wed Oct 29 02:03:14 2014 +0100
     1.3 @@ -0,0 +1,77 @@
     1.4 +/**
     1.5 + * Alt2XML
     1.6 + * Copyright © 2014 František Kučera (frantovo.cz)
     1.7 + *
     1.8 + * This program is free software: you can redistribute it and/or modify
     1.9 + * it under the terms of the GNU General Public License as published by
    1.10 + * the Free Software Foundation, either version 3 of the License, or
    1.11 + * (at your option) any later version.
    1.12 + *
    1.13 + * This program is distributed in the hope that it will be useful,
    1.14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
    1.15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    1.16 + * GNU General Public License for more details.
    1.17 + *
    1.18 + * You should have received a copy of the GNU General Public License
    1.19 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
    1.20 + */
    1.21 +package cz.frantovo.alt2xml.in.fs;
    1.22 +
    1.23 +import java.nio.ByteBuffer;
    1.24 +import java.nio.charset.Charset;
    1.25 +
    1.26 +public class ExtendedAttribute {
    1.27 +
    1.28 +	private String key;
    1.29 +	private String value;
    1.30 +
    1.31 +	public ExtendedAttribute(String key, String value) {
    1.32 +		this.key = key;
    1.33 +		this.value = value;
    1.34 +	}
    1.35 +
    1.36 +	public ExtendedAttribute(String key, ByteBuffer value) {
    1.37 +		this.key = key;
    1.38 +		setValue(value);
    1.39 +	}
    1.40 +
    1.41 +	public ExtendedAttribute() {
    1.42 +	}
    1.43 +
    1.44 +	public String getKey() {
    1.45 +		return key;
    1.46 +	}
    1.47 +
    1.48 +	public void setKey(String key) {
    1.49 +		this.key = key;
    1.50 +	}
    1.51 +
    1.52 +	public String getValue() {
    1.53 +		return value;
    1.54 +	}
    1.55 +
    1.56 +	public final ByteBuffer getValueBytes() {
    1.57 +		return encode(getValue());
    1.58 +	}
    1.59 +
    1.60 +	public void setValue(String value) {
    1.61 +		this.value = value;
    1.62 +	}
    1.63 +
    1.64 +	public final void setValue(ByteBuffer value) {
    1.65 +		setValue(decode(value));
    1.66 +	}
    1.67 +
    1.68 +	private static String decode(ByteBuffer bytes) {
    1.69 +		bytes.flip();
    1.70 +		return Charset.defaultCharset().decode(bytes).toString();
    1.71 +	}
    1.72 +
    1.73 +	private static ByteBuffer encode(String text) {
    1.74 +		if (text == null) {
    1.75 +			return null;
    1.76 +		} else {
    1.77 +			return Charset.defaultCharset().encode(text);
    1.78 +		}
    1.79 +	}
    1.80 +}
     2.1 --- a/java/alt2xml-in-fs/src/cz/frantovo/alt2xml/in/fs/Reader.java	Wed Oct 29 01:25:06 2014 +0100
     2.2 +++ b/java/alt2xml-in-fs/src/cz/frantovo/alt2xml/in/fs/Reader.java	Wed Oct 29 02:03:14 2014 +0100
     2.3 @@ -22,6 +22,16 @@
     2.4  import java.io.IOException;
     2.5  import java.net.URI;
     2.6  import java.net.URISyntaxException;
     2.7 +import java.nio.ByteBuffer;
     2.8 +import java.nio.file.Files;
     2.9 +import java.nio.file.LinkOption;
    2.10 +import java.nio.file.Path;
    2.11 +import java.nio.file.attribute.PosixFilePermission;
    2.12 +import java.nio.file.attribute.UserDefinedFileAttributeView;
    2.13 +import java.nio.file.spi.FileSystemProvider;
    2.14 +import java.util.List;
    2.15 +import java.util.ArrayList;
    2.16 +import java.util.Set;
    2.17  import java.util.logging.Logger;
    2.18  import org.xml.sax.Attributes;
    2.19  import org.xml.sax.InputSource;
    2.20 @@ -38,10 +48,21 @@
    2.21  	public static final String ROOT_ELEMENT = "fs";
    2.22  	public static final String DIR_ELEMENT = "dir";
    2.23  	public static final String FILE_ELEMENT = "file";
    2.24 -	public static final String ROOT_ATTRIBUTE = "root";
    2.25 +	public static final String XATTR_ELEMENT = "xattr";
    2.26 +	public static final String PERMISSIONS_ELEMENT = "mode";
    2.27 +	public static final String PERMISSIONS_U_ELEMENT = "user";
    2.28 +	public static final String PERMISSIONS_G_ELEMENT = "group";
    2.29 +	public static final String PERMISSIONS_O_ELEMENT = "others";
    2.30  	public static final String NAME_ATTRIBUTE = "name";
    2.31 +	public static final String ABSOLUTE_PATH_ATTRIBUTE = "path";
    2.32 +	public static final String SIZE_ATTRIBUTE = "size";
    2.33  	private static final Logger log = Logger.getLogger(Reader.class.getName());
    2.34  
    2.35 +	/**
    2.36 +	 * indentation level
    2.37 +	 */
    2.38 +	private int level = 0;
    2.39 +
    2.40  	@Override
    2.41  	public void parse(InputSource input) throws IOException, SAXException {
    2.42  		File dir = getFile(input.getSystemId());
    2.43 @@ -59,16 +80,38 @@
    2.44  		}
    2.45  	}
    2.46  
    2.47 +	private String getAbsolutePath(File file) throws IOException {
    2.48 +		return file.getCanonicalFile().getAbsolutePath();
    2.49 +	}
    2.50 +
    2.51 +	private Attributes singleAttribute(String name, int value) {
    2.52 +		AttributesImpl attributes = new AttributesImpl();
    2.53 +		addAttribute(attributes, name, value);
    2.54 +		return attributes;
    2.55 +	}
    2.56 +	
    2.57  	private Attributes singleAttribute(String name, String value) {
    2.58  		AttributesImpl attributes = new AttributesImpl();
    2.59 -		attributes.addAttribute(null, name, name, "xs:string", value);
    2.60 +		addAttribute(attributes, name, value);
    2.61  		return attributes;
    2.62  	}
    2.63  
    2.64 -	private void outputStart(File root) throws SAXException {
    2.65 +	private void addAttribute(AttributesImpl attributes, String name, int value) {
    2.66 +		attributes.addAttribute(null, name, name, "xs:int", String.valueOf(value));
    2.67 +	}
    2.68 +
    2.69 +	private void addAttribute(AttributesImpl attributes, String name, long value) {
    2.70 +		attributes.addAttribute(null, name, name, "xs:long", String.valueOf(value));
    2.71 +	}
    2.72 +
    2.73 +	private void addAttribute(AttributesImpl attributes, String name, String value) {
    2.74 +		attributes.addAttribute(null, name, name, "xs:string", value);
    2.75 +	}
    2.76 +
    2.77 +	private void outputStart(File root) throws SAXException, IOException {
    2.78  		contentHandler.startDocument();
    2.79  		contentHandler.lineBreak();
    2.80 -		contentHandler.startElement(null, null, ROOT_ELEMENT, singleAttribute(ROOT_ATTRIBUTE, root.getAbsolutePath()));
    2.81 +		contentHandler.startElement(null, null, ROOT_ELEMENT, singleAttribute(ABSOLUTE_PATH_ATTRIBUTE, getAbsolutePath(root)));
    2.82  		contentHandler.lineBreak();
    2.83  	}
    2.84  
    2.85 @@ -78,22 +121,46 @@
    2.86  		contentHandler.endDocument();
    2.87  	}
    2.88  
    2.89 -	private void outputFile(File file) throws SAXException {
    2.90 -		contentHandler.startElement(null, null, FILE_ELEMENT, singleAttribute(NAME_ATTRIBUTE, file.getName()));
    2.91 +	private void outputFile(File file) throws SAXException, IOException {
    2.92 +		level++;
    2.93 +
    2.94 +		AttributesImpl attributes = new AttributesImpl();
    2.95 +		addAttribute(attributes, NAME_ATTRIBUTE, file.getName());
    2.96 +		addAttribute(attributes, ABSOLUTE_PATH_ATTRIBUTE, getAbsolutePath(file));
    2.97 +		addAttribute(attributes, SIZE_ATTRIBUTE, file.length());
    2.98 +
    2.99 +		contentHandler.indentation(level);
   2.100 +		contentHandler.startElement(null, null, FILE_ELEMENT, attributes);
   2.101  		contentHandler.lineBreak();
   2.102  
   2.103 -		//contentHandler.characters(file.getName());
   2.104 +		outputPermissions(file.toPath());
   2.105 +		outputExtendedAttributes(file);
   2.106  
   2.107 +		contentHandler.indentation(level);
   2.108  		contentHandler.endElement(null, null, FILE_ELEMENT);
   2.109  		contentHandler.lineBreak();
   2.110 +
   2.111 +		level--;
   2.112  	}
   2.113  
   2.114 -	private void outputDir(File dir) throws SAXException {
   2.115 +	private void outputDir(File dir) throws SAXException, IOException {
   2.116 +		level++;
   2.117  
   2.118 -		contentHandler.startElement(null, null, DIR_ELEMENT, singleAttribute(NAME_ATTRIBUTE, dir.getName()));
   2.119 +		final File[] children = dir.listFiles();
   2.120 +
   2.121 +		AttributesImpl attributes = new AttributesImpl();
   2.122 +		addAttribute(attributes, NAME_ATTRIBUTE, dir.getName());
   2.123 +		addAttribute(attributes, ABSOLUTE_PATH_ATTRIBUTE, getAbsolutePath(dir));
   2.124 +		addAttribute(attributes, SIZE_ATTRIBUTE, children.length);
   2.125 +
   2.126 +		contentHandler.indentation(level);
   2.127 +		contentHandler.startElement(null, null, DIR_ELEMENT, attributes);
   2.128  		contentHandler.lineBreak();
   2.129  
   2.130 -		for (File file : dir.listFiles()) {
   2.131 +		outputPermissions(dir.toPath());
   2.132 +		outputExtendedAttributes(dir);
   2.133 +
   2.134 +		for (File file : children) {
   2.135  			if (file.isDirectory()) {
   2.136  				outputDir(file);
   2.137  			} else {
   2.138 @@ -101,7 +168,112 @@
   2.139  			}
   2.140  		}
   2.141  
   2.142 +		contentHandler.indentation(level);
   2.143  		contentHandler.endElement(null, null, DIR_ELEMENT);
   2.144  		contentHandler.lineBreak();
   2.145 +
   2.146 +		level--;
   2.147 +	}
   2.148 +
   2.149 +	private String encodeElementName(String originalName) {
   2.150 +		/**
   2.151 +		 * TODO: encode and/or skip invalid characters
   2.152 +		 */
   2.153 +		return originalName;
   2.154 +	}
   2.155 +
   2.156 +	private void outputPermissions(Path path) throws IOException, SAXException {
   2.157 +		level++;
   2.158 +		Set<PosixFilePermission> permissions = Files.getPosixFilePermissions(path, LinkOption.NOFOLLOW_LINKS);
   2.159 +
   2.160 +		contentHandler.indentation(level);
   2.161 +		contentHandler.startElement(null, PERMISSIONS_ELEMENT, PERMISSIONS_ELEMENT, singleAttribute("octal", getOctal(permissions)));
   2.162 +		contentHandler.lineBreak();
   2.163 +
   2.164 +		level++;
   2.165 +
   2.166 +		outputPermission("owner", permissions.contains(PosixFilePermission.OWNER_READ), permissions.contains(PosixFilePermission.OWNER_WRITE), permissions.contains(PosixFilePermission.OWNER_EXECUTE));
   2.167 +		outputPermission("group", permissions.contains(PosixFilePermission.GROUP_READ), permissions.contains(PosixFilePermission.GROUP_WRITE), permissions.contains(PosixFilePermission.GROUP_EXECUTE));
   2.168 +		outputPermission("others", permissions.contains(PosixFilePermission.OTHERS_READ), permissions.contains(PosixFilePermission.OTHERS_WRITE), permissions.contains(PosixFilePermission.OTHERS_EXECUTE));
   2.169 +
   2.170 +		level--;
   2.171 +
   2.172 +		contentHandler.indentation(level);
   2.173 +		contentHandler.endElement(null, PERMISSIONS_ELEMENT, PERMISSIONS_ELEMENT);
   2.174 +		contentHandler.lineBreak();
   2.175 +
   2.176 +		level--;
   2.177 +	}
   2.178 +
   2.179 +	private int getOctal(Set<PosixFilePermission> permissions) {
   2.180 +		int octal = 0;
   2.181 +		
   2.182 +		octal = octal + 100 * (permissions.contains(PosixFilePermission.OWNER_READ) ? 4 : 0);
   2.183 +		octal = octal + 100 * (permissions.contains(PosixFilePermission.OWNER_WRITE) ? 2 : 0);
   2.184 +		octal = octal + 100 * (permissions.contains(PosixFilePermission.OWNER_EXECUTE) ? 1 : 0);
   2.185 +		
   2.186 +		octal = octal + 10 * (permissions.contains(PosixFilePermission.GROUP_READ) ? 4 : 0);
   2.187 +		octal = octal + 10 * (permissions.contains(PosixFilePermission.GROUP_WRITE) ? 2 : 0);
   2.188 +		octal = octal + 10 * (permissions.contains(PosixFilePermission.GROUP_EXECUTE) ? 1 : 0);
   2.189 +		
   2.190 +		octal = octal + 1 * (permissions.contains(PosixFilePermission.OTHERS_READ) ? 4 : 0);
   2.191 +		octal = octal + 1 * (permissions.contains(PosixFilePermission.OTHERS_WRITE) ? 2 : 0);
   2.192 +		octal = octal + 1 * (permissions.contains(PosixFilePermission.OTHERS_EXECUTE) ? 1 : 0);
   2.193 +
   2.194 +		return octal;
   2.195 +	}
   2.196 +
   2.197 +	private void outputPermission(String name, boolean read, boolean write, boolean execute) throws SAXException {
   2.198 +		contentHandler.indentation(level);
   2.199 +		AttributesImpl attributes = new AttributesImpl();
   2.200 +		attributes.addAttribute(null, "read", "read", "xs:boolean", String.valueOf(read));
   2.201 +		attributes.addAttribute(null, "write", "write", "xs:boolean", String.valueOf(write));
   2.202 +		attributes.addAttribute(null, "execute", "execute", "xs:boolean", String.valueOf(execute));
   2.203 +		contentHandler.startElement(null, name, name, attributes);
   2.204 +		contentHandler.endElement(null, name, name);
   2.205 +		contentHandler.lineBreak();
   2.206 +	}
   2.207 +
   2.208 +	private void outputExtendedAttributes(File file) throws IOException, SAXException {
   2.209 +		level++;
   2.210 +
   2.211 +		final List<ExtendedAttribute> extendedAttributes = getExtendedAttributes(file);
   2.212 +
   2.213 +		if (!extendedAttributes.isEmpty()) {
   2.214 +			contentHandler.indentation(level);
   2.215 +			contentHandler.startElement(null, XATTR_ELEMENT, XATTR_ELEMENT, null);
   2.216 +			contentHandler.lineBreak();
   2.217 +			level++;
   2.218 +			for (ExtendedAttribute ea : extendedAttributes) {
   2.219 +				contentHandler.indentation(level);
   2.220 +				String elementName = encodeElementName(ea.getKey());
   2.221 +				contentHandler.textElement(ea.getValue(), null, elementName, elementName, null);
   2.222 +				contentHandler.lineBreak();
   2.223 +			}
   2.224 +			level--;
   2.225 +			contentHandler.indentation(level);
   2.226 +			contentHandler.endElement(null, XATTR_ELEMENT, XATTR_ELEMENT);
   2.227 +			contentHandler.lineBreak();
   2.228 +		}
   2.229 +
   2.230 +		level--;
   2.231 +	}
   2.232 +
   2.233 +	private List<ExtendedAttribute> getExtendedAttributes(File file) throws IOException {
   2.234 +
   2.235 +		List<ExtendedAttribute> l = new ArrayList<>();
   2.236 +
   2.237 +		Path path = file.toPath();
   2.238 +		FileSystemProvider provider = path.getFileSystem().provider();
   2.239 +		UserDefinedFileAttributeView attributes = provider.getFileAttributeView(path, UserDefinedFileAttributeView.class);
   2.240 +
   2.241 +		for (String jménoAtributu : attributes.list()) {
   2.242 +			ByteBuffer hodnotaAtributu = ByteBuffer.allocate(attributes.size(jménoAtributu));
   2.243 +			attributes.read(jménoAtributu, hodnotaAtributu);
   2.244 +			l.add(new ExtendedAttribute(jménoAtributu, hodnotaAtributu));
   2.245 +		}
   2.246 +
   2.247 +		return l;
   2.248 +
   2.249  	}
   2.250  }