File Source: FileManagerImpl.java

         /* 
    P/P   *  Method: org.apache.roller.weblogger.business.FileManagerImpl$WeblogResourceFile__static_init
          */
     1  /*
     2   * Licensed to the Apache Software Foundation (ASF) under one or more
     3   *  contributor license agreements.  The ASF licenses this file to You
     4   * under the Apache License, Version 2.0 (the "License"); you may not
     5   * use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   *     http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.  For additional information regarding
    15   * copyright in this work, please see the NOTICE file in the top level
    16   * directory of this distribution.
    17   */
    18  
    19  package org.apache.roller.weblogger.business;
    20  
    21  import java.io.File;
    22  import java.io.FileFilter;
    23  import java.io.FileInputStream;
    24  import java.io.FileOutputStream;
    25  import java.io.IOException;
    26  import java.io.InputStream;
    27  import java.io.OutputStream;
    28  import java.math.BigDecimal;
    29  import org.apache.commons.lang.StringUtils;
    30  import org.apache.commons.logging.Log;
    31  import org.apache.commons.logging.LogFactory;
    32  import org.apache.roller.weblogger.config.WebloggerConfig;
    33  import org.apache.roller.weblogger.config.WebloggerRuntimeConfig;
    34  import org.apache.roller.weblogger.pojos.ThemeResource;
    35  import org.apache.roller.weblogger.pojos.Weblog;
    36  import org.apache.roller.weblogger.util.RollerMessages;
    37  
    38  
    39  /**
    40   * Manages files uploaded to Roller weblogs.  
    41   * 
    42   * This base implementation writes resources to a filesystem.
    43   */
    44  public class FileManagerImpl implements FileManager {
    45      
             /* 
    P/P       *  Method: org.apache.roller.weblogger.business.FileManagerImpl__static_init
              * 
              *  Postconditions:
              *    init'ed(log)
              */
    46      private static Log log = LogFactory.getLog(FileManagerImpl.class);
    47      
    48      private String upload_dir = null;
    49      
    50      
    51      /**
    52       * Create file manager.
    53       */
             /* 
    P/P       *  Method: void org.apache.roller.weblogger.business.FileManagerImpl()
              * 
              *  Preconditions:
              *    org/apache/roller/weblogger/config/WebloggerConfig.config != null
              *    org/apache/roller/weblogger/config/WebloggerConfig.log != null
              * 
              *  Presumptions:
              *    init'ed(java.io.File.separator)
              *    init'ed(java.io.File.separatorChar)
              * 
              *  Postconditions:
              *    this.upload_dir != null
              * 
              *  Test Vectors:
              *    java.lang.String:endsWith(...)@62: {1}, {0}
              *    java.lang.String:length(...)@59: {1..232-1}, {0}
              */
    54      public FileManagerImpl() {
    55          String uploaddir = WebloggerConfig.getProperty("uploads.dir");
    56          
    57          // Note: System property expansion is now handled by WebloggerConfig.
    58          
    59          if(uploaddir == null || uploaddir.trim().length() < 1)
    60              uploaddir = System.getProperty("user.home") + File.separator+"roller_data"+File.separator+"uploads";
    61          
    62          if( ! uploaddir.endsWith(File.separator))
    63              uploaddir += File.separator;
    64          
    65          this.upload_dir = uploaddir.replace('/',File.separatorChar);
    66      }
    67      
    68      
    69      /**
    70       * @see org.apache.roller.weblogger.model.FileManager#getFile(weblog, java.lang.String)
    71       */
    72      public ThemeResource getFile(Weblog weblog, String path) 
    73              throws FileNotFoundException, FilePathException {
    74          
    75          // get a reference to the file, checks that file exists & is readable
                 /* 
    P/P           *  Method: ThemeResource getFile(Weblog, String)
                  * 
                  *  Preconditions:
                  *    init'ed(this.upload_dir)
                  *    weblog != null
                  * 
                  *  Presumptions:
                  *    java.io.File:isDirectory(...)@79 == 0
                  * 
                  *  Postconditions:
                  *    return_value == &new FileManagerImpl$WeblogResourceFile(getFile#3)
                  *    new File(getRealFile#6) num objects == 1
                  *    new FileManagerImpl$WeblogResourceFile(getFile#3) num objects == 1
                  *    new FileManagerImpl$WeblogResourceFile(getFile#3).relativePath == path
                  *    init'ed(new FileManagerImpl$WeblogResourceFile(getFile#3).relativePath)
                  *    new FileManagerImpl$WeblogResourceFile(getFile#3).resourceFile == &new File(getRealFile#6)
                  *    new FileManagerImpl$WeblogResourceFile(getFile#3).weblog == weblog
                  *    new FileManagerImpl$WeblogResourceFile(getFile#3).weblog != null
                  */
    76          File resourceFile = this.getRealFile(weblog, path);
    77          
    78          // make sure file is not a directory
    79          if(resourceFile.isDirectory()) {
    80              throw new FilePathException("Invalid path ["+path+"], "+
    81                      "path is a directory.");
    82          }
    83          
    84          // everything looks good, return resource
    85          return new WeblogResourceFile(weblog, path, resourceFile);
    86      }
    87      
    88      
    89      /**
    90       * @see org.apache.roller.weblogger.model.FileManager#getFiles(weblog, java.lang.String)
    91       */
    92      public ThemeResource[] getFiles(Weblog weblog, String path) 
    93              throws FileNotFoundException, FilePathException {
    94          
    95          // get a reference to the dir, checks that dir exists & is readable
                 /* 
    P/P           *  Method: ThemeResource[] getFiles(Weblog, String)
                  * 
                  *  Preconditions:
                  *    init'ed(this.upload_dir)
                  *    weblog != null
                  * 
                  *  Presumptions:
                  *    java.io.File:isDirectory(...)@99 == 1
                  * 
                  *  Postconditions:
                  *    init'ed(return_value)
                  */
    96          File dirFile = this.getRealFile(weblog, path);
    97          
    98          // make sure path is a directory
    99          if(!dirFile.isDirectory()) {
   100              throw new FilePathException("Invalid path ["+path+"], "+
   101                      "path is not a directory.");
   102          }
   103          
   104          // everything looks good, list contents
   105          ThemeResource dir = new WeblogResourceFile(weblog, path, dirFile);
   106          
   107          return dir.getChildren();
   108      }
   109      
   110      
   111      /**
   112       * @see org.apache.roller.weblogger.model.FileManager#getDirectories(weblog)
   113       */
   114      public ThemeResource[] getDirectories(Weblog weblog)
   115              throws FileNotFoundException, FilePathException {
   116          
   117          // get a reference to the root dir, checks that dir exists & is readable
                 /* 
    P/P           *  Method: ThemeResource[] getDirectories(Weblog)
                  * 
                  *  Preconditions:
                  *    init'ed(this.upload_dir)
                  *    weblog != null
                  * 
                  *  Presumptions:
                  *    dirFiles.length@121 <= 232-1
                  *    java.io.File:listFiles(...)@121 != null
                  * 
                  *  Postconditions:
                  *    return_value == &new ThemeResource[](getDirectories#2)
                  *    (soft) new FileManagerImpl$WeblogResourceFile(getDirectories#3) num objects <= 232-1
                  *    init'ed(new FileManagerImpl$WeblogResourceFile(getDirectories#3).relativePath)
                  *    new FileManagerImpl$WeblogResourceFile(getDirectories#3).resourceFile == null
                  *    new FileManagerImpl$WeblogResourceFile(getDirectories#3).weblog == weblog
                  *    new FileManagerImpl$WeblogResourceFile(getDirectories#3).weblog != null
                  *    new ThemeResource[](getDirectories#2) num objects == 1
                  *    (soft) return_value.length <= 232-1
                  *    possibly_updated(return_value[...])
                  *    (soft) new FileManagerImpl$WeblogResourceFile(getDirectories#3) num objects == dirFiles.length@121
                  */
   118          File dirFile = this.getRealFile(weblog, null);
   119          
   120          // we only want a list of directories
                 /* 
    P/P           *  Method: void org.apache.roller.weblogger.business.FileManagerImpl$1(FileManagerImpl)
                  */
   121          File[] dirFiles = dirFile.listFiles(new FileFilter() {
   122              public boolean accept(File f) {
                         /* 
    P/P                   *  Method: bool accept(File)
                          * 
                          *  Postconditions:
                          *    init'ed(return_value)
                          */
   123                  return (f != null) ? f.isDirectory() : false;
   124              }
   125          });
   126          
   127          // convert 'em to ThemeResource objects
   128          ThemeResource[] resources = new ThemeResource[dirFiles.length];
   129          for(int i=0; i < dirFiles.length; i++) {
+  130              String filePath = dirFiles[i].getName();
   131              resources[i] = new WeblogResourceFile(weblog, filePath, dirFiles[i]);
   132          }
   133              
   134          return resources;
   135      }
   136      
   137      
   138      /**
   139       * @see org.apache.roller.weblogger.model.FileManager#saveFile(weblog, java.lang.String, java.lang.String, long, java.io.InputStream)
   140       */
   141      public void saveFile(Weblog weblog, 
   142                           String path, 
   143                           String contentType, 
   144                           long size, 
   145                           InputStream is) 
   146              throws FileNotFoundException, FilePathException, FileIOException {
   147          
                 /* 
    P/P           *  Method: void saveFile(Weblog, String, String, long, InputStream)
                  * 
                  *  Preconditions:
                  *    is != null
                  *    log != null
                  *    path != null
                  *    init'ed(this.upload_dir)
                  *    weblog != null
                  *    (soft) org/apache/roller/weblogger/business/WebloggerFactory.webloggerProvider != null
                  *    (soft) org/apache/roller/weblogger/business/WebloggerFactory.webloggerProvider.webloggerInstance != null
                  *    (soft) org/apache/roller/weblogger/config/WebloggerRuntimeConfig.log != null
                  */
   148          saveFile(weblog, path, contentType, size, is, true);
   149      }
   150      
   151      /**
   152       * @see org.apache.roller.weblogger.model.FileManager#saveFile(weblog, java.lang.String, java.lang.String, long, java.io.InputStream)
   153       */
   154      public void saveFile(Weblog weblog, 
   155                           String path, 
   156                           String contentType, 
   157                           long size, 
   158                           InputStream is,
   159                           boolean checkCanSave)
   160              throws FileNotFoundException, FilePathException, FileIOException {
   161          
                 /* 
    P/P           *  Method: void saveFile(Weblog, String, String, long, InputStream, bool)
                  * 
                  *  Preconditions:
                  *    is != null
                  *    log != null
                  *    path != null
                  *    init'ed(this.upload_dir)
                  *    weblog != null
                  *    (soft) contentType init'ed
                  *    (soft) org/apache/roller/weblogger/business/WebloggerFactory.webloggerProvider != null
                  *    (soft) org/apache/roller/weblogger/business/WebloggerFactory.webloggerProvider.webloggerInstance != null
                  *    (soft) org/apache/roller/weblogger/config/WebloggerRuntimeConfig.log != null
                  * 
                  *  Presumptions:
                  *    (int) (java.math.BigDecimal:doubleValue(...)@366*1024000) in range
                  *    (int) (java.math.BigDecimal:doubleValue(...)@366*1024000) - size in range
                  *    size <= (int) (java.math.BigDecimal:doubleValue(...)@366*1024000) | canSave(...) == 0
                  *    (size + canSave(...)) - (int) (java.math.BigDecimal:doubleValue(...)@377*1024000) in range
                  *    true
                  *    ...
                  * 
                  *  Test Vectors:
                  *    checkCanSave: {0}, {1}
                  *    java.io.File:exists(...)@180: {1}, {0}
                  *    java.io.InputStream:read(...)@195: {-1}, {-231..-2, 0..232-1}
                  *    java.lang.String:indexOf(...)@177: {-1}, {-231..-2, 0..232-1}
                  *    java.lang.String:startsWith(...)@163: {0}, {1}
                  */
   162          String savePath = path;
   163          if(path.startsWith("/")) {
   164              savePath = path.substring(1);
   165          }
   166          
   167          // make sure we are allowed to save this file
   168          RollerMessages msgs = new RollerMessages();
   169          if (checkCanSave && !canSave(weblog, savePath, contentType, size, msgs)) {
+  170              throw new FileIOException(msgs.toString());
   171          }
   172          
   173          // make sure uploads area exists for this weblog
   174          File dirPath = this.getRealFile(weblog, null);
   175          
   176          // if we are saving into a subfolder, make sure it exists
   177          if(path.indexOf("/") != -1) {
   178              String subDir = path.substring(0, path.indexOf("/"));
   179              File subDirFile = new File(dirPath.getAbsolutePath() + File.separator + subDir);
   180              if(!subDirFile.exists()) {
   181                  // directory doesn't exist yet, create it
   182                  log.debug("Creating directory ["+subDir+"] automatically");
   183                  subDirFile.mkdir();
   184              }
   185          }
   186          
   187          // create File that we are about to save
   188          File saveFile = new File(dirPath.getAbsolutePath() + File.separator + savePath);
   189          
   190          byte[] buffer = new byte[8192];
   191          int bytesRead = 0;
   192          OutputStream bos = null;
   193          try {
   194              bos = new FileOutputStream(saveFile);
   195              while ((bytesRead = is.read(buffer, 0, 8192)) != -1) {
   196                  bos.write(buffer, 0, bytesRead);
   197              }
   198              
   199              log.debug("The file has been written to ["+saveFile.getAbsolutePath()+"]");
   200          } catch (Exception e) {
   201              throw new FileIOException("ERROR uploading file", e);
   202          } finally {
   203              try {
   204                  bos.flush();
   205                  bos.close();
   206              } catch (Exception ignored) {}
   207          }
   208          
   209          
   210      }
   211      
   212      
   213      /**
   214       * @see org.apache.roller.weblogger.model.FileManager#createDirectory(weblog, java.lang.String)
   215       */
   216      public void createDirectory(Weblog weblog, String path)
   217              throws FileNotFoundException, FilePathException, FileIOException {
   218          
   219          // get path to weblog's uploads area
                 /* 
    P/P           *  Method: void createDirectory(Weblog, String)
                  * 
                  *  Preconditions:
                  *    path != null
                  *    init'ed(this.upload_dir)
                  *    weblog != null
                  * 
                  *  Presumptions:
                  *    init'ed(java.io.File.separator)
                  *    java.io.File:getCanonicalPath(...)@243 != null
                  *    java.io.File:mkdir(...)@253 == 1
                  *    java.lang.String:indexOf(...)@227 == -1
                  *    java.lang.String:startsWith(...)@243 == 1
                  * 
                  *  Test Vectors:
                  *    java.io.File:canRead(...)@236: {0}, {1}
                  *    java.io.File:exists(...)@236: {0}, {1}
                  *    java.io.File:isDirectory(...)@236: {0}, {1}
                  *    java.lang.String:startsWith(...)@223: {0}, {1}
                  */
   220          File weblogDir = this.getRealFile(weblog, null);
   221          
   222          String savePath = path;
   223          if(path.startsWith("/")) {
   224              savePath = path.substring(1);
   225          }
   226          
+  227          if(savePath != null && savePath.indexOf('/') != -1) {
   228              throw new FilePathException("Invalid path ["+path+"], "+
   229                          "trying to use nested directories.");
   230          }
   231          
   232          // now construct path to new directory
   233          File dir = new File(weblogDir.getAbsolutePath() + File.separator + savePath);
   234          
   235          // check if it already exists
   236          if(dir.exists() && dir.isDirectory() && dir.canRead()) {
   237              // already exists, we don't need to do anything
   238              return;
   239          }
   240          
   241          try {
   242              // make sure someone isn't trying to sneek outside the uploads dir
   243              if(!dir.getCanonicalPath().startsWith(weblogDir.getCanonicalPath())) {
   244                  throw new FilePathException("Invalid path ["+path+"], "+
   245                          "trying to get outside uploads dir.");
   246              }
   247          } catch (IOException ex) {
   248              // rethrow as FilePathException
   249              throw new FilePathException(ex);
   250          }
   251          
   252          // create it
   253          if(!dir.mkdir()) {
   254              // failed for some reason
   255              throw new FileIOException("Failed to create directory ["+path+"], "+
   256                      "probably doesn't have needed parent directories.");
   257          }
   258      }
   259      
   260      
   261      /**
   262       * @see org.apache.roller.weblogger.model.FileManager#deleteFile(weblog, java.lang.String)
   263       */
   264      public void deleteFile(Weblog weblog, String path) 
   265              throws FileNotFoundException, FilePathException, FileIOException {
   266          
   267          // get path to delete file, checks that path exists and is readable
                 /* 
    P/P           *  Method: void deleteFile(Weblog, String)
                  * 
                  *  Preconditions:
                  *    init'ed(this.upload_dir)
                  *    weblog != null
                  * 
                  *  Presumptions:
                  *    java.io.File:delete(...)@270 == 1
                  */
   268          File delFile = this.getRealFile(weblog, path);
   269          
   270          if(!delFile.delete()) {
   271              throw new FileIOException("Delete failed for ["+path+"], "+
   272                      "possibly a non-empty directory?");
   273          }
   274      }
   275      
   276      
   277      /**
   278       * @inheritDoc
   279       */
   280      public void deleteAllFiles(Weblog weblog) throws FileIOException {
   281          
   282          try {
   283              // get path to root folder
                     /* 
    P/P               *  Method: void deleteAllFiles(Weblog)
                      * 
                      *  Preconditions:
                      *    (soft) init'ed(this.upload_dir)
                      *    (soft) weblog != null
                      */
   284              File delFile = this.getRealFile(weblog, "/");
   285              
   286              // delete folder and it's contents
   287              deleteAllFiles(delFile);
   288              
   289          } catch (FileNotFoundException ex) {
   290              // if it doesn't exist then we already have no files, so we're done
   291              return;
   292          } catch (FilePathException ex) {
   293              // should never happen when trying to get root folder
   294          }
   295      }
   296      
   297      
   298      // convenience method to delete a folder and all of it's contents.  called recursively
   299      private void deleteAllFiles(File dir) {
   300          
   301          // delete directory contents
                 /* 
    P/P           *  Method: void deleteAllFiles(File)
                  * 
                  *  Preconditions:
                  *    dir != null
                  * 
                  *  Presumptions:
                  *    dirFiles.length@302 <= 232-1
                  * 
                  *  Test Vectors:
                  *    dirFiles.length@302: {0}, {1..232-1}
                  *    java.io.File:isDirectory(...)@305: {0}, {1}
                  *    java.io.File:listFiles(...)@302: Addr_Set{null}, Inverse{null}
                  */
   302          File[] dirFiles = dir.listFiles();
   303          if(dirFiles != null && dirFiles.length > 0) {
   304              for( File file : dirFiles ) {
+  305                  if(file.isDirectory()) {
   306                      // recursive call
   307                      deleteAllFiles(file);
   308                  } else {
   309                      file.delete();
   310                  }
   311              }
   312          }
   313          
   314          // delete directory itself
   315          dir.delete();
   316      }
   317      
   318      
   319      /**
   320       * @see org.apache.roller.weblogger.model.FileManager#overQuota(weblog)
   321       */
   322      public boolean overQuota(Weblog weblog) {
   323          
                 /* 
    P/P           *  Method: bool overQuota(Weblog)
                  * 
                  *  Preconditions:
                  *    org/apache/roller/weblogger/config/WebloggerRuntimeConfig.log != null
                  *    init'ed(this.upload_dir)
                  *    weblog != null
                  *    (soft) org/apache/roller/weblogger/business/WebloggerFactory.webloggerProvider != null
                  *    (soft) org/apache/roller/weblogger/business/WebloggerFactory.webloggerProvider.webloggerInstance != null
                  * 
                  *  Presumptions:
                  *    (int) (java.math.BigDecimal:doubleValue(...)@329*1024000) in -263..264-1
                  * 
                  *  Postconditions:
                  *    init'ed(return_value)
                  */
   324          String maxDir = WebloggerRuntimeConfig.getProperty("uploads.dir.maxsize");
   325          String maxFile = WebloggerRuntimeConfig.getProperty("uploads.file.maxsize");
   326          BigDecimal maxDirSize = new BigDecimal(maxDir); // in megabytes
+  327          BigDecimal maxFileSize = new BigDecimal(maxFile); // in megabytes
   328          
   329          long maxDirBytes = (long)(1024000 * maxDirSize.doubleValue());
   330          
   331          try {
   332              File uploadsDir = this.getRealFile(weblog, null);
   333              long weblogDirSize = this.getDirSize(uploadsDir, true);
   334              
   335              return weblogDirSize > maxDirBytes;
   336          } catch (Exception ex) {
   337              // shouldn't ever happen, this means user's uploads dir is bad
   338              // rethrow as a runtime exception
   339              throw new RuntimeException(ex);
   340          }
   341      }
   342      
   343      
   344      public void release() {
             /* 
    P/P       *  Method: void release()
              */
   345      }
   346      
   347      
   348      /**
   349       * Determine if file can be saved given current WebloggerConfig settings.
   350       */
   351      private boolean canSave(Weblog weblog, 
   352                             String path, 
   353                             String contentType,
   354                             long size, 
   355                             RollerMessages messages) {
   356          
   357          // first check, is uploading enabled?
                 /* 
    P/P           *  Method: bool canSave(Weblog, String, String, long, RollerMessages)
                  * 
                  *  Preconditions:
                  *    org/apache/roller/weblogger/config/WebloggerRuntimeConfig.log != null
                  *    (soft) log != null
                  *    (soft) messages != null
                  *    (soft) org/apache/roller/weblogger/business/WebloggerFactory.webloggerProvider != null
                  *    (soft) org/apache/roller/weblogger/business/WebloggerFactory.webloggerProvider.webloggerInstance != null
                  *    (soft) path != null
                  *    (soft) init'ed(this.upload_dir)
                  *    (soft) weblog != null
                  * 
                  *  Presumptions:
                  *    (int) (java.math.BigDecimal:doubleValue(...)@366*1024000) in -231..232-1
                  *    (int) (java.math.BigDecimal:doubleValue(...)@377*1024000) in -263..264-1
                  *    allowFiles.length@394 <= 232-1
                  *    forbidFiles.length@395 <= 232-1
                  * 
                  *  Postconditions:
                  *    init'ed(return_value)
                  * 
                  *  Test Vectors:
                  *    java.lang.String:indexOf(...)@402: {-1}, {-231..-2, 0..232-1}
                  */
   358          if(!WebloggerRuntimeConfig.getBooleanProperty("uploads.enabled")) {
   359              messages.addError("error.upload.disabled");
   360              return false;
   361          }
   362          
   363          // second check, does upload exceed max size for file?
   364          BigDecimal maxFileMB = new BigDecimal(
   365                  WebloggerRuntimeConfig.getProperty("uploads.file.maxsize"));
   366          int maxFileBytes = (int)(1024000 * maxFileMB.doubleValue());
   367          log.debug("max allowed file size = "+maxFileBytes);
   368          log.debug("attempted save file size = "+size);
   369          if (size > maxFileBytes) {
   370              messages.addError("error.upload.filemax", maxFileMB.toString());
   371              return false;
   372          }
   373          
   374          // third check, does file cause weblog to exceed quota?
   375          BigDecimal maxDirMB = new BigDecimal(
   376                  WebloggerRuntimeConfig.getProperty("uploads.dir.maxsize"));
   377          long maxDirBytes = (long)(1024000 * maxDirMB.doubleValue());
   378          try {
   379              File uploadsDir = this.getRealFile(weblog, null);
   380              long userDirSize = getDirSize(uploadsDir, true);
   381              if (userDirSize + size > maxDirBytes) {
   382                  messages.addError("error.upload.dirmax", maxDirMB.toString());
   383                  return false;
   384              }
   385          } catch (Exception ex) {
   386              // shouldn't ever happen, means the weblogs uploads dir is bad somehow
   387              // rethrow as a runtime exception
   388              throw new RuntimeException(ex);
   389          }
   390          
   391          // fourth check, is upload type allowed?
   392          String allows = WebloggerRuntimeConfig.getProperty("uploads.types.allowed");
   393          String forbids = WebloggerRuntimeConfig.getProperty("uploads.types.forbid");
   394          String[] allowFiles = StringUtils.split(StringUtils.deleteWhitespace(allows), ",");
   395          String[] forbidFiles = StringUtils.split(StringUtils.deleteWhitespace(forbids), ",");
   396          if (!checkFileType(allowFiles, forbidFiles, path, contentType)) {
   397              messages.addError("error.upload.forbiddenFile", allows);
   398              return false;
   399          }
   400          
   401          // fifth check, is save path viable?
   402          if(path.indexOf("/") != -1) {
   403              // just make sure there is only 1 directory, we don't allow multi
   404              // level directory hierarchies right now
   405              if(path.lastIndexOf("/") != path.indexOf("/")) {
   406                  messages.addError("error.upload.badPath");
   407                  return false;
   408              }
   409          }
   410          
   411          return true;
   412      }
   413      
   414      
   415      /**
   416       * Get the size in bytes of given directory.
   417       *
   418       * Optionally works recursively counting subdirectories if they exist.
   419       */
   420      private long getDirSize(File dir, boolean recurse) {
   421          
                 /* 
    P/P           *  Method: long getDirSize(File, bool)
                  * 
                  *  Preconditions:
                  *    dir != null
                  * 
                  *  Presumptions:
                  *    files.length@424 <= 232-1
                  *    java.io.File:listFiles(...)@424 != null
                  * 
                  *  Postconditions:
                  *    init'ed(return_value)
                  * 
                  *  Test Vectors:
                  *    recurse: {0}, {1}
                  *    java.io.File:canRead(...)@423: {0}, {1}
                  *    java.io.File:exists(...)@423: {0}, {1}
                  *    java.io.File:isDirectory(...)@423: {0}, {1}
                  *    java.io.File:isDirectory(...)@427: {1}, {0}
                  */
   422          long size = 0;
   423          if(dir.exists() && dir.isDirectory() && dir.canRead()) {
   424              File[] files = dir.listFiles();
   425              long dirSize = 0l;
   426              for (int i=0; i < files.length; i++) {
+  427                  if (!files[i].isDirectory()) {
   428                      dirSize += files[i].length();
   429                  } else if(recurse) {
   430                      // count a subdirectory
   431                      dirSize += getDirSize(files[i], recurse);
   432                  }
   433              }
   434              size += dirSize;
   435          }
   436          
   437          return size;
   438      }
   439      
   440      
   441      /**
   442       * Return true if file is allowed to be uplaoded given specified allowed and
   443       * forbidden file types.
   444       */
   445      private boolean checkFileType(String[] allowFiles, String[] forbidFiles,
   446                                    String fileName, String contentType) {
   447          
   448          // TODO: Atom Publushing Protocol figure out how to handle file
   449          // allow/forbid using contentType.
   450          // TEMPORARY SOLUTION: In the allow/forbid lists we will continue to
   451          // allow user to specify file extensions (e.g. gif, png, jpeg) but will
   452          // now also allow them to specify content-type rules (e.g. */*, image/*,
   453          // text/xml, etc.).
   454          
   455          // if content type is invalid, reject file
                 /* 
    P/P           *  Method: bool checkFileType(String[], String[], String, String)
                  * 
                  *  Preconditions:
                  *    (soft) allowFiles.length <= 232-1
                  *    (soft) allowFiles[...] != null
                  *    (soft) fileName != null
                  *    (soft) forbidFiles.length <= 232-1
                  *    (soft) forbidFiles[...] != null
                  * 
                  *  Postconditions:
                  *    init'ed(return_value)
                  * 
                  *  Test Vectors:
                  *    allowFiles: Inverse{null}, Addr_Set{null}
                  *    allowFiles.length: {1..232-1}, {0}
                  *    contentType: Addr_Set{null}, Inverse{null}
                  *    forbidFiles: Addr_Set{null}, Inverse{null}
                  *    forbidFiles.length: {0}, {1..232-1}
                  *    java.lang.String:endsWith(...)@476: {0}, {1}
                  *    java.lang.String:endsWith(...)@503: {0}, {1}
                  *    java.lang.String:indexOf(...)@456: {-231..-2, 0..232-1}, {-1}
                  */
   456          if (contentType == null || contentType.indexOf("/") == -1)  {
   457              return false;
   458          }
   459          
   460          // default to false
   461          boolean allowFile = false;
   462          
   463          // if this person hasn't listed any allows, then assume they want
   464          // to allow *all* filetypes, except those listed under forbid
   465          if(allowFiles == null || allowFiles.length < 1) {
   466              allowFile = true;
   467          }
   468          
   469          // First check against what is ALLOWED
   470          
   471          // check file against allowed file extensions
   472          if (allowFiles != null && allowFiles.length > 0) {
   473              for (int y=0; y<allowFiles.length; y++) {
   474                  // oops, this allowed rule is a content-type, skip it
   475                  if (allowFiles[y].indexOf("/") != -1) continue;
   476                  if (fileName.toLowerCase().endsWith(
   477                          allowFiles[y].toLowerCase())) {
   478                      allowFile = true;
   479                      break;
   480                  }
   481              }
   482          }
   483          
   484          // check file against allowed contentTypes
   485          if (allowFiles != null && allowFiles.length > 0) {
   486              for (int y=0; y<allowFiles.length; y++) {
   487                  // oops, this allowed rule is NOT a content-type, skip it
   488                  if (allowFiles[y].indexOf("/") == -1) continue;
   489                  if (matchContentType(allowFiles[y], contentType)) {
   490                      allowFile = true;
   491                      break;
   492                  }
   493              }
   494          }
   495          
   496          // First check against what is FORBIDDEN
   497          
   498          // check file against forbidden file extensions, overrides any allows
   499          if (forbidFiles != null && forbidFiles.length > 0) {
   500              for (int x=0; x<forbidFiles.length; x++) {
   501                  // oops, this forbid rule is a content-type, skip it
   502                  if (forbidFiles[x].indexOf("/") != -1) continue;
   503                  if (fileName.toLowerCase().endsWith(
   504                          forbidFiles[x].toLowerCase())) {
   505                      allowFile = false;
   506                      break;
   507                  }
   508              }
   509          }
   510          
   511          
   512          // check file against forbidden contentTypes, overrides any allows
   513          if (forbidFiles != null && forbidFiles.length > 0) {
   514              for (int x=0; x<forbidFiles.length; x++) {
   515                  // oops, this forbid rule is NOT a content-type, skip it
   516                  if (forbidFiles[x].indexOf("/") == -1) continue;
   517                  if (matchContentType(forbidFiles[x], contentType)) {
   518                      allowFile = false;
   519                      break;
   520                  }
   521              }
   522          }
   523          
   524          return allowFile;
   525      }
   526      
   527      
   528      /**
   529       * Super simple contentType range rule matching
   530       */
   531      private boolean matchContentType(String rangeRule, String contentType) {
                 /* 
    P/P           *  Method: bool matchContentType(String, String)
                  * 
                  *  Preconditions:
                  *    rangeRule != null
                  *    (soft) contentType != null
                  * 
                  *  Postconditions:
                  *    init'ed(return_value)
                  * 
                  *  Test Vectors:
                  *    java.lang.String:equals(...)@532: {0}, {1}
                  *    java.lang.String:equals(...)@533: {0}, {1}
                  *    java.lang.String:equals(...)@536: {0}, {1}
                  */
   532          if (rangeRule.equals("*/*")) return true;
   533          if (rangeRule.equals(contentType)) return true;
   534          String ruleParts[] = rangeRule.split("/");
   535          String typeParts[] = contentType.split("/");
+  536          if (ruleParts[0].equals(typeParts[0]) && ruleParts[1].equals("*")) 
   537              return true;
   538          
   539          return false;
   540      }
   541      
   542      
   543      /**
   544       * Construct the full real path to a resource in a weblog's uploads area.
   545       */
   546      private File getRealFile(Weblog weblog, String path) 
   547              throws FileNotFoundException, FilePathException {
   548          
   549          // make sure uploads area exists for this weblog
                 /* 
    P/P           *  Method: File getRealFile(Weblog, String)
                  * 
                  *  Preconditions:
                  *    init'ed(this.upload_dir)
                  *    weblog != null
                  * 
                  *  Presumptions:
                  *    init'ed(java.io.File.separator)
                  *    init'ed(java.io.File.separatorChar)
                  *    java.io.File:canRead(...)@584 == 1
                  *    java.io.File:exists(...)@581 == 1
                  *    java.io.File:getCanonicalPath(...)@591 != null
                  *    ...
                  * 
                  *  Postconditions:
                  *    return_value == &new File(getRealFile#6)
                  *    new File(getRealFile#6) num objects == 1
                  * 
                  *  Test Vectors:
                  *    path: Addr_Set{null}, Inverse{null}
                  *    java.io.File:exists(...)@551: {1}, {0}
                  *    java.lang.String:startsWith(...)@557: {0}, {1}
                  */
   550          File weblogDir = new File(this.upload_dir + weblog.getHandle());
   551          if(!weblogDir.exists()) {
   552              weblogDir.mkdirs();
   553          }
   554          
   555          // crop leading slash if it exists
   556          String relPath = path;
   557          if(path != null && path.startsWith("/")) {
   558              relPath = path.substring(1);
   559          }
   560          
   561          // we only allow a single level of directories right now, so make
   562          // sure that the path doesn't try to go multiple levels
   563          if(relPath != null && (relPath.lastIndexOf('/') > relPath.indexOf('/'))) {
   564              throw new FilePathException("Invalid path ["+path+"], "+
   565                      "trying to use nested directories.");
   566          }
   567          
   568          // convert "/" to filesystem specific file separator
   569          if(relPath != null) {
   570              relPath = relPath.replace('/', File.separatorChar);
   571          }
   572          
   573          // now form the absolute path
   574          String filePath = weblogDir.getAbsolutePath();
   575          if(relPath != null) {
   576              filePath += File.separator + relPath;
   577          }
   578          
   579          // make sure path exists and is readable
   580          File file = new File(filePath);
   581          if(!file.exists()) {
   582              throw new FileNotFoundException("Invalid path ["+path+"], "+
   583                      "directory doesn't exist.");
   584          } else if(!file.canRead()) {
   585              throw new FilePathException("Invalid path ["+path+"], "+
   586                      "cannot read from path.");
   587          }
   588          
   589          try {
   590              // make sure someone isn't trying to sneek outside the uploads dir
   591              if(!file.getCanonicalPath().startsWith(weblogDir.getCanonicalPath())) {
   592                  throw new FilePathException("Invalid path ["+path+"], "+
   593                          "trying to get outside uploads dir.");
   594              }
   595          } catch (IOException ex) {
   596              // rethrow as FilePathException
   597              throw new FilePathException(ex);
   598          }
   599          
   600          return file;
   601      }
   602      
   603      
   604      /**
   605       * A FileManagerImpl specific implementation of a ThemeResource.
   606       *
   607       * ThemeResources from the FileManagerImpl are backed by a java.io.File
   608       * object which represents the resource on a filesystem.
   609       *
   610       * This class is internal to the FileManagerImpl class because there should 
   611       * not be any external classes which need to construct their own instances
   612       * of this class.
   613       */
   614      class WeblogResourceFile implements ThemeResource {
   615          
   616          // the physical java.io.File backing this resource
   617          private File resourceFile = null;
   618          
   619          // the relative path of the resource within the weblog's uploads area
   620          private String relativePath = null;
   621          
   622          // the weblog the resource is attached to
   623          private Weblog weblog = null;
   624          
   625          
                 /* 
    P/P           *  Method: void org.apache.roller.weblogger.business.FileManagerImpl$WeblogResourceFile(FileManagerImpl, Weblog, String, File)
                  * 
                  *  Postconditions:
                  *    this.relativePath == path
                  *    init'ed(this.relativePath)
                  *    this.resourceFile == file
                  *    init'ed(this.resourceFile)
                  *    this.weblog == weblog
                  *    init'ed(this.weblog)
                  */
   626          public WeblogResourceFile(Weblog weblog, String path, File file) {
   627              this.weblog = weblog;
   628              relativePath = path;
   629              resourceFile = file;
   630          }
   631          
   632          public Weblog getWeblog() {
                     /* 
    P/P               *  Method: Weblog getWeblog()
                      * 
                      *  Preconditions:
                      *    init'ed(this.weblog)
                      * 
                      *  Postconditions:
                      *    return_value == this.weblog
                      *    init'ed(return_value)
                      */
   633              return weblog;
   634          }
   635          
   636          public ThemeResource[] getChildren() {
   637              
                     /* 
    P/P               *  Method: ThemeResource[] getChildren()
                      * 
                      *  Preconditions:
                      *    this.resourceFile != null
                      *    (soft) init'ed(this.relativePath)
                      *    (soft) init'ed(this.weblog)
                      * 
                      *  Presumptions:
                      *    dirFiles.length@643 <= 232-1
                      *    java.io.File:listFiles(...)@643 != null
                      * 
                      *  Postconditions:
                      *    init'ed(java.lang.StringBuilder:toString(...)._tainted)
                      *    return_value in Addr_Set{null,&new ThemeResource[](getChildren#2)}
                      *    new FileManagerImpl$WeblogResourceFile(getChildren#4) num objects <= 232-1
                      *    possibly_updated(new FileManagerImpl$WeblogResourceFile(getChildren#4).relativePath)
                      *    new FileManagerImpl$WeblogResourceFile(getChildren#4).resourceFile == null
                      *    new FileManagerImpl$WeblogResourceFile(getChildren#4).weblog == this.weblog
                      *    (soft) init'ed(new FileManagerImpl$WeblogResourceFile(getChildren#4).weblog)
                      *    new ThemeResource[](getChildren#2) num objects <= 1
                      *    (soft) new ThemeResource[](getChildren#2).length <= 232-1
                      *    possibly_updated(new ThemeResource[](getChildren#2)[...])
                      * 
                      *  Test Vectors:
                      *    this.relativePath: Addr_Set{null}, Inverse{null}
                      *    java.io.File:isDirectory(...)@638: {1}, {0}
                      *    java.lang.String:equals(...)@653: {1}, {0}
                      */
   638              if(!resourceFile.isDirectory()) {
   639                  return null;
   640              }
   641              
   642              // we only want files, no directories
                     /* 
    P/P               *  Method: void org.apache.roller.weblogger.business.FileManagerImpl$WeblogResourceFile$1(FileManagerImpl$WeblogResourceFile)
                      */
   643              File[] dirFiles = resourceFile.listFiles(new FileFilter() {
   644                  public boolean accept(File f) {
                             /* 
    P/P                       *  Method: bool accept(File)
                              * 
                              *  Postconditions:
                              *    init'ed(return_value)
                              */
   645                      return (f != null) ? f.isFile() : false;
   646                  }
   647              });
   648              
   649              // convert Files into ThemeResources
   650              ThemeResource[] resources = new ThemeResource[dirFiles.length];
   651              for(int i=0; i < dirFiles.length; i++) {
+  652                  String filePath = dirFiles[i].getName();
   653                  if(relativePath != null && !relativePath.trim().equals("")) {
   654                      filePath = relativePath + "/" + filePath;
   655                  }
   656                  
   657                  resources[i] = new WeblogResourceFile(weblog, filePath, dirFiles[i]);
   658              }
   659              
   660              return resources;
   661          }
   662          
   663          public String getName() {
                     /* 
    P/P               *  Method: String getName()
                      * 
                      *  Preconditions:
                      *    this.resourceFile != null
                      * 
                      *  Postconditions:
                      *    init'ed(return_value)
                      */
   664              return resourceFile.getName();
   665          }
   666          
   667          public String getPath() {
                     /* 
    P/P               *  Method: String getPath()
                      * 
                      *  Preconditions:
                      *    init'ed(this.relativePath)
                      * 
                      *  Postconditions:
                      *    return_value == this.relativePath
                      *    init'ed(return_value)
                      */
   668              return relativePath;
   669          }
   670          
   671          public long getLastModified() {
                     /* 
    P/P               *  Method: long getLastModified()
                      * 
                      *  Preconditions:
                      *    this.resourceFile != null
                      * 
                      *  Postconditions:
                      *    init'ed(return_value)
                      */
   672              return resourceFile.lastModified();
   673          }
   674          
   675          public long getLength() {
                     /* 
    P/P               *  Method: long getLength()
                      * 
                      *  Preconditions:
                      *    this.resourceFile != null
                      * 
                      *  Postconditions:
                      *    init'ed(return_value)
                      */
   676              return resourceFile.length();
   677          }
   678          
   679          public boolean isDirectory() {
                     /* 
    P/P               *  Method: bool isDirectory()
                      * 
                      *  Preconditions:
                      *    this.resourceFile != null
                      * 
                      *  Postconditions:
                      *    init'ed(return_value)
                      */
   680              return resourceFile.isDirectory();
   681          }
   682          
   683          public boolean isFile() {
                     /* 
    P/P               *  Method: bool isFile()
                      * 
                      *  Preconditions:
                      *    this.resourceFile != null
                      * 
                      *  Postconditions:
                      *    init'ed(return_value)
                      */
   684              return resourceFile.isFile();
   685          }
   686          
   687          public InputStream getInputStream() {
   688              try {
                         /* 
    P/P                   *  Method: InputStream getInputStream()
                          * 
                          *  Preconditions:
                          *    init'ed(this.resourceFile)
                          * 
                          *  Postconditions:
                          *    return_value == &new FileInputStream(getInputStream#1)
                          *    new FileInputStream(getInputStream#1) num objects == 1
                          */
   689                  return new FileInputStream(resourceFile);
   690              } catch (java.io.FileNotFoundException ex) {
   691                  // should never happen, rethrow as runtime exception
   692                  throw new RuntimeException("Error constructing input stream", ex);
   693              }
   694          }
   695      }
   696      
   697  }








SofCheck Inspector Build Version : 2.18479
FileManagerImpl.java 2009-Jan-02 14:25:18
FileManagerImpl.class 2009-Sep-04 03:12:30
FileManagerImpl$1.class 2009-Sep-04 03:12:30
FileManagerImpl$WeblogResourceFile.class 2009-Sep-04 03:12:30
FileManagerImpl$WeblogResourceFile$1.class 2009-Sep-04 03:12:30