View Javadoc

1   /*
2    * Copyright 2005 The Apache Software Foundation.
3    * 
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    * 
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    * 
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.vafer.jdeb.mapping;
17  
18  import java.io.BufferedReader;
19  import java.io.IOException;
20  import java.io.InputStream;
21  import java.io.InputStreamReader;
22  import java.util.HashMap;
23  import java.util.Map;
24  import java.util.regex.Matcher;
25  import java.util.regex.Pattern;
26  
27  import org.apache.tools.tar.TarEntry;
28  
29  /**
30   * Reads permissions and ownerships from a "ls -laR > mapping.txt" dump and
31   * maps entries accordingly.
32   * 
33   * @author Torsten Curdt <tcurdt@vafer.org>
34   */
35  public final class LsMapper implements Mapper {
36  
37  	private final Map mapping;
38  
39  	
40  	public final static class ParseError extends Exception {
41  
42  		private static final long serialVersionUID = 1L;
43  
44  		public ParseError() {
45  			super();
46  		}
47  
48  		public ParseError(String message, Throwable cause) {
49  			super(message, cause);
50  		}
51  
52  		public ParseError(String message) {
53  			super(message);
54  		}
55  
56  		public ParseError(Throwable cause) {
57  			super(cause);
58  		}
59  		
60  	};
61  	
62  	public LsMapper( final InputStream pInput ) throws IOException, ParseError {
63  		mapping = parse(pInput);
64  	}
65  	
66  	/*
67  ./trunk/target/test-classes/org/vafer/dependency:
68  total 176
69  drwxr-xr-x   23 tcurdt  tcurdt   782 Jun 25 03:48 .
70  drwxr-xr-x    3 tcurdt  tcurdt   102 Jun 25 03:48 ..
71  -rw-r--r--    1 tcurdt  tcurdt  2934 Jun 25 03:48 DependenciesTestCase.class
72  -rw-r--r--    1 tcurdt  tcurdt   786 Jun 25 03:48 JarCombiningTestCase$1.class
73  -rw-r--r--    1 tcurdt  tcurdt  2176 Jun 25 03:48 WarTestCase.class
74  drwxr-xr-x    4 tcurdt  tcurdt   136 Jun 25 03:48 classes
75  
76  ./trunk/target/test-classes/org/vafer/dependency/classes:
77  	 */
78  	
79  	final private Pattern basePattern = Pattern.compile("^\\./(.*):$");
80  	final private Pattern totalPattern = Pattern.compile("^total ([0-9]+)$");
81  	final private Pattern dirPattern = Pattern.compile("^d([rwx-]{9})\\s+([0-9]+)\\s+(\\S*)\\s+(\\S*)\\s+([0-9]+)\\s+(.*)\\s+[\\.]{1,2}$");
82  	final private Pattern filePattern = Pattern.compile("^([d-])([rwx-]{9})\\s+([0-9]+)\\s+(\\S*)\\s+(\\S*)\\s+([0-9]+)\\s+(.*)\\s+(.*)$");
83  	final private Pattern newlinePattern = Pattern.compile("$");
84  
85  	private String readBase( final BufferedReader reader ) throws IOException, ParseError {
86  		final String line = reader.readLine();
87  		if (line == null) {
88  			return null;
89  		}
90  		final Matcher matcher = basePattern.matcher(line);
91  		if (!matcher.matches()) {
92  			throw new ParseError("expected base line but got \"" + line + "\"");
93  		}
94  		return matcher.group(1);
95  	}
96  
97  	private String readTotal( final BufferedReader reader ) throws IOException, ParseError {
98  		final String line = reader.readLine();
99  		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 }