001 /* 002 * Copyright 2001-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.apache.commons.net.ftp.parser; 017 import java.text.ParseException; 018 019 import org.apache.commons.net.ftp.FTPClientConfig; 020 import org.apache.commons.net.ftp.FTPFile; 021 022 /** 023 * Implementation FTPFileEntryParser and FTPFileListParser for standard 024 * Unix Systems. 025 * 026 * This class is based on the logic of Daniel Savarese's 027 * DefaultFTPListParser, but adapted to use regular expressions and to fit the 028 * new FTPFileEntryParser interface. 029 * @version $Id: UnixFTPEntryParser.java 161712 2005-04-18 02:57:04Z scohen $ 030 * @see org.apache.commons.net.ftp.FTPFileEntryParser FTPFileEntryParser (for usage instructions) 031 */ 032 public class UnixFTPEntryParser extends ConfigurableFTPFileEntryParserImpl 033 { 034 /** 035 * months abbreviations looked for by this parser. Also used 036 * to determine which month is matched by the parser 037 */ 038 private static final String DEFAULT_MONTHS = 039 "(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"; 040 041 static final String DEFAULT_DATE_FORMAT 042 = "MMM d yyyy"; //Nov 9 2001 043 044 static final String DEFAULT_RECENT_DATE_FORMAT 045 = "MMM d HH:mm"; //Nov 9 20:06 046 047 static final String NUMERIC_DATE_FORMAT 048 = "yyyy-MM-dd HH:mm"; //2001-11-09 20:06 049 050 /** 051 * Some Linux distributions are now shipping an FTP server which formats 052 * file listing dates in an all-numeric format: 053 * <code>"yyyy-MM-dd HH:mm</code>. 054 * This is a very welcome development, and hopefully it will soon become 055 * the standard. However, since it is so new, for now, and possibly 056 * forever, we merely accomodate it, but do not make it the default. 057 * <p> 058 * For now end users may specify this format only via 059 * <code>UnixFTPEntryParser(FTPClientConfig)</code>. 060 * Steve Cohen - 2005-04-17 061 */ 062 public static final FTPClientConfig NUMERIC_DATE_CONFIG = 063 new FTPClientConfig( 064 FTPClientConfig.SYST_UNIX, 065 NUMERIC_DATE_FORMAT, 066 null, null, null, null); 067 068 /** 069 * this is the regular expression used by this parser. 070 * 071 * Permissions: 072 * r the file is readable 073 * w the file is writable 074 * x the file is executable 075 * - the indicated permission is not granted 076 * L mandatory locking occurs during access (the set-group-ID bit is 077 * on and the group execution bit is off) 078 * s the set-user-ID or set-group-ID bit is on, and the corresponding 079 * user or group execution bit is also on 080 * S undefined bit-state (the set-user-ID bit is on and the user 081 * execution bit is off) 082 * t the 1000 (octal) bit, or sticky bit, is on [see chmod(1)], and 083 * execution is on 084 * T the 1000 bit is turned on, and execution is off (undefined bit- 085 * state) 086 */ 087 private static final String REGEX = 088 "([bcdlfmpSs-])" 089 +"(((r|-)(w|-)([xsStTL-]))((r|-)(w|-)([xsStTL-]))((r|-)(w|-)([xsStTL-])))\\+?\\s+" 090 + "(\\d+)\\s+" 091 + "(\\S+)\\s+" 092 + "(?:(\\S+)\\s+)?" 093 + "(\\d+)\\s+" 094 095 /* 096 numeric or standard format date 097 */ 098 + "((?:\\d+[-/]\\d+[-/]\\d+)|(?:\\S+\\s+\\S+))\\s+" 099 100 /* 101 year (for non-recent standard format) 102 or time (for numeric or recent standard format 103 */ 104 + "(\\d+(?::\\d+)?)\\s+" 105 106 + "(\\S*)(\\s*.*)"; 107 108 109 /** 110 * The default constructor for a UnixFTPEntryParser object. 111 * 112 * @exception IllegalArgumentException 113 * Thrown if the regular expression is unparseable. Should not be seen 114 * under normal conditions. It it is seen, this is a sign that 115 * <code>REGEX</code> is not a valid regular expression. 116 */ 117 public UnixFTPEntryParser() 118 { 119 this(null); 120 } 121 122 /** 123 * This constructor allows the creation of a UnixFTPEntryParser object with 124 * something other than the default configuration. 125 * 126 * @param config The {@link FTPClientConfig configuration} object used to 127 * configure this parser. 128 * @exception IllegalArgumentException 129 * Thrown if the regular expression is unparseable. Should not be seen 130 * under normal conditions. It it is seen, this is a sign that 131 * <code>REGEX</code> is not a valid regular expression. 132 * @since 1.4 133 */ 134 public UnixFTPEntryParser(FTPClientConfig config) 135 { 136 super(REGEX); 137 configure(config); 138 } 139 140 141 /** 142 * Parses a line of a unix (standard) FTP server file listing and converts 143 * it into a usable format in the form of an <code> FTPFile </code> 144 * instance. If the file listing line doesn't describe a file, 145 * <code> null </code> is returned, otherwise a <code> FTPFile </code> 146 * instance representing the files in the directory is returned. 147 * <p> 148 * @param entry A line of text from the file listing 149 * @return An FTPFile instance corresponding to the supplied entry 150 */ 151 public FTPFile parseFTPEntry(String entry) { 152 FTPFile file = new FTPFile(); 153 file.setRawListing(entry); 154 int type; 155 boolean isDevice = false; 156 157 if (matches(entry)) 158 { 159 String typeStr = group(1); 160 String hardLinkCount = group(15); 161 String usr = group(16); 162 String grp = group(17); 163 String filesize = group(18); 164 String datestr = group(19) + " " + group(20); 165 String name = group(21); 166 String endtoken = group(22); 167 168 try 169 { 170 file.setTimestamp(super.parseTimestamp(datestr)); 171 } 172 catch (ParseException e) 173 { 174 return null; // this is a parsing failure too. 175 } 176 177 178 // bcdlfmpSs- 179 switch (typeStr.charAt(0)) 180 { 181 case 'd': 182 type = FTPFile.DIRECTORY_TYPE; 183 break; 184 case 'l': 185 type = FTPFile.SYMBOLIC_LINK_TYPE; 186 break; 187 case 'b': 188 case 'c': 189 isDevice = true; 190 // break; - fall through 191 case 'f': 192 case '-': 193 type = FTPFile.FILE_TYPE; 194 break; 195 default: 196 type = FTPFile.UNKNOWN_TYPE; 197 } 198 199 file.setType(type); 200 201 int g = 4; 202 for (int access = 0; access < 3; access++, g += 4) 203 { 204 // Use != '-' to avoid having to check for suid and sticky bits 205 file.setPermission(access, FTPFile.READ_PERMISSION, 206 (!group(g).equals("-"))); 207 file.setPermission(access, FTPFile.WRITE_PERMISSION, 208 (!group(g + 1).equals("-"))); 209 210 String execPerm = group(g + 2); 211 if (!execPerm.equals("-") && !Character.isUpperCase(execPerm.charAt(0))) 212 { 213 file.setPermission(access, FTPFile.EXECUTE_PERMISSION, true); 214 } 215 else 216 { 217 file.setPermission(access, FTPFile.EXECUTE_PERMISSION, false); 218 } 219 } 220 221 if (!isDevice) 222 { 223 try 224 { 225 file.setHardLinkCount(Integer.parseInt(hardLinkCount)); 226 } 227 catch (NumberFormatException e) 228 { 229 // intentionally do nothing 230 } 231 } 232 233 file.setUser(usr); 234 file.setGroup(grp); 235 236 try 237 { 238 file.setSize(Long.parseLong(filesize)); 239 } 240 catch (NumberFormatException e) 241 { 242 // intentionally do nothing 243 } 244 245 if (null == endtoken) 246 { 247 file.setName(name); 248 } 249 else 250 { 251 // oddball cases like symbolic links, file names 252 // with spaces in them. 253 name += endtoken; 254 if (type == FTPFile.SYMBOLIC_LINK_TYPE) 255 { 256 257 int end = name.indexOf(" -> "); 258 // Give up if no link indicator is present 259 if (end == -1) 260 { 261 file.setName(name); 262 } 263 else 264 { 265 file.setName(name.substring(0, end)); 266 file.setLink(name.substring(end + 4)); 267 } 268 269 } 270 else 271 { 272 file.setName(name); 273 } 274 } 275 return file; 276 } 277 return null; 278 } 279 280 /** 281 * Defines a default configuration to be used when this class is 282 * instantiated without a {@link FTPClientConfig FTPClientConfig} 283 * parameter being specified. 284 * @return the default configuration for this parser. 285 */ 286 protected FTPClientConfig getDefaultConfiguration() { 287 return new FTPClientConfig( 288 FTPClientConfig.SYST_UNIX, 289 DEFAULT_DATE_FORMAT, 290 DEFAULT_RECENT_DATE_FORMAT, 291 null, null, null); 292 } 293 294 295 296 297 }