You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@commons.apache.org by sc...@apache.org on 2005/09/27 00:08:47 UTC

svn commit: r291765 - in /jakarta/commons/proper/io/trunk: RELEASE-NOTES.txt project.xml src/java/org/apache/commons/io/FileUtils.java src/test/org/apache/commons/io/FileUtilsCleanDirectoryTestCase.java src/test/org/apache/commons/io/PackageTestSuite.java

Author: scolebourne
Date: Mon Sep 26 15:08:40 2005
New Revision: 291765

URL: http://svn.apache.org/viewcvs?rev=291765&view=rev
Log:
Handle security restricted directories
bug 36801, from Chris Eldredge

Added:
    jakarta/commons/proper/io/trunk/src/test/org/apache/commons/io/FileUtilsCleanDirectoryTestCase.java   (with props)
Modified:
    jakarta/commons/proper/io/trunk/RELEASE-NOTES.txt
    jakarta/commons/proper/io/trunk/project.xml
    jakarta/commons/proper/io/trunk/src/java/org/apache/commons/io/FileUtils.java
    jakarta/commons/proper/io/trunk/src/test/org/apache/commons/io/PackageTestSuite.java

Modified: jakarta/commons/proper/io/trunk/RELEASE-NOTES.txt
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/io/trunk/RELEASE-NOTES.txt?rev=291765&r1=291764&r2=291765&view=diff
==============================================================================
--- jakarta/commons/proper/io/trunk/RELEASE-NOTES.txt (original)
+++ jakarta/commons/proper/io/trunk/RELEASE-NOTES.txt Mon Sep 26 15:08:40 2005
@@ -21,7 +21,9 @@
 
 Source compatible - ???
 
-Semantic compatible - ???
+Semantic compatible - Yes, except:
+- FileUtils.sizeOfDirectory()
+    May now return a size of 0 if the directory is security restricted
 
 
 Deprecations from 1.0
@@ -57,6 +59,10 @@
 
 - AbstractFileFilter - accept(File, String)  [30992]
     Fixed broken implementation
+
+- FileUtils  [36801]
+    Previously threw NPE when listing files in a security restricted directory
+    Now throw IOException with a better message
 
 
 Enhancements from 1.0

Modified: jakarta/commons/proper/io/trunk/project.xml
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/io/trunk/project.xml?rev=291765&r1=291764&r2=291765&view=diff
==============================================================================
--- jakarta/commons/proper/io/trunk/project.xml (original)
+++ jakarta/commons/proper/io/trunk/project.xml Mon Sep 26 15:08:40 2005
@@ -172,6 +172,9 @@
       <name>Nathan Beyer</name>
     </contributor>
     <contributor>
+      <name>Chris Eldredge</name>
+    </contributor>
+    <contributor>
       <name>Marcelo Liberato</name>
     </contributor>
     <contributor>

Modified: jakarta/commons/proper/io/trunk/src/java/org/apache/commons/io/FileUtils.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/io/trunk/src/java/org/apache/commons/io/FileUtils.java?rev=291765&r1=291764&r2=291765&view=diff
==============================================================================
--- jakarta/commons/proper/io/trunk/src/java/org/apache/commons/io/FileUtils.java (original)
+++ jakarta/commons/proper/io/trunk/src/java/org/apache/commons/io/FileUtils.java Mon Sep 26 15:08:40 2005
@@ -64,6 +64,7 @@
  * @author <a href="mailto:jeremias@apache.org">Jeremias Maerki</a>
  * @author Stephen Colebourne
  * @author Ian Springer
+ * @autor Chris Eldredge
  * @version $Id$
  */
 public class FileUtils {
@@ -605,6 +606,9 @@
         }
         // recurse
         File[] files = srcDir.listFiles();
