View Javadoc
1 package org.apache.commons.net.ftp; 2 3 /* ==================================================================== 4 * The Apache Software License, Version 1.1 5 * 6 * Copyright (c) 2001 The Apache Software Foundation. All rights 7 * reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in 18 * the documentation and/or other materials provided with the 19 * distribution. 20 * 21 * 3. The end-user documentation included with the redistribution, 22 * if any, must include the following acknowledgment: 23 * "This product includes software developed by the 24 * Apache Software Foundation (http://www.apache.org/)." 25 * Alternately, this acknowledgment may appear in the software itself, 26 * if and wherever such third-party acknowledgments normally appear. 27 * 28 * 4. The names "Apache" and "Apache Software Foundation" and 29 * "Apache Commons" must not be used to endorse or promote products 30 * derived from this software without prior written permission. For 31 * written permission, please contact apache@apache.org. 32 * 33 * 5. Products derived from this software may not be called "Apache", 34 * nor may "Apache" appear in their name, without 35 * prior written permission of the Apache Software Foundation. 36 * 37 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED 38 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 39 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 40 * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR 41 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 42 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 43 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 44 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 45 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 46 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 47 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 48 * SUCH DAMAGE. 49 * ==================================================================== 50 * 51 * This software consists of voluntary contributions made by many 52 * individuals on behalf of the Apache Software Foundation. For more 53 * information on the Apache Software Foundation, please see 54 * <http://www.apache.org/>;. 55 */ 56 57 import java.io.BufferedReader; 58 import java.io.IOException; 59 import java.io.InputStream; 60 import java.io.InputStreamReader; 61 import java.util.Calendar; 62 import java.util.StringTokenizer; 63 import java.util.Vector; 64 65 /**** 66 * DefaultFTPFileListParser is the default implementation of 67 * <a href="org.apache.commons.net.ftp.FTPFileListParser.html"> FTPFileListParser </a> 68 * used by <a href="org.apache.commons.net.ftp.FTPClient.html"> FTPClient </a> 69 * to parse file listings. 70 * Sometimes you will want to parse unusual listing formats, in which 71 * case you would create your own implementation of FTPFileListParser and 72 * if necessary, subclass FTPFile. 73 * <p> 74 * <p> 75 * @author Daniel F. Savarese 76 * @see FTPFileListParser 77 * @see FTPFile 78 * @see FTPClient#listFiles 79 ***/ 80 81 public final class DefaultFTPFileListParser implements FTPFileListParser 82 { 83 84 85 // end is one beyond end 86 private int __charArrayToInt(char[] arr, int start, int end) 87 { 88 int value = 0, decimal; 89 decimal = 1; 90 while (end-- > start) 91 { 92 value += (decimal * (arr[end] - '0')); 93 decimal *= 10; 94 } 95 return value; 96 } 97 98 private long __charArrayToLong(char[] arr, int start, int end) 99 { 100 long value = 0, decimal; 101 decimal = 1; 102 while (end-- > start) 103 { 104 value += (decimal * (arr[end] - '0')); 105 decimal *= 10; 106 } 107 return value; 108 } 109 110 private int __skipWhitespace(char[] cToken, int start) 111 { 112 while (start < cToken.length && Character.isWhitespace(cToken[start])) 113 ++start; 114 return start; 115 } 116 117 private int __skipDigits(char[] cToken, int start) 118 { 119 while (start < cToken.length && Character.isDigit(cToken[start])) 120 ++start; 121 return start; 122 } 123 124 private int __skipNonWhitespace(char[] cToken, int start) 125 { 126 while (start < cToken.length && !Character.isWhitespace(cToken[start])) 127 ++start; 128 return start; 129 } 130 131 private int __skipNonWhitespaceToLower(char[] cToken, int start) 132 { 133 while (start < cToken.length && !Character.isWhitespace(cToken[start])) 134 { 135 cToken[start] = Character.toLowerCase(cToken[start]); 136 ++start; 137 } 138 return start; 139 } 140 141 142 /**** 143 * Parses an FTP server listing entry (a single line) and returns an 144 * FTPFile instance with the resulting information. If the entry could 145 * not be parsed, returns null. 146 * <p> 147 * @param entry A single line of an FTP server listing with the 148 * end of line truncated. 149 * @return An FTPFile instance representing the file information. null if 150 * the entry could be parsed, returns null. 151 ***/ 152 public FTPFile parseFTPEntry(String entry) 153 { 154 int access, start, end, type, month, year, hour, minutes; 155 boolean isDevice; 156 Calendar date; 157 StringTokenizer tokenizer; 158 String sToken; 159 char cToken[]; 160 FTPFile file; 161 162 try 163 { 164 cToken = entry.toCharArray(); 165 166 file = new FTPFile(); 167 file.setRawListing(entry); 168 169 isDevice = (cToken[0] == 'b' || cToken[0] == 'c'); 170 171 switch (cToken[0]) 172 { 173 case 'd': 174 type = FTPFile.DIRECTORY_TYPE; 175 break; 176 case 'l': 177 type = FTPFile.SYMBOLIC_LINK_TYPE; 178 break; 179 default: 180 type = FTPFile.FILE_TYPE; 181 break; 182 } 183 184 file.setType(type); 185 186 for (access = 0, start = 1; access < 3; access++) 187 { 188 // We use != '-' so we avoid having to check for suid and sticky bits 189 file.setPermission(access, FTPFile.READ_PERMISSION, 190 (cToken[start++] != '-')); 191 file.setPermission(access, FTPFile.WRITE_PERMISSION, 192 (cToken[start++] != '-')); 193 file.setPermission(access, FTPFile.EXECUTE_PERMISSION, 194 (cToken[start++] != '-')); 195 } 196 197 start = __skipWhitespace(cToken, start); 198 end = __skipDigits(cToken, start); 199 file.setHardLinkCount(__charArrayToInt(cToken, start, end)); 200 201 start = __skipWhitespace(cToken, end); 202 end = __skipNonWhitespace(cToken, start); 203 // Get user and group 204 file.setUser(new String(cToken, start, end - start)); 205 206 start = __skipWhitespace(cToken, end); 207 end = __skipNonWhitespace(cToken, start); 208 file.setGroup(new String(cToken, start, end - start)); 209 210 // Get size, if block or character device, set size to zero and skip 211 // next two tokens. 212 if (isDevice) 213 { 214 start = __skipWhitespace(cToken, end); 215 end = __skipNonWhitespace(cToken, start); 216 start = __skipWhitespace(cToken, end); 217 end = __skipNonWhitespace(cToken, start); 218 // Don't explicitly set size because it is zero by default 219 } 220 else 221 { 222 start = __skipWhitespace(cToken, end); 223 end = __skipDigits(cToken, start); 224 file.setSize(__charArrayToLong(cToken, start, end)); 225 } 226 227 start = __skipWhitespace(cToken, end); 228 end = __skipNonWhitespaceToLower(cToken, start); 229 230 // Get month 231 switch (cToken[start]) 232 { 233 case 'a': 234 if (cToken[end - 1] == 'r') 235 month = 3; 236 else 237 month = 7; 238 break; 239 case 'd': 240 month = 11; 241 break; 242 case 'f': 243 month = 1; 244 break; 245 case 'j': 246 if (cToken[end - 1] == 'l') 247 month = 6; 248 else if (cToken[start + 1] == 'a') 249 month = 0; 250 else 251 month = 5; 252 break; 253 case 'm': 254 if (cToken[end - 1] == 'y') 255 month = 4; 256 else 257 month = 2; 258 break; 259 case 'n': 260 month = 10; 261 break; 262 case 'o': 263 month = 9; 264 break; 265 case 's': 266 month = 8; 267 break; 268 default: 269 month = 0; 270 break; 271 } 272 273 // Get day, and store in access 274 start = __skipWhitespace(cToken, end); 275 end = __skipDigits(cToken, start); 276 access = __charArrayToInt(cToken, start, end); 277 278 start = __skipWhitespace(cToken, end); 279 end = __skipDigits(cToken, start); 280 281 date = Calendar.getInstance(); 282 283 try 284 { 285 // If token contains a :, it must be a time, otherwise a year 286 if (cToken[end] == ':') 287 { 288 year = date.get(Calendar.YEAR); 289 hour = date.get(Calendar.MONTH); 290 if (hour < month) 291 --year; 292 hour = __charArrayToInt(cToken, start, end); 293 start = end + 1; 294 end = __skipDigits(cToken, start); 295 minutes = __charArrayToInt(cToken, start, end); 296 } 297 else 298 { 299 // Have to set minutes or compiler will complain not initialized 300 hour = minutes = -1; 301 year = __charArrayToInt(cToken, start, end); 302 } 303 304 date.clear(); 305 date.set(Calendar.YEAR, year); 306 date.set(Calendar.MONTH, month); 307 date.set(Calendar.DATE, access); 308 309 if (hour != -1) 310 { 311 date.set(Calendar.HOUR, hour); 312 date.set(Calendar.MINUTE, minutes); 313 } 314 315 } 316 catch (IllegalArgumentException e) 317 { 318 // Do nothing 319 } 320 321 file.setTimestamp(date); 322 323 // This is dangerous, but we're going to assume there is only one 324 // space after the date. Most servers seem to use that format and 325 // we need to be able to preserve leading spacesin filenames. 326 //start = __skipWhitespace(cToken, end); 327 start = end + 1; 328 end = __skipNonWhitespace(cToken, start); 329 330 if (end >= cToken.length) 331 { 332 file.setName(new String(cToken, start, end - start)); 333 return file; 334 } 335 336 // Now we have to deal with the possibilities of symbolic links and 337 // filenames with spaces. The filename and/or link may contain 338 // spaces, numbers, or appear like the date entry, group, etc., 339 340 sToken = new String(cToken, start, cToken.length - start); 341 342 if (type == FTPFile.SYMBOLIC_LINK_TYPE) 343 { 344 end = sToken.indexOf(" -> "); 345 // Give up if no link indicator is present 346 if (end == -1) 347 { 348 file.setName(sToken); 349 return file; 350 } 351 352 file.setName(sToken.substring(0, end)); 353 file.setLink(sToken.substring(end + 4)); 354 return file; 355 } 356 357 // For other cases, just take the entire token 358 359 file.setName(sToken); 360 } 361 catch (ArrayIndexOutOfBoundsException e) 362 { 363 return null; 364 } 365 catch (StringIndexOutOfBoundsException e) 366 { 367 return null; 368 } 369 370 return file; 371 } 372 373 374 /**** 375 * Parses an FTP server file listing and converts it into a usable format 376 * in the form of an array of <code> FTPFile </code> instances. If the 377 * file list contains no files, <code> null </code> is returned, otherwise 378 * an array of <code> FTPFile </code> instances representing the files in 379 * the directory is returned. 380 * <p> 381 * @param listStream The InputStream from which the file list should be 382 * read. 383 * @return The list of file information contained in the given path. null 384 * if the list could not be obtained or if there are no files in 385 * the directory. 386 * @exception IOException If an I/O error occurs reading the listStream. 387 ***/ 388 public FTPFile[] parseFileList(InputStream listStream) throws IOException 389 { 390 String line; 391 Vector results; 392 BufferedReader reader; 393 FTPFile entry; 394 395 reader = new BufferedReader(new InputStreamReader(listStream)); 396 397 if ((line = reader.readLine()) == null) 398 { 399 results = null; 400 } 401 else 402 { 403 results = new Vector(); 404 405 // This is to handle a line at the beginning of the listing 406 // that says "total xx" or "Gemstat xx" or something else. 407 if (line.toLowerCase().startsWith("total")) 408 line = reader.readLine(); 409 else 410 { 411 if ((entry = parseFTPEntry(line)) != null) 412 results.addElement(entry); 413 line = reader.readLine(); 414 } 415 416 while (line != null) 417 { 418 if (line.length() == 0 || (entry = parseFTPEntry(line)) == null) 419 { 420 results = null; 421 break; 422 } 423 results.addElement(entry); 424 line = reader.readLine(); 425 } 426 } 427 428 // Finish reading from stream just in case 429 if (line != null) 430 while ((line = reader.readLine()) != null) 431 ; 432 433 reader.close(); 434 435 if (results != null) 436 { 437 FTPFile[] result; 438 439 result = new FTPFile[results.size()]; 440 if (result.length > 0) 441 results.copyInto(result); 442 return result; 443 } 444 445 return null; 446 } 447 448 }

This page was automatically generated by Maven