001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 018package org.apache.commons.net.ftp; 019import java.io.Serializable; 020import java.util.Calendar; 021import java.util.Date; 022import java.util.Formatter; 023import java.util.TimeZone; 024 025/*** 026 * The FTPFile class is used to represent information about files stored 027 * on an FTP server. 028 * 029 * @see FTPFileEntryParser 030 * @see FTPClient#listFiles 031 ***/ 032 033public class FTPFile implements Serializable 034{ 035 private static final long serialVersionUID = 9010790363003271996L; 036 037 /** A constant indicating an FTPFile is a file. ***/ 038 public static final int FILE_TYPE = 0; 039 /** A constant indicating an FTPFile is a directory. ***/ 040 public static final int DIRECTORY_TYPE = 1; 041 /** A constant indicating an FTPFile is a symbolic link. ***/ 042 public static final int SYMBOLIC_LINK_TYPE = 2; 043 /** A constant indicating an FTPFile is of unknown type. ***/ 044 public static final int UNKNOWN_TYPE = 3; 045 046 /** A constant indicating user access permissions. ***/ 047 public static final int USER_ACCESS = 0; 048 /** A constant indicating group access permissions. ***/ 049 public static final int GROUP_ACCESS = 1; 050 /** A constant indicating world access permissions. ***/ 051 public static final int WORLD_ACCESS = 2; 052 053 /** A constant indicating file/directory read permission. ***/ 054 public static final int READ_PERMISSION = 0; 055 /** A constant indicating file/directory write permission. ***/ 056 public static final int WRITE_PERMISSION = 1; 057 /** 058 * A constant indicating file execute permission or directory listing 059 * permission. 060 ***/ 061 public static final int EXECUTE_PERMISSION = 2; 062 063 private int _type, _hardLinkCount; 064 private long _size; 065 private String _rawListing, _user, _group, _name, _link; 066 private Calendar _date; 067 // If this is null, then list entry parsing failed 068 private final boolean[] _permissions[]; // e.g. _permissions[USER_ACCESS][READ_PERMISSION] 069 070 /*** Creates an empty FTPFile. ***/ 071 public FTPFile() 072 { 073 _permissions = new boolean[3][3]; 074 _type = UNKNOWN_TYPE; 075 // init these to values that do not occur in listings 076 // so can distinguish which fields are unset 077 _hardLinkCount = 0; // 0 is invalid as a link count 078 _size = -1; // 0 is valid, so use -1 079 _user = ""; 080 _group = ""; 081 _date = null; 082 _name = null; 083 } 084 085 /** 086 * Constructor for use by {@link FTPListParseEngine} only. 087 * Used to create FTPFile entries for failed parses 088 * @param rawListing line that could not be parsed. 089 * @since 3.4 090 */ 091 FTPFile(String rawListing) 092 { 093 _permissions = null; // flag that entry is invalid 094 _rawListing = rawListing; 095 _type = UNKNOWN_TYPE; 096 // init these to values that do not occur in listings 097 // so can distinguish which fields are unset 098 _hardLinkCount = 0; // 0 is invalid as a link count 099 _size = -1; // 0 is valid, so use -1 100 _user = ""; 101 _group = ""; 102 _date = null; 103 _name = null; 104 } 105 106 107 /*** 108 * Set the original FTP server raw listing from which the FTPFile was 109 * created. 110 * 111 * @param rawListing The raw FTP server listing. 112 ***/ 113 public void setRawListing(String rawListing) 114 { 115 _rawListing = rawListing; 116 } 117 118 /*** 119 * Get the original FTP server raw listing used to initialize the FTPFile. 120 * 121 * @return The original FTP server raw listing used to initialize the 122 * FTPFile. 123 ***/ 124 public String getRawListing() 125 { 126 return _rawListing; 127 } 128 129 130 /*** 131 * Determine if the file is a directory. 132 * 133 * @return True if the file is of type <code>DIRECTORY_TYPE</code>, false if 134 * not. 135 ***/ 136 public boolean isDirectory() 137 { 138 return (_type == DIRECTORY_TYPE); 139 } 140 141 /*** 142 * Determine if the file is a regular file. 143 * 144 * @return True if the file is of type <code>FILE_TYPE</code>, false if 145 * not. 146 ***/ 147 public boolean isFile() 148 { 149 return (_type == FILE_TYPE); 150 } 151 152 /*** 153 * Determine if the file is a symbolic link. 154 * 155 * @return True if the file is of type <code>UNKNOWN_TYPE</code>, false if 156 * not. 157 ***/ 158 public boolean isSymbolicLink() 159 { 160 return (_type == SYMBOLIC_LINK_TYPE); 161 } 162 163 /*** 164 * Determine if the type of the file is unknown. 165 * 166 * @return True if the file is of type <code>UNKNOWN_TYPE</code>, false if 167 * not. 168 ***/ 169 public boolean isUnknown() 170 { 171 return (_type == UNKNOWN_TYPE); 172 } 173 174 /** 175 * Used to indicate whether an entry is valid or not. 176 * If the entry is invalid, only the {@link #getRawListing()} method will be useful. 177 * Other methods may fail. 178 * 179 * Used in conjunction with list parsing that preseverves entries that failed to parse. 180 * @see FTPClientConfig#setUnparseableEntries(boolean) 181 * @return true if the entry is valid 182 * @since 3.4 183 */ 184 public boolean isValid() { 185 return (_permissions != null); 186 } 187 188 /*** 189 * Set the type of the file (<code>DIRECTORY_TYPE</code>, 190 * <code>FILE_TYPE</code>, etc.). 191 * 192 * @param type The integer code representing the type of the file. 193 ***/ 194 public void setType(int type) 195 { 196 _type = type; 197 } 198 199 200 /*** 201 * Return the type of the file (one of the <code>_TYPE</code> constants), 202 * e.g., if it is a directory, a regular file, or a symbolic link. 203 * 204 * @return The type of the file. 205 ***/ 206 public int getType() 207 { 208 return _type; 209 } 210 211 212 /*** 213 * Set the name of the file. 214 * 215 * @param name The name of the file. 216 ***/ 217 public void setName(String name) 218 { 219 _name = name; 220 } 221 222 /*** 223 * Return the name of the file. 224 * 225 * @return The name of the file. 226 ***/ 227 public String getName() 228 { 229 return _name; 230 } 231 232 233 /** 234 * Set the file size in bytes. 235 * @param size The file size in bytes. 236 */ 237 public void setSize(long size) 238 { 239 _size = size; 240 } 241 242 243 /*** 244 * Return the file size in bytes. 245 * 246 * @return The file size in bytes. 247 ***/ 248 public long getSize() 249 { 250 return _size; 251 } 252 253 254 /*** 255 * Set the number of hard links to this file. This is not to be 256 * confused with symbolic links. 257 * 258 * @param links The number of hard links to this file. 259 ***/ 260 public void setHardLinkCount(int links) 261 { 262 _hardLinkCount = links; 263 } 264 265 266 /*** 267 * Return the number of hard links to this file. This is not to be 268 * confused with symbolic links. 269 * 270 * @return The number of hard links to this file. 271 ***/ 272 public int getHardLinkCount() 273 { 274 return _hardLinkCount; 275 } 276 277 278 /*** 279 * Set the name of the group owning the file. This may be 280 * a string representation of the group number. 281 * 282 * @param group The name of the group owning the file. 283 ***/ 284 public void setGroup(String group) 285 { 286 _group = group; 287 } 288 289 290 /*** 291 * Returns the name of the group owning the file. Sometimes this will be 292 * a string representation of the group number. 293 * 294 * @return The name of the group owning the file. 295 ***/ 296 public String getGroup() 297 { 298 return _group; 299 } 300 301 302 /*** 303 * Set the name of the user owning the file. This may be 304 * a string representation of the user number; 305 * 306 * @param user The name of the user owning the file. 307 ***/ 308 public void setUser(String user) 309 { 310 _user = user; 311 } 312 313 /*** 314 * Returns the name of the user owning the file. Sometimes this will be 315 * a string representation of the user number. 316 * 317 * @return The name of the user owning the file. 318 ***/ 319 public String getUser() 320 { 321 return _user; 322 } 323 324 325 /*** 326 * If the FTPFile is a symbolic link, use this method to set the name of the 327 * file being pointed to by the symbolic link. 328 * 329 * @param link The file pointed to by the symbolic link. 330 ***/ 331 public void setLink(String link) 332 { 333 _link = link; 334 } 335 336 337 /*** 338 * If the FTPFile is a symbolic link, this method returns the name of the 339 * file being pointed to by the symbolic link. Otherwise it returns null. 340 * 341 * @return The file pointed to by the symbolic link (null if the FTPFile 342 * is not a symbolic link). 343 ***/ 344 public String getLink() 345 { 346 return _link; 347 } 348 349 350 /*** 351 * Set the file timestamp. This usually the last modification time. 352 * The parameter is not cloned, so do not alter its value after calling 353 * this method. 354 * 355 * @param date A Calendar instance representing the file timestamp. 356 ***/ 357 public void setTimestamp(Calendar date) 358 { 359 _date = date; 360 } 361 362 363 /*** 364 * Returns the file timestamp. This usually the last modification time. 365 * 366 * @return A Calendar instance representing the file timestamp. 367 ***/ 368 public Calendar getTimestamp() 369 { 370 return _date; 371 } 372 373 374 /*** 375 * Set if the given access group (one of the <code> _ACCESS </code> 376 * constants) has the given access permission (one of the 377 * <code> _PERMISSION </code> constants) to the file. 378 * 379 * @param access The access group (one of the <code> _ACCESS </code> 380 * constants) 381 * @param permission The access permission (one of the 382 * <code> _PERMISSION </code> constants) 383 * @param value True if permission is allowed, false if not. 384 * @throws ArrayIndexOutOfBoundsException if either of the parameters is out of range 385 ***/ 386 public void setPermission(int access, int permission, boolean value) 387 { 388 _permissions[access][permission] = value; 389 } 390 391 392 /*** 393 * Determines if the given access group (one of the <code> _ACCESS </code> 394 * constants) has the given access permission (one of the 395 * <code> _PERMISSION </code> constants) to the file. 396 * 397 * @param access The access group (one of the <code> _ACCESS </code> 398 * constants) 399 * @param permission The access permission (one of the 400 * <code> _PERMISSION </code> constants) 401 * @throws ArrayIndexOutOfBoundsException if either of the parameters is out of range 402 * @return true if {@link #isValid()} is {@code true &&} the associated permission is set; 403 * {@code false} otherwise. 404 ***/ 405 public boolean hasPermission(int access, int permission) 406 { 407 if (_permissions == null) { 408 return false; 409 } 410 return _permissions[access][permission]; 411 } 412 413 /*** 414 * Returns a string representation of the FTPFile information. 415 * 416 * @return A string representation of the FTPFile information. 417 */ 418 @Override 419 public String toString() 420 { 421 return getRawListing(); 422 } 423 424 /*** 425 * Returns a string representation of the FTPFile information. 426 * This currently mimics the Unix listing format. 427 * This method uses the timezone of the Calendar entry, which is 428 * the server time zone (if one was provided) otherwise it is 429 * the local time zone. 430 * <p> 431 * Note: if the instance is not valid {@link #isValid()}, no useful 432 * information can be returned. In this case, use {@link #getRawListing()} 433 * instead. 434 * 435 * @return A string representation of the FTPFile information. 436 * @since 3.0 437 */ 438 public String toFormattedString() 439 { 440 return toFormattedString(null); 441 } 442 443 /** 444 * Returns a string representation of the FTPFile information. 445 * This currently mimics the Unix listing format. 446 * This method allows the Calendar time zone to be overridden. 447 * <p> 448 * Note: if the instance is not valid {@link #isValid()}, no useful 449 * information can be returned. In this case, use {@link #getRawListing()} 450 * instead. 451 * @param timezone the timezone to use for displaying the time stamp 452 * If {@code null}, then use the Calendar entry timezone 453 * @return A string representation of the FTPFile information. 454 * @since 3.4 455 */ 456 public String toFormattedString(final String timezone) 457 { 458 459 if (!isValid()) { 460 return "[Invalid: could not parse file entry]"; 461 } 462 StringBuilder sb = new StringBuilder(); 463 Formatter fmt = new Formatter(sb); 464 sb.append(formatType()); 465 sb.append(permissionToString(USER_ACCESS)); 466 sb.append(permissionToString(GROUP_ACCESS)); 467 sb.append(permissionToString(WORLD_ACCESS)); 468 fmt.format(" %4d", Integer.valueOf(getHardLinkCount())); 469 fmt.format(" %-8s %-8s", getUser(), getGroup()); 470 fmt.format(" %8d", Long.valueOf(getSize())); 471 Calendar timestamp = getTimestamp(); 472 if (timestamp != null) { 473 if (timezone != null) { 474 TimeZone newZone = TimeZone.getTimeZone(timezone); 475 if (!newZone.equals(timestamp.getTimeZone())){ 476 Date original = timestamp.getTime(); 477 Calendar newStamp = Calendar.getInstance(newZone); 478 newStamp.setTime(original); 479 timestamp = newStamp; 480 } 481 } 482 fmt.format(" %1$tY-%1$tm-%1$td", timestamp); 483 // Only display time units if they are present 484 if (timestamp.isSet(Calendar.HOUR_OF_DAY)) { 485 fmt.format(" %1$tH", timestamp); 486 if (timestamp.isSet(Calendar.MINUTE)) { 487 fmt.format(":%1$tM", timestamp); 488 if (timestamp.isSet(Calendar.SECOND)) { 489 fmt.format(":%1$tS", timestamp); 490 if (timestamp.isSet(Calendar.MILLISECOND)) { 491 fmt.format(".%1$tL", timestamp); 492 } 493 } 494 } 495 fmt.format(" %1$tZ", timestamp); 496 } 497 } 498 sb.append(' '); 499 sb.append(getName()); 500 fmt.close(); 501 return sb.toString(); 502 } 503 504 private char formatType(){ 505 switch(_type) { 506 case FILE_TYPE: 507 return '-'; 508 case DIRECTORY_TYPE: 509 return 'd'; 510 case SYMBOLIC_LINK_TYPE: 511 return 'l'; 512 default: 513 return '?'; 514 } 515 } 516 517 private String permissionToString(int access ){ 518 StringBuilder sb = new StringBuilder(); 519 if (hasPermission(access, READ_PERMISSION)) { 520 sb.append('r'); 521 } else { 522 sb.append('-'); 523 } 524 if (hasPermission(access, WRITE_PERMISSION)) { 525 sb.append('w'); 526 } else { 527 sb.append('-'); 528 } 529 if (hasPermission(access, EXECUTE_PERMISSION)) { 530 sb.append('x'); 531 } else { 532 sb.append('-'); 533 } 534 return sb.toString(); 535 } 536}