+        if (files == null) {  // null if security restricted
+            throw new IOException("Failed to list contents of " + srcDir);
+        }
         for (int i = 0; i < files.length; i++) {
             File copiedFile = new File(destDir, files[i].getName());
             if (files[i].isDirectory()) {
@@ -686,8 +690,7 @@
      * @param directory directory to clean
      * @throws IOException in case cleaning is unsuccessful
      */
-    public static void cleanDirectory(File directory)
-        throws IOException {
+    public static void cleanDirectory(File directory) throws IOException {
         if (!directory.exists()) {
             String message = directory + " does not exist";
             throw new IllegalArgumentException(message);
@@ -698,9 +701,12 @@
             throw new IllegalArgumentException(message);
         }
 
-        IOException exception = null;
-
         File[] files = directory.listFiles();
+        if (files == null) {  // null if security restricted
+            throw new IOException("Failed to list contents of " + directory);
+        }
+
+        IOException exception = null;
         for (int i = 0; i < files.length; i++) {
             File file = files[i];
             try {
@@ -929,8 +935,7 @@
      * @param directory directory to clean.
      * @throws IOException in case cleaning is unsuccessful
      */
-    private static void cleanDirectoryOnExit(File directory)
-            throws IOException {
+    private static void cleanDirectoryOnExit(File directory) throws IOException {
         if (!directory.exists()) {
             String message = directory + " does not exist";
             throw new IllegalArgumentException(message);
@@ -941,9 +946,12 @@
             throw new IllegalArgumentException(message);
         }
 
-        IOException exception = null;
-
         File[] files = directory.listFiles();
+        if (files == null) {  // null if security restricted
+            throw new IOException("Failed to list contents of " + directory);
+        }
+
+        IOException exception = null;
         for (int i = 0; i < files.length; i++) {
             File file = files[i];
             try {
@@ -990,7 +998,7 @@
      * Recursively count size of a directory (sum of the length of all files).
      *
      * @param directory directory to inspect
-     * @return size of directory in bytes.
+     * @return size of directory in bytes, 0 if directory is security restricted
      */
     public static long sizeOfDirectory(File directory) {
         if (!directory.exists()) {
@@ -1006,6 +1014,9 @@
         long size = 0;
 
         File[] files = directory.listFiles();
+        if (files == null) {  // null if security restricted
+            return 0L;
+        }
         for (int i = 0; i < files.length; i++) {
             File file = files[i];
 

Added: jakarta/commons/proper/io/trunk/src/test/org/apache/commons/io/FileUtilsCleanDirectoryTestCase.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/io/trunk/src/test/org/apache/commons/io/FileUtilsCleanDirectoryTestCase.java?rev=291765&view=auto
==============================================================================
--- jakarta/commons/proper/io/trunk/src/test/org/apache/commons/io/FileUtilsCleanDirectoryTestCase.java (added)
+++ jakarta/commons/proper/io/trunk/src/test/org/apache/commons/io/FileUtilsCleanDirectoryTestCase.java Mon Sep 26 15:08:40 2005
@@ -0,0 +1,165 @@
+/*
+ * Copyright 2005 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.io;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+import junit.textui.TestRunner;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.io.testtools.FileBasedTestCase;
+
+/**
+ * Test cases for FileUtils.cleanDirectory() method.
+ *
+ * @version $Id$
+ * @author Chris Eldredge
+ */
+public class FileUtilsCleanDirectoryTestCase extends FileBasedTestCase {
+    final File top = getLocalTestDirectory();
+
+    public static void main(String[] args) {
+        TestRunner.run(suite());
+    }
+
+    public static Test suite() {
+        return new TestSuite(FileUtilsCleanDirectoryTestCase.class);
+    }
+
+    public FileUtilsCleanDirectoryTestCase(String name) {
+        super(name);
+    }
+
+    private File getLocalTestDirectory() {
+        return new File(getTestDirectory(), "list-files");
+    }
+
+    /**
+     * @see junit.framework.TestCase#setUp()
+     */
+    protected void setUp() throws Exception {
+        top.mkdirs();
+    }
+
+    /**
+     * @see junit.framework.TestCase#tearDown()
+     */
+    protected void tearDown() throws Exception {
+        chmod(top, 775, true);
+        FileUtils.deleteDirectory(top);
+    }
+
+    //-----------------------------------------------------------------------
+    public void testCleanEmpty() throws Exception {
+        assertEquals(0, top.list().length);
+
+        FileUtils.cleanDirectory(top);
+
+        assertEquals(0, top.list().length);
+    }
+
+    public void testDeletesRegular() throws Exception {
+        FileUtils.touch(new File(top, "regular"));
+        FileUtils.touch(new File(top, ".hidden"));
+
+        assertEquals(2, top.list().length);
+
+        FileUtils.cleanDirectory(top);
+
+        assertEquals(0, top.list().length);
+    }
+
+    public void testDeletesNested() throws Exception {
+        final File nested = new File(top, "nested");
+
+        assertTrue(nested.mkdirs());
+
+        FileUtils.touch(new File(nested, "file"));
+
+        assertEquals(1, top.list().length);
+
+        FileUtils.cleanDirectory(top);
+
+        assertEquals(0, top.list().length);
+    }
+
+    public void testThrowsOnNullList() throws Exception {
+        if (!chmod(top, 0, false)) {
+            // test wont work if we can't restrict permissions on the
+            // directory, so skip it.
+            return;
+        }
+
+        try {
+            FileUtils.cleanDirectory(top);
+            fail("expected IOException");
+        } catch (IOException e) {
+            assertEquals("Failed to list contents of " +
+                    top.getAbsolutePath(), e.getMessage());
+        }
+    }
+
+    public void testThrowsOnCannotDeleteFile() throws Exception {
+        final File file = new File(top, "restricted");
+        FileUtils.touch(file);
+
+        if (!chmod(top, 500, false)) {
+            // test wont work if we can't restrict permissions on the
+            // directory, so skip it.
+            return;
+        }
+
+        try {
+            FileUtils.cleanDirectory(top);
+            fail("expected IOException");
+        } catch (IOException e) {
+            assertEquals("Unable to delete file: " +
+                    file.getAbsolutePath(), e.getMessage());
+        }
+    }
+
+    private boolean chmod(File file, int mode, boolean recurse)
+            throws IOException, InterruptedException {
+        // TODO: Refactor this to FileSystemUtils
+        List args = new ArrayList();
+        args.add("chmod");
+
+        if (recurse) {
+            args.add("-R");
+        }
+
+        args.add(Integer.toString(mode));
+        args.add(file.getAbsolutePath());
+
+        Process proc;
+
+        try {
+            proc = Runtime.getRuntime().exec(
+                    (String[]) args.toArray(new String[args.size()]));
+        } catch (IOException e) {
+            return false;
+        }
+        int result = proc.waitFor();
+        assertEquals(0, result);
+        return true;
+    }
+
+}

Propchange: jakarta/commons/proper/io/trunk/src/test/org/apache/commons/io/FileUtilsCleanDirectoryTestCase.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jakarta/commons/proper/io/trunk/src/test/org/apache/commons/io/FileUtilsCleanDirectoryTestCase.java
------------------------------------------------------------------------------
    svn:keywords = "author date id revision"

Modified: jakarta/commons/proper/io/trunk/src/test/org/apache/commons/io/PackageTestSuite.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/io/trunk/src/test/org/apache/commons/io/PackageTestSuite.java?rev=291765&r1=291764&r2=291765&view=diff
==============================================================================
--- jakarta/commons/proper/io/trunk/src/test/org/apache/commons/io/PackageTestSuite.java (original)
+++ jakarta/commons/proper/io/trunk/src/test/org/apache/commons/io/PackageTestSuite.java Mon Sep 26 15:08:40 2005
@@ -44,6 +44,7 @@
         suite.addTest(new TestSuite(FileSystemUtilsTestCase.class));
         suite.addTest(new TestSuite(FileUtilsFileNewerTestCase.class));
         suite.addTest(new TestSuite(FileUtilsListFilesTestCase.class));
+        suite.addTest(new TestSuite(FileUtilsCleanDirectoryTestCase.class));
         suite.addTest(new TestSuite(FileUtilsTestCase.class));
         suite.addTest(new TestSuite(FileFilterTestCase.class));
         suite.addTest(new TestSuite(HexDumpTest.class));



---------------------------------------------------------------------
To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-dev-help@jakarta.apache.org