jafs-library-20020725
[openafs.git] / src / JAVA / classes / org / openafs / jafs / File.java
1 /*
2  * @(#)File.java        1.3 10/12/2000
3  *
4  * Copyright (c) 2001 International Business Machines Corp.
5  * All rights reserved.
6  *
7  * This software has been released under the terms of the IBM Public
8  * License.  For details, see the LICENSE file in the top-level source
9  * directory or online at http://www.openafs.org/dl/license10.html
10  * 
11  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
12  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
13  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
14  * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR
15  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
16  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
17  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
18  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
19  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
20  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
21  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
22  */
23
24 package org.openafs.jafs;
25
26 import java.io.IOException;
27 import java.util.ArrayList;
28
29 /*****************************************************************************/
30 /**
31  * 
32  * An abstract representation of AFS file and directory pathnames.
33  *
34  * This class is an extension of the standard Java File class with file-based 
35  * manipulation methods overridden by integrated AFS native methods.
36  *
37  * <p> Extension methods include:
38  *
39  * <ol>
40  * <li> <code>{@link #isMountPoint}</code>
41  * <li> <code>{@link #isLink}</code>
42  * <li> <code>{@link #isValidated}</code>
43  * <li> <code>{@link #validate}</code>
44  * <li> <code>{@link #refresh}</code>
45  * <li> <code>{@link #getErrorCode}</code>
46  * <li> <code>{@link #getErrorMessage}</code>
47  * </ol>
48  *
49  * <p> For performance optimization, all newly constructed <code>File</code> 
50  * objects are only validated once.  Furthermore, if an abstract pathname 
51  * denotes a symbolic-link, then the {@link #isLink} attribute is set 
52  * to true and the {@link #getTarget} field member is populated with 
53  * this symbolic-link's target resource. (see {@link #getTarget})
54  * 
55  * <p> If you are interested in validating the target resource, simply 
56  * call {@link #validate} before calling any of the attribute accessors. 
57  * This action will <code>stat</code> the target resource, identifying 
58  * its associated attributes and populating them in this objects field 
59  * members.
60  * 
61  * <p> Following is an example of how to construct a new AFS File Object:
62  * <p><blockquote><pre>
63  *     try {
64  *         File file = new File("/afs/mycell.com/proj/");
65  *         if (file.isDirectory()) {
66  *           System.out.println("This is a directory.");
67  *         } else if (file.isLink()) {
68  *           System.out.println("This is a symbolic-link.");
69  *           System.out.println("  Its target is: " + file.getTarget());
70  *           file.validate();
71  *           if (file.isFile()) {
72  *             System.out.println("  This object is now a file!");
73  *           } else if (file.isDirectory()) {
74  *             System.out.println("  This object is now a directory!");
75  *           } else if (file.isMountPoint()) {
76  *             System.out.println("  This object is now a volume mount point!");
77  *           }
78  *         } else if (file.isMountPoint()) {
79  *           System.out.println("This is a volume mount point.");
80  *         } else if (file.isFile()) {
81  *           System.out.println("This is file.");
82  *           System.out.println("  its size is: " + file.length());
83  *         }
84  *     } catch (AFSFileException ae) {
85  *         System.out.println("AFS Exception: " + ae.getMessage());
86  *         System.out.println("AFS Error Code: " + ae.getErrorCode());
87  *     } catch (Exception e) {
88  *         System.out.println("Exception: " + e.getMessage());
89  *         e.printStackTrace();
90  *     }
91  * </pre></blockquote>
92  *
93  * @version 2.0, 04/16/2001 - Completely revised class for efficiency.
94  * @version 1.3, 10/12/2000 - Introduced error code capture from native methods.
95  * @version 1.2, 05/30/2000
96  */
97 public class File extends java.io.File implements Comparable
98 {
99   private String path;
100   private String type;
101   private String target;
102
103   /** Each member is mutually exclusive */
104   private boolean isMountPoint = false;
105   private boolean isDirectory = false;
106   private boolean isFile = false;
107   private boolean isLink = false;
108
109   private boolean exists;
110   private long lastModified;
111   private long length;
112
113   private ACL.Entry acl;
114   private boolean validated = false;
115   private long dirHandle;
116   private int permissionsMask;
117   private int errno;
118
119   /**
120    * Creates a new <code>File</code> instance by converting the given
121    * pathname string into an abstract pathname and validating it against
122    * the file system.  If the given string is an empty string, then the 
123    * result is the empty abstract pathname; otherwise the abstract pathname 
124    * is <code>validated</code> to represent a qualified file object.
125    *
126    * @param   pathname  A pathname string
127    * @throws  NullPointerException
128    *          If the <code>pathname</code> argument is <code>null</code>
129    * @throws  AFSFileException
130    *          If the user constructing this AFS file object is denied
131    *          access to stat the file or simply a stat cannot be performed
132    *          on the file. The reason code and message will be available
133    *          from {@link org.openafs.jafs.AFSFileException#getErrorCode} and 
134    *          {@link org.openafs.jafs.AFSFileException#getMessage} respectively.
135    *          <p> This exception <U>will not</U> be thrown if the file does not
136    *          exist.  Rather, the {@link #exists} attribute will be set to
137    *          <code>false</code>.
138    * @see     #validate()
139    */
140   public File(String pathname) throws AFSFileException
141   {
142         super(pathname);
143         path = getAbsolutePath();
144         validated = setAttributes();
145         if (!validated) throw new AFSFileException(errno);
146   }
147   /**
148    * Creates a new <code>File</code> instance by converting the given
149    * pathname string into an abstract pathname.  If the given string is
150    * an empty string, then the result is the empty abstract pathname.
151    *
152    * <p> The abstract pathname will remain <B>abstract</B> unless the
153    * <code>validate</code> parameter is set to <code>true</code>. This
154    * means that the abstract pathname will <U>not</U> be <code>validated</code>
155    * and therefore the file object will not represent a qualified, attributed,
156    * AFS file resource.  Rather, this constructor provides a method by which
157    * you can construct a non-validated <code>File</code> object (one that
158    * does not contain the file's complete status information).
159    *
160    * <p> This constructor is useful for creating file objects of file/path names
161    * that you know exist, however are unauthorized to <code>validate</code> (or
162    * <code>stat</code> - to obtain complete status information). For example,
163    * if you are permitted to <code>lookup</code> (see: {@link #canLookup}) the
164    * contents of a given directory yet <U>not</U> permitted to <code>read</code>
165    * (see: {@link #canRead}), then this constructor would enable you to render the
166    * contents of the directory without validating each entry.
167    *
168    * <p> <B>Please note:</B> this is the only constructor that does not throw an AFSFileException.
169    *
170    * @param   pathname  A pathname string
171    * @param   validate  A boolean flag to indicate if this abstract path
172    *                            should be validated.
173    * @throws  NullPointerException
174    *          If the <code>pathname</code> argument is <code>null</code>
175    * @see         #File(String)
176    * @see     #validate()
177    */
178   public File(String pathname, boolean validate)
179   {
180         super(pathname);
181         path = getAbsolutePath();
182         if (validate) validated = setAttributes();
183   }
184   /**
185    * Creates a new <code>File</code> instance from a parent pathname string
186    * and a child pathname string and validates it against the file system.
187    *
188    * <p> If <code>parent</code> is <code>null</code> then the new
189    * <code>File</code> instance is created as if by invoking the
190    * single-argument <code>File</code> constructor on the given
191    * <code>filename</code> string (child pathname).
192    *
193    * <p> Otherwise the <code>parent</code> pathname string is taken to denote
194    * a directory, and the <code>filename</code> string is taken to
195    * denote either a directory or a file. The directory or file will then be
196    * <code>validated</code> to represent a qualified file object.
197    *
198    * @param   parent   The parent pathname string
199    * @param   filename This file's pathname string (child of specified parent)
200    * @throws  NullPointerException
201    *          If <code>child</code> is <code>null</code>
202    * @throws  AFSFileException
203    *          If the user constructing this AFS file object is denied
204    *          access to stat the file or simply a stat cannot be performed
205    *          on the file. The reason code and message will be available
206    *          from {@link org.openafs.jafs.AFSFileException#getErrorCode} and 
207    *          {@link org.openafs.jafs.AFSFileException#getMessage} respectively.
208    *          <p> This exception <U>will not</U> be thrown if the file does not
209    *          exist.  Rather, the {@link #exists} attribute will be set to
210    *          <code>false</code>.
211    * @see     #validate()
212    */
213   public File(String parent, String filename) throws AFSFileException
214   {
215         super(parent, filename);
216         path = getAbsolutePath();
217         validated = setAttributes();
218         if (!validated) throw new AFSFileException(errno);
219   }
220   /**
221    * Creates a new <code>File</code> instance from a parent pathname string
222    * and a child pathname string.
223    *
224    * <p> If <code>parent</code> is <code>null</code> then the new
225    * <code>File</code> instance is created as if by invoking the
226    * single-argument <code>File</code> constructor on the given
227    * <code>filename</code> string (child pathname).
228    *
229    * <p> Otherwise the <code>parent</code> pathname string is taken to denote
230    * a directory, and the <code>filename</code> string is taken to
231    * denote either a directory or a file.
232    *
233    * <p> The abstract pathname will remain <B>abstract</B> unless the
234    * <code>validate</code> parameter is set to <code>true</code>. This
235    * means that the abstract pathname will <U>not</U> be <code>validated</code>
236    * and therefore the file object will not represent a qualified, attributed,
237    * AFS file resource.  Rather, this constructor provides a method by which
238    * you can construct a non-validated <code>File</code> object (one that
239    * does not contain the file's complete status information).
240    *
241    * <p> This constructor is useful for creating file objects of file/path names
242    * that you know exist, however are unauthorized to <code>validate</code> (or
243    * <code>stat</code> - to obtain complete status information). For example,
244    * if you are permitted to <code>lookup</code> (see: {@link #canLookup}) the
245    * contents of a given directory yet <U>not</U> permitted to <code>read</code>
246    * (see: {@link #canRead}), then this constructor would enable you to render the
247    * contents of the directory without validating each entry.
248    *
249    * @param   parent    The parent pathname string
250    * @param   filename  This file's pathname string (child of specified parent)
251    * @param   validate  A boolean flag to indicate if this abstract path
252    *                            should be validated.
253    * @throws  NullPointerException
254    *          If <code>child</code> is <code>null</code>
255    * @throws  AFSFileException
256    *          If the user constructing this AFS file object is denied
257    *          access to stat the file or simply a stat cannot be performed
258    *          on the file. The reason code and message will be available
259    *          from {@link org.openafs.jafs.AFSFileException#getErrorCode} and 
260    *          {@link org.openafs.jafs.AFSFileException#getMessage} respectively.
261    *          <p> This exception <U>will not</U> be thrown if the file does not
262    *          exist.  Rather, the {@link #exists} attribute will be set to
263    *          <code>false</code>.
264    * @see         #File(String, String)
265    * @see     #validate()
266    */
267   public File(String parent, String filename, boolean validate) throws AFSFileException
268   {
269         super(parent, filename);
270         path = getAbsolutePath();
271         if (validate) {
272           validated = setAttributes();
273           if (!validated) throw new AFSFileException(errno);
274         }
275   }
276   /**
277    * Creates a new <code>File</code> instance from a parent abstract
278    * pathname and a child pathname string and validates it against the file system.
279    *
280    * <p> If <code>parent</code> is <code>null</code> then the new
281    * <code>File</code> instance is created as if by invoking the
282    * single-argument <code>File</code> constructor on the given
283    * <code>filename</code> string (child pathname).
284    *
285    * <p> Otherwise the <code>parent</code> abstract pathname is taken to
286    * denote a directory, and the <code>filename</code> string is taken
287    * to denote either a directory or a file.  The directory or file will then be
288    * <code>validated</code> to represent a qualified file object.
289    *
290    * @param   parent    The parent abstract pathname
291    * @param   filename  This file's pathname string (child of specified parent)
292    * @param   validate  A boolean flag to indicate if this abstract path
293    *                            should be validated.
294    * @throws  NullPointerException
295    *          If <code>child</code> is <code>null</code>
296    * @throws  AFSFileException
297    *          If the user constructing this AFS file object is denied
298    *          access to stat the file or simply a stat cannot be performed
299    *          on the file. The reason code and message will be available
300    *          from {@link org.openafs.jafs.AFSFileException#getErrorCode} and 
301    *          {@link org.openafs.jafs.AFSFileException#getMessage} respectively.
302    *          <p> This exception <U>will not</U> be thrown if the file does not
303    *          exist.  Rather, the {@link #exists} attribute will be set to
304    *          <code>false</code>.
305    * @see     #validate()
306    */
307   public File(File parent, String filename) throws AFSFileException
308   {
309         super(parent, filename);
310         path = getAbsolutePath();
311         validated = setAttributes();
312         if (!validated) throw new AFSFileException(errno);
313   }
314   /**
315    * Creates a new <code>File</code> instance from a parent abstract
316    * pathname and a child pathname string.
317    *
318    * <p> If <code>parent</code> is <code>null</code> then the new
319    * <code>File</code> instance is created as if by invoking the
320    * single-argument <code>File</code> constructor on the given
321    * <code>filename</code> string (child pathname).
322    *
323    * <p> Otherwise the <code>parent</code> abstract pathname is taken to
324    * denote a directory, and the <code>filename</code> string is taken
325    * to denote either a directory or a file.
326    *
327    * <p> The abstract pathname will remain <B>abstract</B> unless the
328    * <code>validate</code> parameter is set to <code>true</code>. This
329    * means that the abstract pathname will <U>not</U> be <code>validated</code>
330    * and therefore the file object will not represent a qualified, attributed,
331    * AFS file resource.  Rather, this constructor provides a method by which
332    * you can construct a non-validated <code>File</code> object (one that
333    * does not contain the file's complete status information).
334    *
335    * <p> This constructor is useful for creating file objects of file/path names
336    * that you know exist, however are unauthorized to <code>validate</code> (or
337    * <code>stat</code> - to obtain complete status information). For example,
338    * if you are permitted to <code>lookup</code> (see: {@link #canLookup}) the
339    * contents of a given directory yet <U>not</U> permitted to <code>read</code>
340    * (see: {@link #canRead}), then this constructor would enable you to render the
341    * contents of the directory without validating each entry.
342    *
343    * @param   parent    The parent abstract pathname
344    * @param   filename  This file's pathname string (child of specified parent)
345    * @param   validate  A boolean flag to indicate if this abstract path
346    *                            should be validated.
347    * @throws  NullPointerException
348    *          If <code>child</code> is <code>null</code>
349    * @throws  AFSFileException
350    *          If the user constructing this AFS file object is denied
351    *          access to stat the file or simply a stat cannot be performed
352    *          on the file. The reason code and message will be available
353    *          from {@link org.openafs.jafs.AFSFileException#getErrorCode} and 
354    *          {@link org.openafs.jafs.AFSFileException#getMessage} respectively.
355    *          <p> This exception <U>will not</U> be thrown if the file does not
356    *          exist.  Rather, the {@link #exists} attribute will be set to
357    *          <code>false</code>.
358    * @see     #validate()
359    * @see         #File(File, String)
360    */
361   public File(File parent, String filename, boolean validate) throws AFSFileException
362   {
363         super(parent, filename);
364         path = getAbsolutePath();
365         if (validate) {
366           validated = setAttributes();
367           if (!validated) throw new AFSFileException(errno);
368         }
369   }
370
371   /*****************************************************************************/
372
373   /**
374    * Validates this abstract pathname as an attributed AFS file object.  
375    * This method will, if authorized, perform a <code>stat</code> on the
376    * actual AFS file and update its respective field members; defining
377    * this file object's attributes.
378    *
379    * @throws  AFSSecurityException
380    *          If an AFS exception occurs while attempting to stat and set this
381    *          AFS file object's attributes.
382    */
383   public void validate() throws AFSSecurityException
384   {
385         validated = setAttributes();
386         if (!validated) throw new AFSSecurityException(errno);
387   }
388   /**
389    * Tests whether the file denoted by this abstract pathname has
390    * been validated.
391    *
392    * <P> Validation is always attempted upon construction of the file object,
393    * therefore if this method returns false, then you are not permitted to 
394    * <code>validate</code> this file and consequently all attribute accessors
395    * will be invalid.
396    *
397    * <P> This method should return <code>true</code> even if this abstract 
398    * pathname does not exist. If this is abstract pathname does not exist then
399    * the <code>{@link #exists}</code> method should return false, however this
400    * implies that the attribute accessors are valid and accurate; thus implying
401    * successful validation.
402    *
403    * <P> This method is useful before calling any of the attribute accessors
404    * to ensure a valid response. 
405    *
406    * @return <code>true</code> if and only if the file denoted by this
407    *          abstract pathname has been validated during or after object construction;
408    *          <code>false</code> otherwise
409    */
410   public boolean isValidated()
411   {
412         return validated;
413   }
414   /**
415    * Refreshes this AFS file object by updating its attributes.
416    * This method currently provides the same functionality as
417    * {@link #validate}.
418    *
419    * @throws  AFSSecurityException
420    *          If an AFS exception occurs while attempting to stat and update this
421    *          AFS file object's attributes.
422    * @see     #validate()
423    */
424   public void refresh() throws AFSSecurityException
425   {
426         validate();
427   }
428   /*-------------------------------------------------------------------------*/
429   /**
430    * Tests whether the file denoted by this abstract pathname is a
431    * directory.
432    *
433    * @return <code>true</code> if and only if the file denoted by this
434    *          abstract pathname exists <em>and</em> is a directory;
435    *          <code>false</code> otherwise
436    */
437   public boolean isDirectory() 
438   {
439         return (isDirectory || isMountPoint) ? true : false;
440   }
441   /**
442    * Tests whether the file denoted by this abstract pathname is a normal
443    * file.  A file is <em>normal</em> if it is not a directory and, in
444    * addition, satisfies other system-dependent criteria.  Any non-directory
445    * file created by a Java application is guaranteed to be a normal file.
446    *
447    * @return  <code>true</code> if and only if the file denoted by this
448    *          abstract pathname exists <em>and</em> is a normal file;
449    *          <code>false</code> otherwise
450    */
451   public boolean isFile() 
452   {
453         return isFile;
454   }
455   /**
456    * Tests whether the file denoted by this abstract pathname is an
457    * AFS Volume Mount Point.
458    *
459    * @return <code>true</code> if and only if the file denoted by this
460    *          abstract pathname exists <em>and</em> is a mount point;
461    *          <code>false</code> otherwise
462    */
463   public boolean isMountPoint() 
464   {
465         return isMountPoint;
466   }
467   /**
468    * Tests whether the file denoted by this abstract pathname is a
469    * symbolic-link.
470    *
471    * @return <code>true</code> if and only if the file denoted by this
472    *          abstract pathname exists <em>and</em> is a symbolic-link;
473    *          <code>false</code> otherwise
474    */
475   public boolean isLink()
476   {
477         return isLink;
478   }
479   /*-------------------------------------------------------------------------*/
480   /**
481    * Tests whether the file denoted by this abstract pathname exists.
482    *
483    * @return  <code>true</code> if and only if the file denoted by this
484    *          abstract pathname exists; <code>false</code> otherwise
485    */
486   public boolean exists() 
487   {
488         return exists;
489   }
490   /**
491    * Returns the time that the file denoted by this abstract pathname was
492    * last modified.
493    *
494    * @return  A <code>long</code> value representing the time the file was
495    *          last modified, measured in milliseconds since the epoch
496    *          (00:00:00 GMT, January 1, 1970), or <code>0L</code> if the
497    *          file does not exist or if an I/O error occurs
498    */
499   public long lastModified() 
500   {
501         return lastModified;
502   }
503   /**
504    * Returns the length of the file denoted by this abstract pathname.
505    *
506    * @return  The length, in bytes, of the file denoted by this abstract
507    *          pathname, or <code>0L</code> if the file does not exist
508    */
509   public long length() 
510   {
511         return length;
512   }
513   /**
514    * Returns an abstract pathname string that represents the target resource of
515    * of this file, if it is a symbolic-link.
516    *
517    * <p> If this abstract pathname <B>does not</B> denote a symbolic-link, then this
518    * method returns <code>null</code>.  Otherwise a string is
519    * returned that represents the target resource of this symbolic-link.
520    *
521    * @return  A string representation of this symbolic-link's target resource.
522    * @see     #isLink()
523    */
524   public String getTarget()
525   {
526         return target;
527   }
528   /**
529    * Returns an array of strings naming the files and directories in the
530    * directory denoted by this abstract pathname.
531    *
532    * <p> If this abstract pathname does not denote a directory, then this
533    * method returns <code>null</code>.  Otherwise an array of strings is
534    * returned, one for each file or directory in the directory.  Names
535    * denoting the directory itself and the directory's parent directory are
536    * not included in the result.  Each string is a file name rather than a
537    * complete path.
538    *
539    * <p> There is no guarantee that the name strings in the resulting array
540    * will appear in any specific order; they are not, in particular,
541    * guaranteed to appear in alphabetical order.
542    *
543    * @return  An array of strings naming the files and directories in the
544    *          directory denoted by this abstract pathname.  The array will be
545    *          empty if the directory is empty.  Returns <code>null</code> if
546    *          this abstract pathname does not denote a directory, or if an
547    *          I/O error occurs.
548    */
549   public String[] list()
550   {
551         try {
552           if (isFile()) {
553             errno = ErrorTable.NOT_DIRECTORY;
554             return null;
555           }
556           ArrayList buffer = new ArrayList();
557           dirHandle = listNative(buffer);
558           if (dirHandle == 0) {
559             return null;
560           } else {
561             return (String[])buffer.toArray(new String[0]);
562           }
563         } catch (Exception e) {
564           System.out.println(e);
565           return null;
566         }
567   }
568   /**
569    * Returns an ArrayList object containing strings naming the files and 
570    * directories in the directory denoted by this abstract pathname.
571    *
572    * <p> If this abstract pathname does not denote a directory, then this
573    * method returns <code>null</code>.  Otherwise an array of strings is
574    * returned, one for each file or directory in the directory.  Names
575    * denoting the directory itself and the directory's parent directory are
576    * not included in the result.  Each string is a file name rather than a
577    * complete path.
578    *
579    * <p> There is no guarantee that the name strings in the resulting array
580    * will appear in any specific order; they are not, in particular,
581    * guaranteed to appear in alphabetical order.
582    *
583    * @return  An array of strings naming the files and directories in the
584    *          directory denoted by this abstract pathname.  The array will be
585    *          empty if the directory is empty.  Returns <code>null</code> if
586    *          this abstract pathname does not denote a directory, or if an
587    *          I/O error occurs.
588    * @throws  AFSSecurityException
589    *          If you are not authorized to list the contents of this directory
590    * @throws  AFSFileException
591    *          If this file object is not a <code>mount point</code>, <code>link
592    *          </code>, or <code>directory</code> <B>or</B> an unexpected AFS 
593    *          error occurs.
594    * @see     #list()
595    */
596   public ArrayList listArray() throws AFSFileException
597   {
598         try {
599           if (isFile()) throw new AFSFileException(ErrorTable.NOT_DIRECTORY);
600           ArrayList buffer = new ArrayList();
601           dirHandle = listNative(buffer);
602           if (dirHandle == 0) {
603             if (errno == ErrorTable.PERMISSION_DENIED) {
604                 throw new AFSSecurityException(errno);
605             } else {
606                 throw new AFSFileException(errno);
607             }
608           } else {
609             return buffer;
610           }
611         } catch (Exception e) {
612           System.out.println(e);
613           throw new AFSFileException(errno);
614         }
615   }
616   /*-------------------------------------------------------------------------*/
617   /**
618    * Deletes the file or directory denoted by this abstract pathname.  If
619    * this pathname denotes a directory, then the directory must be empty in
620    * order to be deleted.
621    *
622    * @return  <code>true</code> if and only if the file or directory is
623    *          successfully deleted; <code>false</code> otherwise
624    */
625   public boolean delete()
626   {
627         try {
628           if(this.isDirectory()) {
629             return this.rmdir();
630           } else if(this.isFile() || this.isLink()) {
631             return this.rmfile();
632           }
633           return false;
634         } catch (Exception e) {
635           System.out.println(e);
636           return false;
637         }
638   }
639   /**
640    * Copies the file denoted by this abstract pathname to the destination
641    * file provided.  Then checks the newly copied file's size to
642    * test for file size consistency.
643    *
644    * @param  dest  The new abstract pathname for the named file
645    * 
646    * @return  <code>true</code> if and only if the file that was copied
647    *          reports the same file size (length) as that of this file;
648    *          <code>false</code> otherwise
649    *
650    * @throws  AFSFileException
651    *          If an I/O or AFS exception is encountered while copying the file.
652    */
653   public boolean copyTo(File dest) throws AFSFileException
654   {
655     FileInputStream fis  = new FileInputStream(this);
656     FileOutputStream fos = new FileOutputStream(dest);
657     byte[] buf = new byte[1024];
658     int i = 0;
659     while((i=fis.read(buf))!=-1) {
660       fos.write(buf, 0, i);
661     }
662     fis.close();
663     fos.close();
664     dest.validate();
665     return (dest.length() == this.length());
666   }
667   /*-------------------------------------------------------------------------*/
668   /**
669    * Returns the permissions mask of the ACL for this object relative to the user accessing it.
670    *
671    * @return  the permissions mask of this object based upon the current user.
672    * @see     org.openafs.jafs.ACL.Entry#getPermissionsMask()
673    */
674   public int getPermissionsMask() 
675   {
676         return getRights();
677   }
678   /**
679    * Tests whether the user can administer the ACL (see: {@link org.openafs.jafs.ACL}
680    * of the directory denoted by this abstract pathname.
681    *
682    * @see org.openafs.jafs.ACL.Entry#canAdmin
683    * @return  <code>true</code> if and only if the directory specified by this
684    *          abstract pathname exists <em>and</em> can be administered by the
685    *          current user; <code>false</code> otherwise
686    */
687   public boolean canAdmin()
688   {
689         if (acl == null) acl = new ACL.Entry(getRights());
690         return acl.canAdmin();
691   }
692   /**
693    * Tests whether the current user can delete the files or subdirectories of
694    * the directory denoted by this abstract pathname.
695    *
696    * @see org.openafs.jafs.ACL.Entry#canDelete
697    * @return  <code>true</code> if and only if the directory specified by this
698    *          abstract pathname exists <em>and</em> permits deletion of its files
699    *          and subdirectories by the current user; <code>false</code> otherwise
700    */
701   public boolean canDelete()
702   {
703         if (acl == null) acl = new ACL.Entry(getRights());
704         return acl.canDelete();
705   }
706   /**
707    * Tests whether the current user can insert a file into the directory
708    * denoted by this abstract pathname.
709    *
710    * @see org.openafs.jafs.ACL.Entry#canInsert
711    * @return  <code>true</code> if and only if the directory specified by this
712    *          abstract pathname exists <em>and</em> a file can be inserted by the
713    *          current user; <code>false</code> otherwise
714    */
715   public boolean canInsert()
716   {
717         if (acl == null) acl = new ACL.Entry(getRights());
718         return acl.canInsert();
719   }
720   /**
721    * Tests whether the current user can lock the file denoted by this 
722    * abstract pathname.
723    *
724    * @see org.openafs.jafs.ACL.Entry#canLock
725    * @return  <code>true</code> if and only if the file specified by this
726    *          abstract pathname exists <em>and</em> can be locked by the
727    *          current user; <code>false</code> otherwise
728    */
729   public boolean canLock()
730   {
731         if (acl == null) acl = new ACL.Entry(getRights());
732         return acl.canLock();
733   }
734   /**
735    * Tests whether the current user can lookup the contents of the directory
736    * denoted by this abstract pathname.
737    *
738    * @see org.openafs.jafs.ACL.Entry#canLookup
739    * @return  <code>true</code> if and only if the directory specified by this
740    *          abstract pathname exists <em>and</em> its contents can be listed by the
741    *          current user; <code>false</code> otherwise
742    */
743   public boolean canLookup()
744   {
745         if (acl == null) acl = new ACL.Entry(getRights());
746         return acl.canLookup();
747   }
748   /**
749    * Tests whether the current user can read the file denoted by this
750    * abstract pathname.
751    *
752    * @see org.openafs.jafs.ACL.Entry#canRead
753    * @return  <code>true</code> if and only if the file specified by this
754    *          abstract pathname exists <em>and</em> can be read by the
755    *          current user; <code>false</code> otherwise
756    */
757   public boolean canRead()
758   {
759         if (acl == null) acl = new ACL.Entry(getRights());
760         return acl.canRead();
761   }
762   /**
763    * Tests whether the current user can modify to the file denoted by this
764    * abstract pathname.
765    *
766    * @see org.openafs.jafs.ACL.Entry#canWrite
767    * @return  <code>true</code> if and only if the file system actually
768    *          contains a file denoted by this abstract pathname <em>and</em>
769    *          the current user is allowed to write to the file;
770    *          <code>false</code> otherwise.
771    */
772   public boolean canWrite()
773   {
774         if (acl == null) acl = new ACL.Entry(getRights());
775         return acl.canWrite();
776   }
777   /*-------------------------------------------------------------------------*/
778   /**
779    * Closes the directory denoted by this abstract pathname.
780    *
781    * @return  <code>true</code> if and only if the directory is
782    *          successfully closed; <code>false</code> otherwise
783    */
784   public boolean close()
785   {
786         if (dirHandle == 0) {
787           return false;
788         }
789         return closeDir(dirHandle);
790   }
791   /*-------------------------------------------------------------------------*/
792   /**
793    * Returns the AFS specific error number (code).  This code can be interpreted 
794    * by use of <code>{@link org.openafs.jafs.ErrorTable}</code> static class method 
795    * <code>{@link org.openafs.jafs.ErrorTable#getMessage}</code>
796    *
797    * @return  the AFS error code (number) associated with the last action performed
798    *          on this object.
799    * @see     org.openafs.jafs.ErrorTable#getMessage(int)
800    */
801   public int getErrorCode() 
802   {
803         return errno;
804   }
805   /**
806    * Returns the AFS error message string defined by the <code>{@link org.openafs.jafs.ErrorTable}</code>
807    * class.
808    *
809    * @return  the AFS error message string associated with the last action performed
810    *          on this object.
811    * @see     org.openafs.jafs.ErrorTable#getMessage(int)
812    */
813   public String getErrorMessage() 
814   {
815         return ErrorTable.getMessage(errno);
816   }
817
818   /////////////// custom override methods ////////////////////
819
820   /**
821    * Compares two File objects relative to their filenames and <B>does not</B>
822    * compare their respective absolute paths.  Alphabetic case is significant in 
823    * comparing filenames.
824    *
825    * @param   file  The File object to be compared to this file's filename
826    * 
827    * @return  Zero if the argument is equal to this file's filename, a
828    *            value less than zero if this file's filename is
829    *            lexicographically less than the argument, or a value greater
830    *            than zero if this file's filename is lexicographically
831    *            greater than the argument
832    *
833    * @since   JDK1.2
834    */
835   public int compareTo(File file) {
836     return this.getName().compareTo(file.getName());
837   }
838   /**
839    * Compares this file to another File object.  If the other object
840    * is an abstract pathname, then this function behaves like <code>{@link
841    * #compareTo(File)}</code>.  Otherwise, it throws a
842    * <code>ClassCastException</code>, since File objects can only be
843    * compared to File objects.
844    *
845    * @param   o  The <code>Object</code> to be compared to this abstract pathname
846    *
847    * @return  If the argument is an File object, returns zero
848    *          if the argument is equal to this file's filename, a value
849    *          less than zero if this file's filename is lexicographically
850    *          less than the argument, or a value greater than zero if this
851    *          file's filename is lexicographically greater than the
852    *          argument
853    *
854    * @throws  <code>ClassCastException</code> if the argument is not an
855    *              File object
856    *
857    * @see     java.lang.Comparable
858    * @since   JDK1.2
859    */
860   public int compareTo(Object o) throws ClassCastException 
861   { 
862     File file = (File)o;
863     return compareTo(file);
864   } 
865
866   /////////////// public native methods ////////////////////
867
868   /**
869    * Creates the directory named by this abstract pathname.
870    *
871    * @return  <code>true</code> if and only if the directory was
872    *          created; <code>false</code> otherwise
873    */
874   public native boolean mkdir();
875   /**
876    * Renames the file denoted by this abstract pathname.
877    *
878    * @param  dest  The new abstract pathname for the named file
879    * 
880    * @return  <code>true</code> if and only if the renaming succeeded;
881    *          <code>false</code> otherwise
882    *
883    * @throws  NullPointerException  
884    *          If parameter <code>dest</code> is <code>null</code>
885    */
886   public native boolean renameTo(File dest);
887   /**
888    * Performs a file <code>stat</code> on the actual AFS file and populates  
889    * this object's respective field members with the appropriate values.
890    * method will, if authorized, perform a <code>stat</code> on the
891    * actual AFS file and update its respective field members; defining
892    * this file object's attributes.
893    *
894    * <P><B>This method should not be used directly for refreshing or validating
895    * this AFS file object.  Please use {@link #validate} instead.</B>
896    *
897    * @return  <code>true</code> if and only if the current user is allowed to stat the file;
898    *          <code>false</code> otherwise.
899    * @see     #validate()
900    */
901   public native boolean setAttributes() throws AFSSecurityException;
902
903   /////////////// private native methods ////////////////////
904
905   /**
906    * List the contents of this directory.
907    *
908    * @return  the directory handle
909    */
910   private native long listNative(ArrayList buffer) throws AFSSecurityException;
911   /**
912    * Close the currently open directory using a previously obtained handle.
913    *
914    * @return  true if the directory closes without error
915    */
916   private native boolean closeDir(long dp) throws AFSSecurityException;
917   /**
918    * Removes/deletes the current directory.
919    *
920    * @return  true if the directory is removed without error
921    */
922   private native boolean rmdir() throws AFSSecurityException;
923   /**
924    * Removes/deletes the current file.
925    *
926    * @return  true if the file is removed without error
927    */
928   private native boolean rmfile() throws AFSSecurityException;
929   /**
930    * Returns the permission/ACL mask for this directory
931    *
932    * @return  permission/ACL mask
933    */
934   private native int getRights() throws AFSSecurityException;
935   /*-------------------------------------------------------------------------*/
936 }
937
938
939
940
941
942