View Javadoc
1   /*
2    * This file is part of Waarp Project (named also Waarp or GG).
3    *
4    *  Copyright (c) 2019, Waarp SAS, and individual contributors by the @author
5    *  tags. See the COPYRIGHT.txt in the distribution for a full listing of
6    * individual contributors.
7    *
8    *  All Waarp Project is free software: you can redistribute it and/or
9    * modify it under the terms of the GNU General Public License as published by
10   * the Free Software Foundation, either version 3 of the License, or (at your
11   * option) any later version.
12   *
13   * Waarp is distributed in the hope that it will be useful, but WITHOUT ANY
14   * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
15   * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
16   *
17   *  You should have received a copy of the GNU General Public License along with
18   * Waarp . If not, see <http://www.gnu.org/licenses/>.
19   */
20  package org.waarp.common.file.filesystembased;
21  
22  import org.waarp.common.command.exception.CommandAbstractException;
23  import org.waarp.common.command.exception.Reply550Exception;
24  import org.waarp.common.command.exception.Reply553Exception;
25  import org.waarp.common.digest.FilesystemBasedDigest;
26  import org.waarp.common.digest.FilesystemBasedDigest.DigestAlgo;
27  import org.waarp.common.file.AbstractDir;
28  import org.waarp.common.file.FileInterface;
29  import org.waarp.common.file.FileUtils;
30  import org.waarp.common.file.OptsMLSxInterface;
31  import org.waarp.common.file.SessionInterface;
32  import org.waarp.common.file.filesystembased.specific.FilesystemBasedCommonsIo;
33  import org.waarp.common.file.filesystembased.specific.FilesystemBasedDirJdk5;
34  import org.waarp.common.file.filesystembased.specific.FilesystemBasedDirJdk6;
35  import org.waarp.common.file.filesystembased.specific.FilesystemBasedDirJdkAbstract;
36  import org.waarp.common.logging.WaarpLogger;
37  import org.waarp.common.logging.WaarpLoggerFactory;
38  import org.waarp.common.utility.DetectionUtils;
39  import org.waarp.common.utility.ParametersChecker;
40  
41  import java.io.File;
42  import java.io.FileFilter;
43  import java.io.FileInputStream;
44  import java.io.FileNotFoundException;
45  import java.io.IOException;
46  import java.text.DateFormat;
47  import java.text.SimpleDateFormat;
48  import java.util.ArrayList;
49  import java.util.Arrays;
50  import java.util.Calendar;
51  import java.util.Date;
52  import java.util.List;
53  import java.util.Locale;
54  import java.util.zip.CRC32;
55  import java.util.zip.CheckedInputStream;
56  
57  import static org.waarp.common.file.FileUtils.*;
58  
59  /**
60   * Directory implementation for Filesystem Based
61   */
62  public abstract class FilesystemBasedDirImpl extends AbstractDir {
63    private static final String ERROR_WHILE_READING_FILE =
64        "Error while reading file: ";
65  
66    private static final String DIRECTORY_NOT_FOUND = "Directory not found: ";
67  
68    /**
69     * Internal Logger
70     */
71    private static final WaarpLogger logger =
72        WaarpLoggerFactory.getLogger(FilesystemBasedDirImpl.class);
73  
74    /**
75     * Class that handles specifity of one Jdk or another
76     */
77    protected static FilesystemBasedDirJdkAbstract filesystemBasedFtpDirJdk;
78  
79    /*
80     * Initialize the filesystem
81     */
82    static {
83      initJdkDependent();
84    }
85  
86    /**
87     * Init according to internals of JDK
88     */
89    private static void initJdkDependent() {
90      if (DetectionUtils.javaVersion() >= 6) {
91        filesystemBasedFtpDirJdk = new FilesystemBasedDirJdk6();
92      } else {
93        filesystemBasedFtpDirJdk = new FilesystemBasedDirJdk5();
94      }
95    }
96  
97    /**
98     * Init the dependant object according to internals of JDK
99     *
100    * @param filesystemBasedFtpDirJdkChoice
101    *
102    * @deprecated replaced by initJdkDependent()
103    */
104   @Deprecated
105   public static void initJdkDependent(
106       final FilesystemBasedDirJdkAbstract filesystemBasedFtpDirJdkChoice) {
107     filesystemBasedFtpDirJdk = filesystemBasedFtpDirJdkChoice;
108   }
109 
110   /**
111    * @param session
112    * @param optsMLSx
113    */
114   protected FilesystemBasedDirImpl(final SessionInterface session,
115                                    final OptsMLSxInterface optsMLSx) {
116     this.session = session;
117     this.optsMLSx = optsMLSx;
118     this.optsMLSx.setOptsModify((byte) 1);
119     this.optsMLSx.setOptsPerm((byte) 1);
120     this.optsMLSx.setOptsSize((byte) 1);
121     this.optsMLSx.setOptsType((byte) 1);
122   }
123 
124   /**
125    * Finds all files matching a wildcard expression (based on '?', '~' or
126    * '*').
127    *
128    * @param pathWithWildcard The wildcard expression with a business
129    *     path.
130    *
131    * @return List of String as relative paths matching the wildcard
132    *     expression.
133    *     Those files are tested as valid
134    *     from business point of view. If Wildcard support is not active,
135    *     if the
136    *     path contains any wildcards,
137    *     it will throw an error.
138    *
139    * @throws CommandAbstractException
140    */
141   @Override
142   protected final List<String> wildcardFiles(final String pathWithWildcard)
143       throws CommandAbstractException {
144     final List<String> resultPaths = new ArrayList<String>();
145     // First check if pathWithWildcard contains wildcards
146     if (!(pathWithWildcard.contains("*") || pathWithWildcard.contains("?") ||
147           pathWithWildcard.contains("~"))) {
148       // No so simply return the list containing this path after
149       // validating it
150       if (getSession().getAuth().isBusinessPathValid(pathWithWildcard)) {
151         resultPaths.add(pathWithWildcard);
152       }
153       return resultPaths;
154     }
155     // Do we support Wildcard path
156     if (!FilesystemBasedDirJdkAbstract.ueApacheCommonsIo) {
157       throw new Reply553Exception("Wildcards in pathname is not allowed");
158     }
159     File wildcardFile;
160     final File rootFile;
161     if (!ISUNIX && isAbsolute(pathWithWildcard)) {
162       wildcardFile = new File(pathWithWildcard);
163       rootFile = getCorrespondingRoot(wildcardFile);
164     } else {
165       if (isAbsolute(pathWithWildcard)) {
166         rootFile = new File("/");
167       } else {
168         rootFile = new File(getSession().getAuth().getBaseDirectory());
169       }
170       wildcardFile = new File(rootFile, pathWithWildcard);
171     }
172     // Split wildcard path into subdirectories.
173     final List<String> subdirs = new ArrayList<String>();
174     while (wildcardFile != null) {
175       final File parent = wildcardFile.getParentFile();
176       if (parent == null) {
177         subdirs.add(0, wildcardFile.getPath());
178         break;
179       }
180       subdirs.add(0, wildcardFile.getName());
181       if (parent.equals(rootFile)) {
182         // End of wildcard path
183         subdirs.add(0, parent.getPath());
184         break;
185       }
186       wildcardFile = parent;
187     }
188     List<File> basedPaths = new ArrayList<File>();
189     // First set root
190     basedPaths.add(new File(subdirs.get(0)));
191     int i = 1;
192     // For each wilcard subdirectory
193     while (i < subdirs.size()) {
194       // Set current filter
195       final FileFilter fileFilter =
196           FilesystemBasedCommonsIo.getWildcardFileFilter(subdirs.get(i));
197       final List<File> newBasedPaths = new ArrayList<File>();
198       // Look for matches in all the current search paths
199       for (final File dir : basedPaths) {
200         if (dir.isDirectory()) {
201           newBasedPaths.addAll(Arrays.asList(dir.listFiles(fileFilter)));
202         }
203       }
204       // base Search Path changes now
205       basedPaths = newBasedPaths;
206       i++;
207     }
208     // Valid each file first
209     for (final File file : basedPaths) {
210       final String relativePath = getSession().getAuth().getRelativePath(
211           normalizePath(file.getAbsolutePath()));
212       final String newpath = validatePath(relativePath);
213       resultPaths.add(newpath);
214     }
215     return resultPaths;
216   }
217 
218   /**
219    * Get the FileInterface from this path, checking first its validity
220    *
221    * @param path
222    *
223    * @return the FileInterface
224    *
225    * @throws CommandAbstractException
226    */
227   protected final File getFileFromPath(final String path)
228       throws CommandAbstractException {
229     final String newdir = validatePath(path);
230     if (isAbsolute(newdir)) {
231       return new File(newdir);
232     }
233     final String truedir =
234         ((FilesystemBasedAuthImpl) getSession().getAuth()).getAbsolutePath(
235             newdir);
236     return new File(truedir);
237   }
238 
239   /**
240    * Get the true file from the path
241    *
242    * @param path
243    *
244    * @return the true File from the path
245    *
246    * @throws CommandAbstractException
247    */
248   protected final File getTrueFile(final String path)
249       throws CommandAbstractException {
250     checkIdentify();
251     final String newpath = consolidatePath(path);
252     final List<String> paths = wildcardFiles(normalizePath(newpath));
253     if (paths.size() != 1) {
254       throw new Reply550Exception(
255           "File not found: " + paths.size() + " founds");
256     }
257     String extDir = paths.get(0);
258     extDir = validatePath(extDir);
259     final File file = getFileFromPath(extDir);
260     if (!file.isFile()) {
261       throw new Reply550Exception("Path is not a file: " + path);
262     }
263     return file;
264   }
265 
266   /**
267    * Get the relative path (without mount point)
268    *
269    * @param file
270    *
271    * @return the relative path
272    */
273   protected final String getRelativePath(final File file) {
274     return getSession().getAuth()
275                        .getRelativePath(normalizePath(file.getAbsolutePath()));
276   }
277 
278   @Override
279   public final boolean changeDirectory(final String path)
280       throws CommandAbstractException {
281     checkIdentify();
282     final String newpath = consolidatePath(path);
283     final List<String> paths = wildcardFiles(newpath);
284     if (paths.size() != 1) {
285       logger.warn("CD error: {}", newpath);
286       throw new Reply550Exception(
287           DIRECTORY_NOT_FOUND + paths.size() + " founds");
288     }
289     String extDir = paths.get(0);
290     extDir = validatePath(extDir);
291     if (isDirectory(extDir)) {
292       currentDir = extDir;
293       return true;
294     }
295     throw new Reply550Exception(DIRECTORY_NOT_FOUND + extDir);
296   }
297 
298   @Override
299   public final boolean changeDirectoryNotChecked(final String path)
300       throws CommandAbstractException {
301     checkIdentify();
302     final String newpath = consolidatePath(path);
303     final List<String> paths = wildcardFiles(newpath);
304     if (paths.size() != 1) {
305       logger.warn("CD error: {}", newpath);
306       throw new Reply550Exception(
307           DIRECTORY_NOT_FOUND + paths.size() + " founds");
308     }
309     String extDir = paths.get(0);
310     extDir = validatePath(extDir);
311     currentDir = extDir;
312     return true;
313   }
314 
315   @Override
316   public final String mkdir(final String directory)
317       throws CommandAbstractException {
318     checkIdentify();
319     final String newdirectory = consolidatePath(directory);
320     final File dir = new File(newdirectory);
321     final String parent = dir.getParentFile().getPath();
322     final List<String> paths = wildcardFiles(normalizePath(parent));
323     if (paths.size() != 1) {
324       throw new Reply550Exception(
325           "Base Directory not found: " + paths.size() + " founds");
326     }
327     String newDir = paths.get(0) + SEPARATOR + dir.getName();
328     newDir = validatePath(newDir);
329     final File newdir = getFileFromPath(newDir);
330     if (newdir.mkdir()) {
331       return newDir;
332     }
333     throw new Reply550Exception("Cannot create directory " + newDir);
334   }
335 
336   @Override
337   public final String rmdir(final String directory)
338       throws CommandAbstractException {
339     checkIdentify();
340     final String newdirectory = consolidatePath(directory);
341     final List<String> paths = wildcardFiles(normalizePath(newdirectory));
342     if (paths.size() != 1) {
343       throw new Reply550Exception(
344           DIRECTORY_NOT_FOUND + paths.size() + " founds");
345     }
346     String extDir = paths.get(0);
347     extDir = validatePath(extDir);
348     final File dir = getFileFromPath(extDir);
349     if (dir.delete()) {
350       return extDir;
351     }
352     throw new Reply550Exception("Cannot delete directory " + extDir);
353   }
354 
355   @Override
356   public final boolean isDirectory(final String path)
357       throws CommandAbstractException {
358     checkIdentify();
359     final File dir = getFileFromPath(path);
360     return dir.isDirectory();
361   }
362 
363   @Override
364   public final boolean isFile(final String path)
365       throws CommandAbstractException {
366     checkIdentify();
367     return getFileFromPath(path).isFile();
368   }
369 
370   @Override
371   public final String getModificationTime(final String path)
372       throws CommandAbstractException {
373     checkIdentify();
374     final File file = getFileFromPath(path);
375     if (file.exists()) {
376       return getModificationTime(file);
377     }
378     throw new Reply550Exception('"' + path + "\" does not exist");
379   }
380 
381   /**
382    * Return the Modification time for the File
383    *
384    * @param file
385    *
386    * @return the Modification time as a String YYYYMMDDHHMMSS.sss
387    */
388   protected final String getModificationTime(final File file) {
389     final long mstime = file.lastModified();
390     final Calendar calendar = Calendar.getInstance();
391     calendar.setTimeInMillis(mstime);
392     final int year = calendar.get(Calendar.YEAR);
393     final int month = calendar.get(Calendar.MONTH) + 1;
394     final int day = calendar.get(Calendar.DAY_OF_MONTH);
395     final int hour = calendar.get(Calendar.HOUR_OF_DAY);
396     final int minute = calendar.get(Calendar.MINUTE);
397     final int second = calendar.get(Calendar.SECOND);
398     final int ms = calendar.get(Calendar.MILLISECOND);
399     final StringBuilder sb = new StringBuilder(18);
400     sb.append(year);
401     if (month < 10) {
402       sb.append(0);
403     }
404     sb.append(month);
405     if (day < 10) {
406       sb.append(0);
407     }
408     sb.append(day);
409     if (hour < 10) {
410       sb.append(0);
411     }
412     sb.append(hour);
413     if (minute < 10) {
414       sb.append(0);
415     }
416     sb.append(minute);
417     if (second < 10) {
418       sb.append(0);
419     }
420     sb.append(second).append('.');
421     if (ms < 10) {
422       sb.append(0);
423     }
424     if (ms < 100) {
425       sb.append(0);
426     }
427     sb.append(ms);
428     return sb.toString();
429   }
430 
431   @Override
432   public final List<String> list(final String path)
433       throws CommandAbstractException {
434     checkIdentify();
435     // First get all base directories
436     String newpath = path;
437     if (ParametersChecker.isEmpty(newpath)) {
438       newpath = currentDir;
439     }
440     if (newpath.startsWith("-a") || newpath.startsWith("-A")) {
441       final String[] args = newpath.split(" ");
442       if (args.length > 1) {
443         newpath = args[1];
444       } else {
445         newpath = currentDir;
446       }
447     }
448     newpath = consolidatePath(newpath);
449     logger.debug("debug: {}", newpath);
450     final List<String> paths = wildcardFiles(newpath);
451     if (paths.isEmpty()) {
452       throw new Reply550Exception("No files found");
453     }
454     // Now if they are directories, list inside them
455     final List<String> newPaths = new ArrayList<String>();
456     for (final String file : paths) {
457       final File dir = getFileFromPath(file);
458       if (dir.exists()) {
459         if (dir.isDirectory()) {
460           final String[] files = dir.list();
461           for (final String finalFile : files) {
462             final String relativePath =
463                 getSession().getAuth().getRelativePath(finalFile);
464             newPaths.add(relativePath);
465           }
466         } else {
467           newPaths.add(file);
468         }
469       }
470     }
471     return newPaths;
472   }
473 
474   @Override
475   public final List<String> listFull(final String path, final boolean lsFormat)
476       throws CommandAbstractException {
477     checkIdentify();
478     boolean listAllFiles = false;
479     String newpath = path;
480     if (ParametersChecker.isEmpty(newpath)) {
481       newpath = currentDir;
482     }
483     if (newpath.startsWith("-a") || newpath.startsWith("-A")) {
484       final String[] args = newpath.split(" ");
485       if (args.length > 1) {
486         newpath = args[1];
487       } else {
488         newpath = currentDir;
489       }
490       listAllFiles = true;
491     }
492     newpath = consolidatePath(newpath);
493     // First get all base directories
494     final List<String> paths = wildcardFiles(newpath);
495     if (paths.isEmpty()) {
496       throw new Reply550Exception("No files found");
497     }
498     // Now if they are directories, list inside them
499     final List<String> newPaths = new ArrayList<String>();
500     for (final String file : paths) {
501       final File dir = getFileFromPath(file);
502       if (dir.exists()) {
503         if (dir.isDirectory()) {
504           final File[] files = dir.listFiles();
505           for (final File finalFile : files) {
506             if (lsFormat) {
507               newPaths.add(lsInfo(finalFile));
508             } else {
509               newPaths.add(mlsxInfo(finalFile));
510             }
511           }
512         } else {
513           if (lsFormat) {
514             newPaths.add(lsInfo(dir));
515           } else {
516             newPaths.add(mlsxInfo(dir));
517           }
518         }
519       }
520     }
521     if (listAllFiles) {
522       final File dir = new File(getFileFromPath(newpath), SEPARATOR + "..");
523       if (lsFormat) {
524         newPaths.add(lsInfo(dir));
525       } else {
526         newPaths.add(mlsxInfo(dir));
527       }
528     }
529     return newPaths;
530   }
531 
532   @Override
533   public final String fileFull(final String path, final boolean lsFormat)
534       throws CommandAbstractException {
535     checkIdentify();
536     final String newpath = consolidatePath(path);
537     final List<String> paths = wildcardFiles(normalizePath(newpath));
538     if (paths.size() != 1) {
539       throw new Reply550Exception("No files found " + paths.size() + " founds");
540     }
541     final File file = getFileFromPath(paths.get(0));
542     if (file.exists()) {
543       if (lsFormat) {
544         return "Listing of \"" + paths.get(0) + "\"\n" + lsInfo(file) +
545                "\nEnd of listing";
546       }
547       return "Listing of \"" + paths.get(0) + "\"\n" + mlsxInfo(file) +
548              "\nEnd of listing";
549     }
550     return "No file with name \"" + path + '"';
551   }
552 
553   /**
554    * Decide if Full time or partial time as in 'ls' command
555    *
556    * @return True if Full Time, False is Default (as in 'ls' command)
557    */
558   protected final boolean isFullTime() {
559     return false;
560   }
561 
562   /**
563    * @param file
564    *
565    * @return the ls format information
566    */
567   protected final String lsInfo(final File file) {
568     // Unix FileInterface type,permissions,hard
569     // link(?),owner(?),group(?),size,date
570     // and filename
571     final StringBuilder builder =
572         new StringBuilder().append(file.isDirectory()? 'd' : '-')
573                            .append(file.canRead()? 'r' : '-')
574                            .append(file.canWrite()? 'w' : '-');
575     if (filesystemBasedFtpDirJdk != null) {
576       builder.append(filesystemBasedFtpDirJdk.canExecute(file)? 'x' : '-');
577     } else {
578       builder.append('-');
579     }
580     // Group and others not supported
581     builder.append("---").append("---").append(' ').append("1 ")// hard link ?
582            .append("anybody\t")// owner ?
583            .append("anygroup\t")// group ?
584            .append(file.length())// size
585            .append('\t');
586     final long lastmod = file.lastModified();
587     final String fmt;
588     // It seems Full Time is not recognized by some FTP client
589     final long currentTime = System.currentTimeMillis();
590     if (currentTime > lastmod + 6L * 30L * 24L * 60L * 60L * 1000L // Old.
591         || currentTime < lastmod - 60L * 60L * 1000L) { // In the
592       // future.
593       // The file is fairly old or in the future.
594       // POSIX says the cutoff is 6 months old.
595       // approximate this by 6*30 days.
596       // Allow a 1 hour slop factor for what is considered "the future",
597       // to allow for NFS server/client clock disagreement.
598       // Show the year instead of the time of day.
599       fmt = "MMM dd  yyyy";
600     } else {
601       fmt = "MMM dd HH:mm";
602     }
603     final SimpleDateFormat dateFormat =
604         (SimpleDateFormat) DateFormat.getDateTimeInstance(DateFormat.LONG,
605                                                           DateFormat.LONG,
606                                                           Locale.ENGLISH);
607     dateFormat.applyPattern(fmt);
608     builder.append(dateFormat.format(new Date(lastmod)))// date
609            .append('\t').append(file.getName());
610     return builder.toString();
611   }
612 
613   /**
614    * @param file
615    *
616    * @return the MLSx information: ' Fact=facts;...; filename'
617    */
618   protected final String mlsxInfo(final File file) {
619     // don't have create, unique, lang, media-type, charset
620     final StringBuilder builder = new StringBuilder(" ");
621     if (getOptsMLSx().getOptsSize() == 1) {
622       builder.append("Size=").append(file.length()).append(';');
623     }
624     if (getOptsMLSx().getOptsModify() == 1) {
625       builder.append("Modify=").append(getModificationTime(file)).append(';');
626     }
627     if (getOptsMLSx().getOptsType() == 1) {
628       builder.append("Type=");
629       try {
630         if (getFileFromPath(currentDir).equals(file)) {
631           builder.append("cdir");
632         } else {
633           if (file.isDirectory()) {
634             builder.append("dir");
635           } else {
636             builder.append("file");
637           }
638         }
639       } catch (final CommandAbstractException e) {
640         if (file.isDirectory()) {
641           builder.append("dir");
642         } else {
643           builder.append("file");
644         }
645       }
646       builder.append(';');
647     }
648     if (getOptsMLSx().getOptsPerm() == 1) {
649       builder.append("Perm=");
650       if (file.isFile()) {
651         if (file.canWrite()) {
652           builder.append('a').append('d').append('f').append('w');
653         }
654         if (file.canRead()) {
655           builder.append('r');
656         }
657       } else {
658         // Directory
659         if (file.canWrite()) {
660           builder.append('c');
661           try {
662             if (validatePath(file) != null) {
663               builder.append('d').append('m').append('p');
664             }
665           } catch (final CommandAbstractException ignored) {
666             // nothing
667           }
668         }
669         if (file.canRead()) {
670           builder.append('l').append('e');
671         }
672       }
673       builder.append(';');
674     }
675 
676     builder.append(' ').append(file.getName());
677     return builder.toString();
678   }
679 
680   @Override
681   public final long getFreeSpace() throws CommandAbstractException {
682     checkIdentify();
683     final File directory = getFileFromPath(currentDir);
684     if (filesystemBasedFtpDirJdk != null) {
685       return filesystemBasedFtpDirJdk.getFreeSpace(directory);
686     } else {
687       return Integer.MAX_VALUE;
688     }
689   }
690 
691   @Override
692   public FileInterface setUniqueFile() throws CommandAbstractException {
693     checkIdentify();
694     final File file;
695     try {
696       file = File.createTempFile(getSession().getAuth().getUser(),
697                                  session.getUniqueExtension(),
698                                  getFileFromPath(currentDir));
699     } catch (final IOException e) {
700       throw new Reply550Exception("Cannot create unique file");
701     }
702     final String currentFile = getRelativePath(file);
703     return newFile(normalizePath(currentFile), false);
704   }
705 
706   @Override
707   public final boolean canRead() throws CommandAbstractException {
708     checkIdentify();
709     return getFileFromPath(currentDir).canRead();
710   }
711 
712   @Override
713   public final boolean canWrite() throws CommandAbstractException {
714     checkIdentify();
715     final File file = getFileFromPath(currentDir);
716     return file.canWrite();
717   }
718 
719   @Override
720   public final boolean exists() throws CommandAbstractException {
721     checkIdentify();
722     return getFileFromPath(currentDir).exists();
723   }
724 
725   @Override
726   public final long getCRC(final String path) throws CommandAbstractException {
727     final File file = getTrueFile(path);
728     FileInputStream fis = null;
729     CheckedInputStream cis = null;
730     try {
731       try {
732         // Computer CRC32 checksum
733         fis = new FileInputStream(file);
734         cis = new CheckedInputStream(fis, new CRC32());
735       } catch (final FileNotFoundException e) {
736         throw new Reply550Exception("File not found: " + path);
737       }
738       final byte[] buf = new byte[ZERO_COPY_CHUNK_SIZE];
739       while (cis.read(buf) >= 0) {
740         // nothing
741       }
742       return cis.getChecksum().getValue();
743     } catch (final IOException e) {
744       throw new Reply550Exception(ERROR_WHILE_READING_FILE + path);
745     } finally {
746       FileUtils.close(cis);
747       FileUtils.close(fis);
748     }
749   }
750 
751   @Override
752   public final byte[] getMD5(final String path)
753       throws CommandAbstractException {
754     return getDigest(path, DigestAlgo.MD5.name());
755   }
756 
757   @Override
758   public final byte[] getSHA1(final String path)
759       throws CommandAbstractException {
760     return getDigest(path, DigestAlgo.SHA1.name());
761   }
762 
763   @Override
764   public final byte[] getDigest(final String path, final String algo)
765       throws CommandAbstractException {
766     final DigestAlgo digestAlgo;
767     try {
768       digestAlgo = DigestAlgo.getFromName(algo);
769     } catch (final IllegalArgumentException e) {
770       throw new Reply553Exception("Algorithme unknown: " + algo);
771     }
772     final File file = getTrueFile(path);
773     try {
774       return FilesystemBasedDigest.getHash(file,
775                                            FilesystemBasedFileParameterImpl.useNio,
776                                            digestAlgo);
777     } catch (final IOException e1) {
778       throw new Reply550Exception(ERROR_WHILE_READING_FILE + path);
779     }
780   }
781 
782 }