001 /*
002 * Copyright 2005 The Apache Software Foundation.
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 */
016 package org.vafer.jdeb.mapping;
017
018 import java.io.BufferedReader;
019 import java.io.IOException;
020 import java.io.InputStream;
021 import java.io.InputStreamReader;
022 import java.util.HashMap;
023 import java.util.Map;
024 import java.util.regex.Matcher;
025 import java.util.regex.Pattern;
026
027 import org.apache.tools.tar.TarEntry;
028
029 /**
030 * Reads permissions and ownerships from a "ls -laR > mapping.txt" dump and
031 * maps entries accordingly.
032 *
033 * @author Torsten Curdt <tcurdt@vafer.org>
034 */
035 public final class LsMapper implements Mapper {
036
037 private final Map mapping;
038
039
040 public final static class ParseError extends Exception {
041
042 private static final long serialVersionUID = 1L;
043
044 public ParseError() {
045 super();
046 }
047
048 public ParseError(String message, Throwable cause) {
049 super(message, cause);
050 }
051
052 public ParseError(String message) {
053 super(message);
054 }
055
056 public ParseError(Throwable cause) {
057 super(cause);
058 }
059
060 };
061
062 public LsMapper( final InputStream pInput ) throws IOException, ParseError {
063 mapping = parse(pInput);
064 }
065
066 /*
067 ./trunk/target/test-classes/org/vafer/dependency:
068 total 176
069 drwxr-xr-x 23 tcurdt tcurdt 782 Jun 25 03:48 .
070 drwxr-xr-x 3 tcurdt tcurdt 102 Jun 25 03:48 ..
071 -rw-r--r-- 1 tcurdt tcurdt 2934 Jun 25 03:48 DependenciesTestCase.class
072 -rw-r--r-- 1 tcurdt tcurdt 786 Jun 25 03:48 JarCombiningTestCase$1.class
073 -rw-r--r-- 1 tcurdt tcurdt 2176 Jun 25 03:48 WarTestCase.class
074 drwxr-xr-x 4 tcurdt tcurdt 136 Jun 25 03:48 classes
075
076 ./trunk/target/test-classes/org/vafer/dependency/classes:
077 */
078
079 final private Pattern basePattern = Pattern.compile("^\\./(.*):$");
080 final private Pattern totalPattern = Pattern.compile("^total ([0-9]+)$");
081 final private Pattern dirPattern = Pattern.compile("^d([rwx-]{9})\\s+([0-9]+)\\s+(\\S*)\\s+(\\S*)\\s+([0-9]+)\\s+(.*)\\s+[\\.]{1,2}$");
082 final private Pattern filePattern = Pattern.compile("^([d-])([rwx-]{9})\\s+([0-9]+)\\s+(\\S*)\\s+(\\S*)\\s+([0-9]+)\\s+(.*)\\s+(.*)$");
083 final private Pattern newlinePattern = Pattern.compile("$");
084
085 private String readBase( final BufferedReader reader ) throws IOException, ParseError {
086 final String line = reader.readLine();
087 if (line == null) {
088 return null;
089 }
090 final Matcher matcher = basePattern.matcher(line);
091 if (!matcher.matches()) {
092 throw new ParseError("expected base line but got \"" + line + "\"");
093 }
094 return matcher.group(1);
095 }
096
097 private String readTotal( final BufferedReader reader ) throws IOException, ParseError {
098 final String line = reader.readLine();
099 final Matcher matcher = totalPattern.matcher(line);
100 if (!matcher.matches()) {
101 throw new ParseError("expected total line but got \"" + line + "\"");
102 }
103 return matcher.group(1);
104 }
105
106 private TarEntry readDir( final BufferedReader reader, final String base ) throws IOException, ParseError {
107 final String current = reader.readLine();
108 final Matcher currentMatcher = dirPattern.matcher(current);
109 if (!currentMatcher.matches()) {
110 throw new ParseError("expected dirline but got \"" + current + "\"");
111 }
112
113 final String parent = reader.readLine();
114 final Matcher parentMatcher = dirPattern.matcher(parent);
115 if (!parentMatcher.matches()) {
116 throw new ParseError("expected dirline but got \"" + parent + "\"");
117 }
118
119 final TarEntry entry = new TarEntry(base);
120
121 entry.setMode(convertModeFromString(currentMatcher.group(1)));
122 entry.setUserName(currentMatcher.group(3));
123 entry.setGroupName(currentMatcher.group(4));
124
125 return entry;
126 }
127
128
129 private int convertModeFromString( final String mode ) {
130
131 final char[] m = mode.toCharArray();
132 /*
133 -rwxrwxrwx
134
135 4000 set-user-ID-on-execution bit
136 2000 set-user-ID-on-execution bit
137 1000 sticky bit
138 0400 allow read by owner.
139 0200 allow write by owner.
140 0100 execute / search
141 0040 allow read by group members.
142 0020 allow write by group members.
143 0010 execute / search
144 0004 allow read by others.
145 0002 allow write by others.
146 0001 execute / search
147 */
148 // TODO: simplified - needs fixing
149 int sum = 0;
150 int bit = 1;
151 for(int i=m.length-1; i>=0 ; i--) {
152 if (m[i] != '-') {
153 sum += bit;
154 }
155 bit += bit;
156 }
157 return sum;
158 }
159
160 private TarEntry readFile( final BufferedReader reader, final String base ) throws IOException, ParseError {
161
162 while(true) {
163 final String line = reader.readLine();
164
165 if (line == null) {
166 return null;
167 }
168
169 final Matcher currentMatcher = filePattern.matcher(line);
170 if (!currentMatcher.matches()) {
171 final Matcher newlineMatcher = newlinePattern.matcher(line);
172 if (newlineMatcher.matches()) {
173 return null;
174 }
175 throw new ParseError("expected file line but got \"" + line + "\"");
176 }
177
178 final String type = currentMatcher.group(1);
179 if (type.startsWith("-")) {
180 final TarEntry entry = new TarEntry(base + "/" + currentMatcher.group(8));
181
182 entry.setMode(convertModeFromString(currentMatcher.group(2)));
183 entry.setUserName(currentMatcher.group(4));
184 entry.setGroupName(currentMatcher.group(5));
185
186 return entry;
187 }
188 }
189
190 }
191
192 private Map parse( final InputStream pInput ) throws IOException, ParseError {
193 final Map mapping = new HashMap();
194
195 final BufferedReader reader = new BufferedReader(new InputStreamReader(pInput));
196
197 boolean first = true;
198 while(true) {
199
200 final String base;
201 if (first) {
202 base = "";
203 first = false;
204 } else {
205 base = readBase(reader);
206 if (base == null) {
207 break;
208 }
209 }
210
211 readTotal(reader);
212 final TarEntry dir = readDir(reader, base);
213 mapping.put(dir.getName(), dir);
214
215 while(true) {
216 final TarEntry file = readFile(reader, base);
217
218 if (file == null) {
219 break;
220 }
221
222 mapping.put(file.getName(), file);
223 }
224 }
225
226 return mapping;
227 }
228
229 public TarEntry map( final TarEntry pEntry ) {
230
231 final TarEntry entry = (TarEntry) mapping.get(pEntry.getName());
232
233 if (entry != null) {
234
235 final TarEntry newEntry = new TarEntry(entry.getName());
236 newEntry.setUserId(entry.getUserId());
237 newEntry.setGroupId(entry.getGroupId());
238 newEntry.setUserName(entry.getUserName());
239 newEntry.setGroupName(entry.getGroupName());
240 newEntry.setMode(entry.getMode());
241 newEntry.setSize(entry.getSize());
242
243 return newEntry;
244 }
245
246 return pEntry;
247 }
248
249 }