View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  package org.apache.commons.net.ftp;
19  import java.io.Serializable;
20  import java.util.Calendar;
21  import java.util.Date;
22  import java.util.Formatter;
23  import java.util.TimeZone;
24  
25  /***
26   * The FTPFile class is used to represent information about files stored
27   * on an FTP server.
28   *
29   * @see FTPFileEntryParser
30   * @see FTPClient#listFiles
31   ***/
32  
33  public class FTPFile implements Serializable
34  {
35      private static final long serialVersionUID = 9010790363003271996L;
36  
37      /** A constant indicating an FTPFile is a file. ***/
38      public static final int FILE_TYPE = 0;
39      /** A constant indicating an FTPFile is a directory. ***/
40      public static final int DIRECTORY_TYPE = 1;
41      /** A constant indicating an FTPFile is a symbolic link. ***/
42      public static final int SYMBOLIC_LINK_TYPE = 2;
43      /** A constant indicating an FTPFile is of unknown type. ***/
44      public static final int UNKNOWN_TYPE = 3;
45  
46      /** A constant indicating user access permissions. ***/
47      public static final int USER_ACCESS = 0;
48      /** A constant indicating group access permissions. ***/
49      public static final int GROUP_ACCESS = 1;
50      /** A constant indicating world access permissions. ***/
51      public static final int WORLD_ACCESS = 2;
52  
53      /** A constant indicating file/directory read permission. ***/
54      public static final int READ_PERMISSION = 0;
55      /** A constant indicating file/directory write permission. ***/
56      public static final int WRITE_PERMISSION = 1;
57      /**
58       * A constant indicating file execute permission or directory listing
59       * permission.
60       ***/
61      public static final int EXECUTE_PERMISSION = 2;
62  
63      private int _type, _hardLinkCount;
64      private long _size;
65      private String _rawListing, _user, _group, _name, _link;
66      private Calendar _date;
67      // If this is null, then list entry parsing failed
68      private final boolean[] _permissions[]; // e.g. _permissions[USER_ACCESS][READ_PERMISSION]
69  
70      /*** Creates an empty FTPFile. ***/
71      public FTPFile()
72      {
73          _permissions = new boolean[3][3];
74          _type = UNKNOWN_TYPE;
75          // init these to values that do not occur in listings
76          // so can distinguish which fields are unset
77          _hardLinkCount = 0; // 0 is invalid as a link count
78          _size = -1; // 0 is valid, so use -1
79          _user = "";
80          _group = "";
81          _date = null;
82          _name = null;
83      }
84  
85      /**
86       * Constructor for use by {@link FTPListParseEngine} only.
87       * Used to create FTPFile entries for failed parses
88       * @param rawListing line that could not be parsed.
89       * @since 3.4
90       */
91      FTPFile(String rawListing)
92      {
93          _permissions = null; // flag that entry is invalid
94          _rawListing = rawListing;
95          _type = UNKNOWN_TYPE;
96          // init these to values that do not occur in listings
97          // so can distinguish which fields are unset
98          _hardLinkCount = 0; // 0 is invalid as a link count
99          _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 }