franta-hg@11: /**
franta-hg@11: * Alt2XML
franta-hg@11: * Copyright © 2014 František Kučera (frantovo.cz)
franta-hg@11: *
franta-hg@11: * This program is free software: you can redistribute it and/or modify
franta-hg@11: * it under the terms of the GNU General Public License as published by
franta-hg@111: * the Free Software Foundation, version 3 of the License.
franta-hg@11: *
franta-hg@11: * This program is distributed in the hope that it will be useful,
franta-hg@11: * but WITHOUT ANY WARRANTY; without even the implied warranty of
franta-hg@11: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
franta-hg@11: * GNU General Public License for more details.
franta-hg@11: *
franta-hg@11: * You should have received a copy of the GNU General Public License
franta-hg@11: * along with this program. If not, see .
franta-hg@11: */
franta-hg@103: package cz.frantovo.alt2xml.in.fs;
franta-hg@2:
franta-hg@17: import cz.frantovo.alt2xml.AbstractAlt2XmlReader;
franta-hg@103: import java.io.File;
franta-hg@2: import java.io.IOException;
franta-hg@103: import java.net.URI;
franta-hg@103: import java.net.URISyntaxException;
franta-hg@106: import java.nio.ByteBuffer;
franta-hg@106: import java.nio.file.Files;
franta-hg@106: import java.nio.file.LinkOption;
franta-hg@106: import java.nio.file.Path;
franta-hg@106: import java.nio.file.attribute.PosixFilePermission;
franta-hg@106: import java.nio.file.attribute.UserDefinedFileAttributeView;
franta-hg@106: import java.nio.file.spi.FileSystemProvider;
franta-hg@106: import java.util.List;
franta-hg@106: import java.util.ArrayList;
franta-hg@106: import java.util.Set;
franta-hg@77: import java.util.logging.Logger;
franta-hg@103: import org.xml.sax.Attributes;
franta-hg@2: import org.xml.sax.InputSource;
franta-hg@2: import org.xml.sax.SAXException;
franta-hg@92: import org.xml.sax.helpers.AttributesImpl;
franta-hg@2:
franta-hg@2: /**
franta-hg@103: * Reads filesystem – hierarchical structure of directories and files.
franta-hg@2: *
franta-hg@17: * @author Ing. František Kučera (frantovo.cz)
franta-hg@2: */
franta-hg@17: public class Reader extends AbstractAlt2XmlReader {
franta-hg@13:
franta-hg@103: public static final String ROOT_ELEMENT = "fs";
franta-hg@103: public static final String DIR_ELEMENT = "dir";
franta-hg@103: public static final String FILE_ELEMENT = "file";
franta-hg@106: public static final String XATTR_ELEMENT = "xattr";
franta-hg@106: public static final String PERMISSIONS_ELEMENT = "mode";
franta-hg@106: public static final String PERMISSIONS_U_ELEMENT = "user";
franta-hg@106: public static final String PERMISSIONS_G_ELEMENT = "group";
franta-hg@106: public static final String PERMISSIONS_O_ELEMENT = "others";
franta-hg@103: public static final String NAME_ATTRIBUTE = "name";
franta-hg@106: public static final String ABSOLUTE_PATH_ATTRIBUTE = "path";
franta-hg@106: public static final String SIZE_ATTRIBUTE = "size";
franta-hg@77: private static final Logger log = Logger.getLogger(Reader.class.getName());
franta-hg@77:
franta-hg@106: /**
franta-hg@106: * indentation level
franta-hg@106: */
franta-hg@106: private int level = 0;
franta-hg@106:
franta-hg@2: @Override
franta-hg@6: public void parse(InputSource input) throws IOException, SAXException {
franta-hg@103: File dir = getFile(input.getSystemId());
franta-hg@77:
franta-hg@103: outputStart(dir);
franta-hg@103: outputDir(dir);
franta-hg@59: outputEnd();
franta-hg@59: }
franta-hg@59:
franta-hg@103: private File getFile(String systemId) throws IOException {
franta-hg@103: try {
franta-hg@103: return new File(new URI(systemId));
franta-hg@103: } catch (URISyntaxException e) {
franta-hg@103: throw new IOException("Invalid dir URI", e);
franta-hg@103: }
franta-hg@103: }
franta-hg@103:
franta-hg@106: private String getAbsolutePath(File file) throws IOException {
franta-hg@106: return file.getCanonicalFile().getAbsolutePath();
franta-hg@106: }
franta-hg@106:
franta-hg@106: private Attributes singleAttribute(String name, int value) {
franta-hg@106: AttributesImpl attributes = new AttributesImpl();
franta-hg@106: addAttribute(attributes, name, value);
franta-hg@106: return attributes;
franta-hg@106: }
franta-hg@109:
franta-hg@103: private Attributes singleAttribute(String name, String value) {
franta-hg@103: AttributesImpl attributes = new AttributesImpl();
franta-hg@106: addAttribute(attributes, name, value);
franta-hg@103: return attributes;
franta-hg@103: }
franta-hg@103:
franta-hg@106: private void addAttribute(AttributesImpl attributes, String name, int value) {
franta-hg@106: attributes.addAttribute(null, name, name, "xs:int", String.valueOf(value));
franta-hg@106: }
franta-hg@106:
franta-hg@106: private void addAttribute(AttributesImpl attributes, String name, long value) {
franta-hg@106: attributes.addAttribute(null, name, name, "xs:long", String.valueOf(value));
franta-hg@106: }
franta-hg@106:
franta-hg@106: private void addAttribute(AttributesImpl attributes, String name, String value) {
franta-hg@106: attributes.addAttribute(null, name, name, "xs:string", value);
franta-hg@106: }
franta-hg@106:
franta-hg@106: private void outputStart(File root) throws SAXException, IOException {
franta-hg@21: contentHandler.startDocument();
franta-hg@76: contentHandler.lineBreak();
franta-hg@106: contentHandler.startElement(null, null, ROOT_ELEMENT, singleAttribute(ABSOLUTE_PATH_ATTRIBUTE, getAbsolutePath(root)));
franta-hg@75: contentHandler.lineBreak();
franta-hg@59: }
franta-hg@59:
franta-hg@59: private void outputEnd() throws SAXException {
franta-hg@102: contentHandler.endElement(null, null, ROOT_ELEMENT);
franta-hg@75: contentHandler.lineBreak();
franta-hg@21: contentHandler.endDocument();
franta-hg@6: }
franta-hg@76:
franta-hg@106: private void outputFile(File file) throws SAXException, IOException {
franta-hg@106: level++;
franta-hg@106:
franta-hg@106: AttributesImpl attributes = new AttributesImpl();
franta-hg@106: addAttribute(attributes, NAME_ATTRIBUTE, file.getName());
franta-hg@106: addAttribute(attributes, ABSOLUTE_PATH_ATTRIBUTE, getAbsolutePath(file));
franta-hg@106: addAttribute(attributes, SIZE_ATTRIBUTE, file.length());
franta-hg@106:
franta-hg@106: contentHandler.indentation(level);
franta-hg@106: contentHandler.startElement(null, null, FILE_ELEMENT, attributes);
franta-hg@103: contentHandler.lineBreak();
franta-hg@77:
franta-hg@106: outputPermissions(file.toPath());
franta-hg@106: outputExtendedAttributes(file);
franta-hg@77:
franta-hg@106: contentHandler.indentation(level);
franta-hg@103: contentHandler.endElement(null, null, FILE_ELEMENT);
franta-hg@103: contentHandler.lineBreak();
franta-hg@106:
franta-hg@106: level--;
franta-hg@77: }
franta-hg@77:
franta-hg@106: private void outputDir(File dir) throws SAXException, IOException {
franta-hg@106: level++;
franta-hg@89:
franta-hg@106: final File[] children = dir.listFiles();
franta-hg@106:
franta-hg@106: AttributesImpl attributes = new AttributesImpl();
franta-hg@106: addAttribute(attributes, NAME_ATTRIBUTE, dir.getName());
franta-hg@106: addAttribute(attributes, ABSOLUTE_PATH_ATTRIBUTE, getAbsolutePath(dir));
franta-hg@106: addAttribute(attributes, SIZE_ATTRIBUTE, children.length);
franta-hg@106:
franta-hg@106: contentHandler.indentation(level);
franta-hg@106: contentHandler.startElement(null, null, DIR_ELEMENT, attributes);
franta-hg@103: contentHandler.lineBreak();
franta-hg@77:
franta-hg@106: outputPermissions(dir.toPath());
franta-hg@106: outputExtendedAttributes(dir);
franta-hg@106:
franta-hg@106: for (File file : children) {
franta-hg@103: if (file.isDirectory()) {
franta-hg@103: outputDir(file);
franta-hg@103: } else {
franta-hg@103: outputFile(file);
franta-hg@81: }
franta-hg@77: }
franta-hg@77:
franta-hg@106: contentHandler.indentation(level);
franta-hg@103: contentHandler.endElement(null, null, DIR_ELEMENT);
franta-hg@103: contentHandler.lineBreak();
franta-hg@106:
franta-hg@106: level--;
franta-hg@106: }
franta-hg@106:
franta-hg@106: private String encodeElementName(String originalName) {
franta-hg@106: /**
franta-hg@106: * TODO: encode and/or skip invalid characters
franta-hg@106: */
franta-hg@106: return originalName;
franta-hg@106: }
franta-hg@106:
franta-hg@106: private void outputPermissions(Path path) throws IOException, SAXException {
franta-hg@106: level++;
franta-hg@109: Set permissions = Files.getPosixFilePermissions(path); // TODO: maybe symlinks: LinkOption.NOFOLLOW_LINKS
franta-hg@106:
franta-hg@106: contentHandler.indentation(level);
franta-hg@106: contentHandler.startElement(null, PERMISSIONS_ELEMENT, PERMISSIONS_ELEMENT, singleAttribute("octal", getOctal(permissions)));
franta-hg@106: contentHandler.lineBreak();
franta-hg@106:
franta-hg@106: level++;
franta-hg@106:
franta-hg@106: outputPermission("owner", permissions.contains(PosixFilePermission.OWNER_READ), permissions.contains(PosixFilePermission.OWNER_WRITE), permissions.contains(PosixFilePermission.OWNER_EXECUTE));
franta-hg@106: outputPermission("group", permissions.contains(PosixFilePermission.GROUP_READ), permissions.contains(PosixFilePermission.GROUP_WRITE), permissions.contains(PosixFilePermission.GROUP_EXECUTE));
franta-hg@106: outputPermission("others", permissions.contains(PosixFilePermission.OTHERS_READ), permissions.contains(PosixFilePermission.OTHERS_WRITE), permissions.contains(PosixFilePermission.OTHERS_EXECUTE));
franta-hg@106:
franta-hg@106: level--;
franta-hg@106:
franta-hg@106: contentHandler.indentation(level);
franta-hg@106: contentHandler.endElement(null, PERMISSIONS_ELEMENT, PERMISSIONS_ELEMENT);
franta-hg@106: contentHandler.lineBreak();
franta-hg@106:
franta-hg@106: level--;
franta-hg@106: }
franta-hg@106:
franta-hg@106: private int getOctal(Set permissions) {
franta-hg@106: int octal = 0;
franta-hg@109:
franta-hg@106: octal = octal + 100 * (permissions.contains(PosixFilePermission.OWNER_READ) ? 4 : 0);
franta-hg@106: octal = octal + 100 * (permissions.contains(PosixFilePermission.OWNER_WRITE) ? 2 : 0);
franta-hg@106: octal = octal + 100 * (permissions.contains(PosixFilePermission.OWNER_EXECUTE) ? 1 : 0);
franta-hg@109:
franta-hg@106: octal = octal + 10 * (permissions.contains(PosixFilePermission.GROUP_READ) ? 4 : 0);
franta-hg@106: octal = octal + 10 * (permissions.contains(PosixFilePermission.GROUP_WRITE) ? 2 : 0);
franta-hg@106: octal = octal + 10 * (permissions.contains(PosixFilePermission.GROUP_EXECUTE) ? 1 : 0);
franta-hg@109:
franta-hg@106: octal = octal + 1 * (permissions.contains(PosixFilePermission.OTHERS_READ) ? 4 : 0);
franta-hg@106: octal = octal + 1 * (permissions.contains(PosixFilePermission.OTHERS_WRITE) ? 2 : 0);
franta-hg@106: octal = octal + 1 * (permissions.contains(PosixFilePermission.OTHERS_EXECUTE) ? 1 : 0);
franta-hg@106:
franta-hg@106: return octal;
franta-hg@106: }
franta-hg@106:
franta-hg@106: private void outputPermission(String name, boolean read, boolean write, boolean execute) throws SAXException {
franta-hg@106: contentHandler.indentation(level);
franta-hg@106: AttributesImpl attributes = new AttributesImpl();
franta-hg@106: attributes.addAttribute(null, "read", "read", "xs:boolean", String.valueOf(read));
franta-hg@106: attributes.addAttribute(null, "write", "write", "xs:boolean", String.valueOf(write));
franta-hg@106: attributes.addAttribute(null, "execute", "execute", "xs:boolean", String.valueOf(execute));
franta-hg@106: contentHandler.startElement(null, name, name, attributes);
franta-hg@106: contentHandler.endElement(null, name, name);
franta-hg@106: contentHandler.lineBreak();
franta-hg@106: }
franta-hg@106:
franta-hg@106: private void outputExtendedAttributes(File file) throws IOException, SAXException {
franta-hg@106: level++;
franta-hg@106:
franta-hg@106: final List extendedAttributes = getExtendedAttributes(file);
franta-hg@106:
franta-hg@106: if (!extendedAttributes.isEmpty()) {
franta-hg@106: contentHandler.indentation(level);
franta-hg@106: contentHandler.startElement(null, XATTR_ELEMENT, XATTR_ELEMENT, null);
franta-hg@106: contentHandler.lineBreak();
franta-hg@106: level++;
franta-hg@106: for (ExtendedAttribute ea : extendedAttributes) {
franta-hg@106: contentHandler.indentation(level);
franta-hg@106: String elementName = encodeElementName(ea.getKey());
franta-hg@106: contentHandler.textElement(ea.getValue(), null, elementName, elementName, null);
franta-hg@106: contentHandler.lineBreak();
franta-hg@106: }
franta-hg@106: level--;
franta-hg@106: contentHandler.indentation(level);
franta-hg@106: contentHandler.endElement(null, XATTR_ELEMENT, XATTR_ELEMENT);
franta-hg@106: contentHandler.lineBreak();
franta-hg@106: }
franta-hg@106:
franta-hg@106: level--;
franta-hg@106: }
franta-hg@106:
franta-hg@106: private List getExtendedAttributes(File file) throws IOException {
franta-hg@106:
franta-hg@106: List l = new ArrayList<>();
franta-hg@106:
franta-hg@106: Path path = file.toPath();
franta-hg@106: FileSystemProvider provider = path.getFileSystem().provider();
franta-hg@106: UserDefinedFileAttributeView attributes = provider.getFileAttributeView(path, UserDefinedFileAttributeView.class);
franta-hg@106:
franta-hg@106: for (String jménoAtributu : attributes.list()) {
franta-hg@106: ByteBuffer hodnotaAtributu = ByteBuffer.allocate(attributes.size(jménoAtributu));
franta-hg@106: attributes.read(jménoAtributu, hodnotaAtributu);
franta-hg@106: l.add(new ExtendedAttribute(jménoAtributu, hodnotaAtributu));
franta-hg@106: }
franta-hg@106:
franta-hg@106: return l;
franta-hg@106:
franta-hg@77: }
franta-hg@2: }