001/* 002 * Copyright 2007-2018 The jdeb developers. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.vafer.jdeb.mapping; 017 018import java.io.BufferedReader; 019import java.io.IOException; 020import java.io.InputStream; 021import java.io.InputStreamReader; 022import java.util.HashMap; 023import java.util.Map; 024import java.util.regex.Matcher; 025import java.util.regex.Pattern; 026 027import org.apache.commons.compress.archivers.tar.TarArchiveEntry; 028 029/** 030 * Reads permissions and ownerships from a "ls -laR > mapping.txt" dump and 031 * maps entries accordingly. 032 */ 033public final class LsMapper implements Mapper { 034 035 private final Map<String, TarArchiveEntry> mapping; 036 037 038 public final static class ParseError extends Exception { 039 040 private static final long serialVersionUID = 1L; 041 042 public ParseError( String message ) { 043 super(message); 044 } 045 } 046 047 048 public LsMapper( final InputStream pInput ) throws IOException, ParseError { 049 mapping = parse(pInput); 050 } 051 052 /* 053./trunk/target/test-classes/org/vafer/dependency: 054total 176 055drwxr-xr-x 23 tcurdt tcurdt 782 Jun 25 03:48 . 056drwxr-xr-x 3 tcurdt tcurdt 102 Jun 25 03:48 .. 057-rw-r--r-- 1 tcurdt tcurdt 2934 Jun 25 03:48 DependenciesTestCase.class 058-rw-r--r-- 1 tcurdt tcurdt 786 Jun 25 03:48 JarCombiningTestCase$1.class 059-rw-r--r-- 1 tcurdt tcurdt 2176 Jun 25 03:48 WarTestCase.class 060drwxr-xr-x 4 tcurdt tcurdt 136 Jun 25 03:48 classes 061 062./trunk/target/test-classes/org/vafer/dependency/classes: 063 */ 064 065 final private Pattern basePattern = Pattern.compile("^\\./(.*):$"); 066 final private Pattern totalPattern = Pattern.compile("^total ([0-9]+)$"); 067 final private Pattern dirPattern = Pattern.compile("^d([rwx-]{9})\\s+([0-9]+)\\s+(\\S*)\\s+(\\S*)\\s+([0-9]+)\\s+(.*)\\s+[\\.]{1,2}$"); 068 final private Pattern filePattern = Pattern.compile("^([d-])([rwx-]{9})\\s+([0-9]+)\\s+(\\S*)\\s+(\\S*)\\s+([0-9]+)\\s+(.*)\\s+(.*)$"); 069 final private Pattern newlinePattern = Pattern.compile("$"); 070 071 private String readBase( final BufferedReader reader ) throws IOException, ParseError { 072 final String line = reader.readLine(); 073 if (line == null) { 074 return null; 075 } 076 final Matcher matcher = basePattern.matcher(line); 077 if (!matcher.matches()) { 078 throw new ParseError("expected base line but got \"" + line + "\""); 079 } 080 return matcher.group(1); 081 } 082 083 private String readTotal( final BufferedReader reader ) throws IOException, ParseError { 084 final String line = reader.readLine(); 085 final Matcher matcher = totalPattern.matcher(line); 086 if (!matcher.matches()) { 087 throw new ParseError("expected total line but got \"" + line + "\""); 088 } 089 return matcher.group(1); 090 } 091 092 private TarArchiveEntry readDir( final BufferedReader reader, final String base ) throws IOException, ParseError { 093 final String current = reader.readLine(); 094 final Matcher currentMatcher = dirPattern.matcher(current); 095 if (!currentMatcher.matches()) { 096 throw new ParseError("expected dirline but got \"" + current + "\""); 097 } 098 099 final String parent = reader.readLine(); 100 final Matcher parentMatcher = dirPattern.matcher(parent); 101 if (!parentMatcher.matches()) { 102 throw new ParseError("expected dirline but got \"" + parent + "\""); 103 } 104 105 final TarArchiveEntry entry = new TarArchiveEntry(base, true); 106 107 entry.setMode(convertModeFromString(currentMatcher.group(1))); 108 entry.setUserName(currentMatcher.group(3)); 109 entry.setGroupName(currentMatcher.group(4)); 110 111 return entry; 112 } 113 114 115 private int convertModeFromString( final String mode ) { 116 117 final char[] m = mode.toCharArray(); 118 /* 119 -rwxrwxrwx 120 121 4000 set-user-ID-on-execution bit 122 2000 set-user-ID-on-execution bit 123 1000 sticky bit 124 0400 allow read by owner. 125 0200 allow write by owner. 126 0100 execute / search 127 0040 allow read by group members. 128 0020 allow write by group members. 129 0010 execute / search 130 0004 allow read by others. 131 0002 allow write by others. 132 0001 execute / search 133 */ 134 // TODO: simplified - needs fixing 135 int sum = 0; 136 int bit = 1; 137 for (int i = m.length - 1; i >= 0; i--) { 138 if (m[i] != '-') { 139 sum += bit; 140 } 141 bit += bit; 142 } 143 return sum; 144 } 145 146 private TarArchiveEntry readFile( final BufferedReader reader, final String base ) throws IOException, ParseError { 147 148 while (true) { 149 final String line = reader.readLine(); 150 151 if (line == null) { 152 return null; 153 } 154 155 final Matcher currentMatcher = filePattern.matcher(line); 156 if (!currentMatcher.matches()) { 157 final Matcher newlineMatcher = newlinePattern.matcher(line); 158 if (newlineMatcher.matches()) { 159 return null; 160 } 161 throw new ParseError("expected file line but got \"" + line + "\""); 162 } 163 164 final String type = currentMatcher.group(1); 165 if (type.startsWith("-")) { 166 final TarArchiveEntry entry = new TarArchiveEntry(base + "/" + currentMatcher.group(8), true); 167 168 entry.setMode(convertModeFromString(currentMatcher.group(2))); 169 entry.setUserName(currentMatcher.group(4)); 170 entry.setGroupName(currentMatcher.group(5)); 171 172 return entry; 173 } 174 } 175 176 } 177 178 private Map<String, TarArchiveEntry> parse( final InputStream pInput ) throws IOException, ParseError { 179 final Map<String, TarArchiveEntry> mapping = new HashMap<String, TarArchiveEntry>(); 180 181 final BufferedReader reader = new BufferedReader(new InputStreamReader(pInput)); 182 183 boolean first = true; 184 while (true) { 185 186 final String base; 187 if (first) { 188 base = ""; 189 first = false; 190 } else { 191 base = readBase(reader); 192 if (base == null) { 193 break; 194 } 195 } 196 197 readTotal(reader); 198 final TarArchiveEntry dir = readDir(reader, base); 199 mapping.put(dir.getName(), dir); 200 201 while (true) { 202 final TarArchiveEntry file = readFile(reader, base); 203 204 if (file == null) { 205 break; 206 } 207 208 mapping.put(file.getName(), file); 209 } 210 } 211 212 return mapping; 213 } 214 215 public TarArchiveEntry map( final TarArchiveEntry pEntry ) { 216 final TarArchiveEntry entry = mapping.get(pEntry.getName()); 217 if (entry != null) { 218 return entry; 219 } 220 return pEntry; 221 } 222 223}