java/alt2xml-in-fs/src/cz/frantovo/alt2xml/in/fs/Reader.java
author František Kučera <franta-hg@frantovo.cz>
Wed, 29 Oct 2014 02:03:14 +0100
changeset 106 02739f60b1ec
parent 103 5e22fa13e016
child 109 76df01fc4aa2
permissions -rw-r--r--
in-fs: permissions and extended attributes
franta-hg@11
     1
/**
franta-hg@11
     2
 * Alt2XML
franta-hg@11
     3
 * Copyright © 2014 František Kučera (frantovo.cz)
franta-hg@11
     4
 *
franta-hg@11
     5
 * This program is free software: you can redistribute it and/or modify
franta-hg@11
     6
 * it under the terms of the GNU General Public License as published by
franta-hg@11
     7
 * the Free Software Foundation, either version 3 of the License, or
franta-hg@11
     8
 * (at your option) any later version.
franta-hg@11
     9
 *
franta-hg@11
    10
 * This program is distributed in the hope that it will be useful,
franta-hg@11
    11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
franta-hg@11
    12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
franta-hg@11
    13
 * GNU General Public License for more details.
franta-hg@11
    14
 *
franta-hg@11
    15
 * You should have received a copy of the GNU General Public License
franta-hg@11
    16
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
franta-hg@11
    17
 */
franta-hg@103
    18
package cz.frantovo.alt2xml.in.fs;
franta-hg@2
    19
franta-hg@17
    20
import cz.frantovo.alt2xml.AbstractAlt2XmlReader;
franta-hg@103
    21
import java.io.File;
franta-hg@2
    22
import java.io.IOException;
franta-hg@103
    23
import java.net.URI;
franta-hg@103
    24
import java.net.URISyntaxException;
franta-hg@106
    25
import java.nio.ByteBuffer;
franta-hg@106
    26
import java.nio.file.Files;
franta-hg@106
    27
import java.nio.file.LinkOption;
franta-hg@106
    28
import java.nio.file.Path;
franta-hg@106
    29
import java.nio.file.attribute.PosixFilePermission;
franta-hg@106
    30
import java.nio.file.attribute.UserDefinedFileAttributeView;
franta-hg@106
    31
import java.nio.file.spi.FileSystemProvider;
franta-hg@106
    32
import java.util.List;
franta-hg@106
    33
import java.util.ArrayList;
franta-hg@106
    34
import java.util.Set;
franta-hg@77
    35
import java.util.logging.Logger;
franta-hg@103
    36
import org.xml.sax.Attributes;
franta-hg@2
    37
import org.xml.sax.InputSource;
franta-hg@2
    38
import org.xml.sax.SAXException;
franta-hg@92
    39
import org.xml.sax.helpers.AttributesImpl;
franta-hg@2
    40
franta-hg@2
    41
/**
franta-hg@103
    42
 * Reads filesystem – hierarchical structure of directories and files.
franta-hg@2
    43
 *
franta-hg@17
    44
 * @author Ing. František Kučera (frantovo.cz)
franta-hg@2
    45
 */
franta-hg@17
    46
