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.openr66.context.filesystem;
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.file.filesystembased.FilesystemBasedDirImpl;
26  import org.waarp.common.file.filesystembased.FilesystemBasedOptsMLSxImpl;
27  import org.waarp.common.file.filesystembased.specific.FilesystemBasedCommonsIo;
28  import org.waarp.common.file.filesystembased.specific.FilesystemBasedDirJdkAbstract;
29  import org.waarp.openr66.context.R66Session;
30  import org.waarp.openr66.context.authentication.R66Auth;
31  import org.waarp.openr66.protocol.configuration.Configuration;
32  
33  import java.io.File;
34  import java.io.FileFilter;
35  import java.io.IOException;
36  import java.util.ArrayList;
37  import java.util.Collections;
38  import java.util.List;
39  
40  /**
41   * Directory representation
42   */
43  public class R66Dir extends FilesystemBasedDirImpl {
44  
45    /**
46     * @param session
47     */
48    public R66Dir(final R66Session session) {
49      super(session, new FilesystemBasedOptsMLSxImpl());
50    }
51  
52    @Override
53    public final R66File newFile(final String path, final boolean append)
54        throws CommandAbstractException {
55      return new R66File((R66Session) getSession(), this, path, append);
56    }
57  
58    /**
59     * Same as setUnique() except that File will be prefixed by id and postfixed
60     * by filename
61     *
62     * @param prefix
63     * @param filename
64     *
65     * @return the R66File with a unique filename and a temporary extension
66     *
67     * @throws CommandAbstractException
68     */
69    public synchronized R66File setUniqueFile(final long prefix,
70                                              final String filename)
71        throws CommandAbstractException {
72      checkIdentify();
73      final File file;
74      String prename = prefix + "_";
75      if (prename.length() < 3) {
76        prename = "xx_" + prename;
77      }
78      String basename = R66File.getBasename(filename);
79      if (basename.length() >
80          Configuration.configuration.getMaxfilenamelength() - 55) {
81        basename = basename.substring(basename.length() -
82                                      Configuration.configuration.getMaxfilenamelength() +
83                                      55);
84      }
85      try {
86        file =
87            File.createTempFile(prename, '_' + basename + Configuration.EXT_R66,
88                                getFileFromPath(currentDir));
89      } catch (final IOException e) {
90        throw new Reply550Exception("Cannot create unique file from " + basename);
91      }
92      final String currentFile = getRelativePath(file);
93      return newFile(normalizePath(currentFile), false);
94    }
95  
96    /**
97     * @param file
98     *
99     * @return the final unique basename without the temporary extension
100    */
101   public static String getFinalUniqueFilename(final R66File file) {
102     String finalpath = file.getBasename();
103     final int pos = finalpath.lastIndexOf(Configuration.EXT_R66);
104     if (pos > 0) {
105       finalpath = finalpath.substring(0, pos);
106     }
107     return finalpath;
108   }
109 
110   /**
111    * Finds all files matching a wildcard expression (based on '?', '~' or '*')
112    * but without checking
113    * BusinessPath, thus returning absolute path.
114    *
115    * @param pathWithWildcard The wildcard expression with a business
116    *     path.
117    *
118    * @return List of String as relative paths matching the wildcard
119    *     expression.
120    *     Those files are tested as valid
121    *     from business point of view. If Wildcard support is not active,
122    *     if the
123    *     path contains any wildcards,
124    *     it will throw an error.
125    *
126    * @throws CommandAbstractException
127    */
128   protected final List<String> wildcardFilesNoCheck(
129       final String pathWithWildcard) throws CommandAbstractException {
130     final List<String> resultPaths = new ArrayList<String>();
131     // First check if pathWithWildcard contains wildcards
132     if (!(pathWithWildcard.contains("*") || pathWithWildcard.contains("?") ||
133           pathWithWildcard.contains("~"))) {
134       // No so simply return the list containing this path
135       resultPaths.add(pathWithWildcard);
136       return resultPaths;
137     }
138     // Do we support Wildcard path
139     if (!FilesystemBasedDirJdkAbstract.ueApacheCommonsIo) {
140       throw new Reply553Exception("Wildcards in pathname is not allowed");
141     }
142     File wildcardFile = new File(pathWithWildcard);
143     final File rootFile;
144     if (ISUNIX) {
145       rootFile = new File("/");
146     } else {
147       rootFile = getCorrespondingRoot(wildcardFile);
148     }
149     // Split wildcard path into subdirectories.
150     final List<String> subdirs = new ArrayList<String>();
151     while (wildcardFile != null) {
152       final File parent = wildcardFile.getParentFile();
153       if (parent == null) {
154         subdirs.add(0, wildcardFile.getPath());
155         break;
156       }
157       subdirs.add(0, wildcardFile.getName());
158       if (parent.equals(rootFile)) {
159         // End of wildcard path
160         subdirs.add(0, parent.getPath());
161         break;
162       }
163       wildcardFile = parent;
164     }
165     List<File> basedPaths = new ArrayList<File>();
166     // First set root
167     basedPaths.add(new File(subdirs.get(0)));
168     int i = 1;
169     // For each wilcard subdirectory
170     while (i < subdirs.size()) {
171       // Set current filter
172       final FileFilter fileFilter =
173           FilesystemBasedCommonsIo.getWildcardFileFilter(subdirs.get(i));
174       final List<File> newBasedPaths = new ArrayList<File>();
175       // Look for matches in all the current search paths
176       for (final File dir : basedPaths) {
177         if (dir.isDirectory()) {
178           Collections.addAll(newBasedPaths, dir.listFiles(fileFilter));
179         }
180       }
181       // base Search Path changes now
182       basedPaths = newBasedPaths;
183       i++;
184     }
185     // Valid each file first
186     for (final File file : basedPaths) {
187       resultPaths.add(file.getAbsolutePath());
188     }
189     return resultPaths;
190   }
191 
192   /**
193    * Create a new file according to the path without checking BusinessPath, so
194    * as external File.
195    *
196    * @param path
197    *
198    * @return the File created
199    *
200    * @throws CommandAbstractException
201    */
202   public final R66File setFileNoCheck(final String path)
203       throws CommandAbstractException {
204     checkIdentify();
205     final String newpath = consolidatePath(path);
206     final List<String> paths = wildcardFilesNoCheck(newpath);
207     if (paths.size() != 1) {
208       throw new Reply550Exception(
209           "File not found from: " + newpath + " and " + paths.size() +
210           " founds");
211     }
212     final String extDir = paths.get(0);
213     return new R66File((R66Session) getSession(), this, extDir);
214   }
215 
216   /**
217    * This method returns the Full path for the current directory
218    *
219    * @return the full path associated with the current Dir
220    */
221   public final String getFullPath() {
222     if (session.getAuth() == null) {
223       return currentDir;
224     }
225     if (isAbsolute(currentDir)) {
226       return currentDir;
227     }
228     return ((R66Auth) session.getAuth()).getAbsolutePath(currentDir);
229   }
230 
231   @Override
232   public String toString() {
233     return "Dir: " + currentDir;
234   }
235 }