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 |