public class Reader extends AbstractAlt2XmlReader {
franta-hg@13
    47
franta-hg@103
    48
	public static final String ROOT_ELEMENT = "fs";
franta-hg@103
    49
	public static final String DIR_ELEMENT = "dir";
franta-hg@103
    50
	public static final String FILE_ELEMENT = "file";
franta-hg@106
    51
	public static final String XATTR_ELEMENT = "xattr";
franta-hg@106
    52
	public static final String PERMISSIONS_ELEMENT = "mode";
franta-hg@106
    53
	public static final String PERMISSIONS_U_ELEMENT = "user";
franta-hg@106
    54
	public static final String PERMISSIONS_G_ELEMENT = "group";
franta-hg@106
    55
	public static final String PERMISSIONS_O_ELEMENT = "others";
franta-hg@103
    56
	public static final String NAME_ATTRIBUTE = "name";
franta-hg@106
    57
	public static final String ABSOLUTE_PATH_ATTRIBUTE = "path";
franta-hg@106
    58
	public static final String SIZE_ATTRIBUTE = "size";
franta-hg@77
    59
	private static final Logger log = Logger.getLogger(Reader.class.getName());
franta-hg@77
    60
franta-hg@106
    61
	/**
franta-hg@106
    62
	 * indentation level
franta-hg@106
    63
	 */
franta-hg@106
    64
	private int level = 0;
franta-hg@106
    65
franta-hg@2
    66
	@Override
franta-hg@6
    67
	public void parse(InputSource input) throws IOException, SAXException {
franta-hg@103
    68
		File dir = getFile(input.getSystemId());
franta-hg@77
    69
franta-hg@103
    70
		outputStart(dir);
franta-hg@103
    71
		outputDir(dir);
franta-hg@59
    72
		outputEnd();
franta-hg@59
    73
	}
franta-hg@59
    74
franta-hg@103
    75
	private File getFile(String systemId) throws IOException {
franta-hg@103
    76
		try {
franta-hg@103
    77
			return new File(new URI(systemId));
franta-hg@103
    78
		} catch (URISyntaxException e) {
franta-hg@103
    79
			throw new IOException("Invalid dir URI", e);
franta-hg@103
    80
		}
franta-hg@103
    81
	}
franta-hg@103
    82
franta-hg@106
    83
	private String getAbsolutePath(File file) throws IOException {
franta-hg@106
    84
		return file.getCanonicalFile().getAbsolutePath();
franta-hg@106
    85
	}
franta-hg@106
    86
franta-hg@106
    87
	private Attributes singleAttribute(String name, int value) {
franta-hg@106
    88
		AttributesImpl attributes = new AttributesImpl();
franta-hg@106
    89
		addAttribute(attributes, name, value);
franta-hg@106
    90
		return attributes;
franta-hg@106
    91
	}
franta-hg@106
    92
	
franta-hg@103
    93
	private Attributes singleAttribute(String name, String value) {
franta-hg@103
    94
		AttributesImpl attributes = new AttributesImpl();
franta-hg@106
    95
		addAttribute(attributes, name, value);
franta-hg@103
    96
		return attributes;
franta-hg@103
    97
	}
franta-hg@103
    98
franta-hg@106
    99
	private void addAttribute(AttributesImpl attributes, String name, int value) {
franta-hg@106
   100
		attributes.addAttribute(null, name, name, "xs:int", String.valueOf(value));
franta-hg@106
   101
	}
franta-hg@106
   102
franta-hg@106
   103
	private void addAttribute(AttributesImpl attributes, String name, long value) {
franta-hg@106
   104
		attributes.addAttribute(null, name, name, "xs:long", String.valueOf(value));
franta-hg@106
   105
	}
franta-hg@106
   106
franta-hg@106
   107
	private void addAttribute(AttributesImpl attributes, String name, String value) {
franta-hg@106
   108
		attributes.addAttribute(null, name, name, "xs:string", value);
franta-hg@106
   109
	}
franta-hg@106
   110
franta-hg@106
   111
	private void outputStart(File root) throws SAXException, IOException {
franta-hg@21
   112
		contentHandler.startDocument();
franta-hg@76
   113
		contentHandler.lineBreak();
franta-hg@106
   114
		contentHandler.startElement(null, null, ROOT_ELEMENT, singleAttribute(ABSOLUTE_PATH_ATTRIBUTE, getAbsolutePath(root)));
franta-hg@75
   115
		contentHandler.lineBreak();
franta-hg@59
   116
	}
franta-hg@59
   117
franta-hg@59
   118
	private void outputEnd() throws SAXException {
franta-hg@102
   119
		contentHandler.endElement(null, null, ROOT_ELEMENT);
franta-hg@75
   120
		contentHandler.lineBreak();
franta-hg@21
   121
		contentHandler.endDocument();
franta-hg@6
   122
	}
franta-hg@76
   123
franta-hg@106
   124
	private void outputFile(File file) throws SAXException, IOException {
franta-hg@106
   125
		level++;
franta-hg@106
   126
franta-hg@106
   127
		AttributesImpl attributes = new AttributesImpl();
franta-hg@106
   128
		addAttribute(attributes, NAME_ATTRIBUTE, file.getName());
franta-hg@106
   129
		addAttribute(attributes, ABSOLUTE_PATH_ATTRIBUTE, getAbsolutePath(file));
franta-hg@106
   130
		addAttribute(attributes, SIZE_ATTRIBUTE, file.length());
franta-hg@106
   131
franta-hg@106
   132
		contentHandler.indentation(level);
franta-hg@106
   133
		contentHandler.startElement(null, null, FILE_ELEMENT, attributes);
franta-hg@103
   134
		contentHandler.lineBreak();
franta-hg@77
   135
franta-hg@106
   136
		outputPermissions(file.toPath());
franta-hg@106
   137
		outputExtendedAttributes(file);
franta-hg@77
   138
franta-hg@106
   139
		contentHandler.indentation(level);
franta-hg@103
   140
		contentHandler.endElement(null, null, FILE_ELEMENT);
franta-hg@103
   141
		contentHandler.lineBreak();
franta-hg@106
   142
franta-hg@106
   143
		level--;
franta-hg@77
   144
	}
franta-hg@77
   145
franta-hg@106
   146
	private void outputDir(File dir) throws SAXException, IOException {
franta-hg@106
   147
		level++;
franta-hg@89
   148
franta-hg@106
   149
		final File[] children = dir.listFiles();
franta-hg@106
   150
franta-hg@106
   151
		AttributesImpl attributes = new AttributesImpl();
franta-hg@106
   152
		addAttribute(attributes, NAME_ATTRIBUTE, dir.getName());
franta-hg@106
   153
		addAttribute(attributes, ABSOLUTE_PATH_ATTRIBUTE, getAbsolutePath(dir));
franta-hg@106
   154
		addAttribute(attributes, SIZE_ATTRIBUTE, children.length);
franta-hg@106
   155
franta-hg@106
   156
		contentHandler.indentation(level);
franta-hg@106
   157
		contentHandler.startElement(null, null, DIR_ELEMENT, attributes);
franta-hg@103
   158
		contentHandler.lineBreak();
franta-hg@77
   159
franta-hg@106
   160
		outputPermissions(dir.toPath());
franta-hg@106
   161
		outputExtendedAttributes(dir);
franta-hg@106
   162
franta-hg@106
   163
		for (File file : children) {
franta-hg@103
   164
			if (file.isDirectory()) {
franta-hg@103
   165
				outputDir(file);
franta-hg@103
   166
			} else {
franta-hg@103
   167
				outputFile(file);
franta-hg@81
   168
			}
franta-hg@77
   169
		}
franta-hg@77
   170
franta-hg@106
   171
		contentHandler.indentation(level);
franta-hg@103
   172
		contentHandler.endElement(null, null, DIR_ELEMENT);
franta-hg@103
   173
		contentHandler.lineBreak();
franta-hg@106
   174
franta-hg@106
   175
		level--;
franta-hg@106
   176
	}
franta-hg@106
   177
franta-hg@106
   178
	private String encodeElementName(String originalName) {
franta-hg@106
   179
		/**
franta-hg@106
   180
		 * TODO: encode and/or skip invalid characters
franta-hg@106
   181
		 */
franta-hg@106
   182
		return originalName;
franta-hg@106
   183
	}
franta-hg@106
   184
franta-hg@106
   185
	private void outputPermissions(Path path) throws IOException, SAXException {
franta-hg@106
   186
		level++;
franta-hg@106
   187
		Set<PosixFilePermission> permissions = Files.getPosixFilePermissions(path, LinkOption.NOFOLLOW_LINKS);
franta-hg@106
   188
franta-hg@106
   189
		contentHandler.indentation(level);
franta-hg@106
   190
		contentHandler.startElement(null, PERMISSIONS_ELEMENT, PERMISSIONS_ELEMENT, singleAttribute("octal", getOctal(permissions)));
franta-hg@106
   191
		contentHandler.lineBreak();
franta-hg@106
   192
franta-hg@106
   193
		level++;
franta-hg@106
   194
franta-hg@106
   195
		outputPermission("owner", permissions.contains(PosixFilePermission.OWNER_READ), permissions.contains(PosixFilePermission.OWNER_WRITE), permissions.contains(PosixFilePermission.OWNER_EXECUTE));
franta-hg@106
   196
		outputPermission("group", permissions.contains(PosixFilePermission.GROUP_READ), permissions.contains(PosixFilePermission.GROUP_WRITE), permissions.contains(PosixFilePermission.GROUP_EXECUTE));
franta-hg@106
   197
		outputPermission("others", permissions.contains(PosixFilePermission.OTHERS_READ), permissions.contains(PosixFilePermission.OTHERS_WRITE), permissions.contains(PosixFilePermission.OTHERS_EXECUTE));
franta-hg@106
   198
franta-hg@106
   199
		level--;
franta-hg@106
   200
franta-hg@106
   201
		contentHandler.indentation(level);
franta-hg@106
   202
		contentHandler.endElement(null, PERMISSIONS_ELEMENT, PERMISSIONS_ELEMENT);
franta-hg@106
   203
		contentHandler.lineBreak();
franta-hg@106
   204
franta-hg@106
   205
		level--;
franta-hg@106
   206
	}
franta-hg@106
   207
franta-hg@106
   208
	private int getOctal(Set<PosixFilePermission> permissions) {
franta-hg@106
   209
		int octal = 0;
franta-hg@106
   210
		
franta-hg@106
   211
		octal = octal + 100 * (permissions.contains(PosixFilePermission.OWNER_READ) ? 4 : 0);
franta-hg@106
   212
		octal = octal + 100 * (permissions.contains(PosixFilePermission.OWNER_WRITE) ? 2 : 0);
franta-hg@106
   213
		octal = octal + 100 * (permissions.contains(PosixFilePermission.OWNER_EXECUTE) ? 1 : 0);
franta-hg@106
   214
		
franta-hg@106
   215
		octal = octal + 10 * (permissions.contains(PosixFilePermission.GROUP_READ) ? 4 : 0);
franta-hg@106
   216
		octal = octal + 10 * (permissions.contains(PosixFilePermission.GROUP_WRITE) ? 2 : 0);
franta-hg@106
   217
		octal = octal + 10 * (permissions.contains(PosixFilePermission.GROUP_EXECUTE) ? 1 : 0);
franta-hg@106
   218
		
franta-hg@106
   219
		octal = octal + 1 * (permissions.contains(PosixFilePermission.OTHERS_READ) ? 4 : 0);
franta-hg@106
   220
		octal = octal + 1 * (permissions.contains(PosixFilePermission.OTHERS_WRITE) ? 2 : 0);
franta-hg@106
   221
		octal = octal + 1 * (permissions.contains(PosixFilePermission.OTHERS_EXECUTE) ? 1 : 0);
franta-hg@106
   222
franta-hg@106
   223
		return octal;
franta-hg@106
   224
	}
franta-hg@106
   225
franta-hg@106
   226
	private void outputPermission(String name, boolean read, boolean write, boolean execute) throws SAXException {
franta-hg@106
   227
		contentHandler.indentation(level);
franta-hg@106
   228
		AttributesImpl attributes = new AttributesImpl();
franta-hg@106
   229
		attributes.addAttribute(null, "read", "read", "xs:boolean", String.valueOf(read));
franta-hg@106
   230
		attributes.addAttribute(null, "write", "write", "xs:boolean", String.valueOf(write));
franta-hg@106
   231
		attributes.addAttribute(null, "execute", "execute", "xs:boolean", String.valueOf(execute));
franta-hg@106
   232
		contentHandler.startElement(null, name, name, attributes);
franta-hg@106
   233
		contentHandler.endElement(null, name, name);
franta-hg@106
   234
		contentHandler.lineBreak();
franta-hg@106
   235
	}
franta-hg@106
   236
franta-hg@106
   237
	private void outputExtendedAttributes(File file) throws IOException, SAXException {
franta-hg@106
   238
		level++;
franta-hg@106
   239
franta-hg@106
   240
		final List<ExtendedAttribute> extendedAttributes = getExtendedAttributes(file);
franta-hg@106
   241
franta-hg@106
   242
		if (!extendedAttributes.isEmpty()) {
franta-hg@106
   243
			contentHandler.indentation(level);
franta-hg@106
   244
			contentHandler.startElement(null, XATTR_ELEMENT, XATTR_ELEMENT, null);
franta-hg@106
   245
			contentHandler.lineBreak();
franta-hg@106
   246
			level++;
franta-hg@106
   247
			for (ExtendedAttribute ea : extendedAttributes) {
franta-hg@106
   248
				contentHandler.indentation(level);
franta-hg@106
   249
				String elementName = encodeElementName(ea.getKey());
franta-hg@106
   250
				contentHandler.textElement(ea.getValue(), null, elementName, elementName, null);
franta-hg@106
   251
				contentHandler.lineBreak();
franta-hg@106
   252
			}
franta-hg@106
   253
			level--;
franta-hg@106
   254
			contentHandler.indentation(level);
franta-hg@106
   255
			contentHandler.endElement(null, XATTR_ELEMENT, XATTR_ELEMENT);
franta-hg@106
   256
			contentHandler.lineBreak();
franta-hg@106
   257
		}
franta-hg@106
   258
franta-hg@106
   259
		level--;
franta-hg@106
   260
	}
franta-hg@106
   261
franta-hg@106
   262
	private List<ExtendedAttribute> getExtendedAttributes(File file) throws IOException {
franta-hg@106
   263
franta-hg@106
   264
		List<ExtendedAttribute> l = new ArrayList<>();
franta-hg@106
   265
franta-hg@106
   266
		Path path = file.toPath();
franta-hg@106
   267
		FileSystemProvider provider = path.getFileSystem().provider();
franta-hg@106
   268
		UserDefinedFileAttributeView attributes = provider.getFileAttributeView(path, UserDefinedFileAttributeView.class);
franta-hg@106
   269
franta-hg@106
   270
		for (String jménoAtributu : attributes.list()) {
franta-hg@106
   271
			ByteBuffer hodnotaAtributu = ByteBuffer.allocate(attributes.size(jménoAtributu));
franta-hg@106
   272
			attributes.read(jménoAtributu, hodnotaAtributu);
franta-hg@106
   273
			l.add(new ExtendedAttribute(jménoAtributu, hodnotaAtributu));
franta-hg@106
   274
		}
franta-hg@106
   275
franta-hg@106
   276
		return l;
franta-hg@106
   277
franta-hg@77
   278
	}
franta-hg@2
   279
}