package org.zeroturnaround.zip; /** * Copyright (C) 2012 ZeroTurnaround LLC <support@zeroturnaround.com> * * 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. */ import java.io.File; import java.io.IOException; import org.junit.Assume; import org.zeroturnaround.zip.commons.FileUtils; import org.junit.Test; import static org.junit.Assert.*; public class FilePermissionsTest { private final File testFile = new File(getClass().getClassLoader().getResource("TestFile.txt").getPath()); @Test public void testPreserveExecuteFlag() throws Exception { String dirName = "FilePermissionsTest-e"; File tmpDir = File.createTempFile(dirName, null); tmpDir.delete(); tmpDir.mkdir(); File fileA = new File(tmpDir, "fileA.txt"); File fileB = new File(tmpDir, "fileB.txt"); FileUtils.copyFile(testFile, fileA); FileUtils.copyFile(testFile, fileB); Assume.assumeTrue(setExecutable(fileA, false)); //Avoids failing test on Windows: File.setExecutable(): "If executable is false and the underlying file system does not implement an execute permission, then the operation will fail." setExecutable(fileA, true); setExecutable(fileB, false); //TESTS BEFORE ZIP assertTrue(fileA.exists() && fileB.exists()); assertTrue(canExecute(fileA)); assertFalse(canExecute(fileB)); assertTrue(doZipAndUnpack(dirName, ".zip", tmpDir)); //SAME TESTS AFTER ZIP & UNZIP assertTrue(fileA.exists() && fileB.exists()); assertTrue(canExecute(fileA)); assertFalse(canExecute(fileB)); } @Test public void testPreserveReadFlag() throws Exception { String dirName = "FilePermissionsTest-r"; File tmpDir = File.createTempFile(dirName, null); tmpDir.delete(); tmpDir.mkdir(); File fileA = new File(tmpDir, "fileA.txt"); File fileB = new File(tmpDir, "fileB.txt"); FileUtils.copyFile(testFile, fileA); FileUtils.copyFile(testFile, fileB); Assume.assumeTrue(setReadable(fileA, false)); //Avoids failing test on Windows: File.setReadable(): "If readable is false and the underlying file system does not implement a read permission, then the operation will fail." setReadable(fileA, true); setReadable(fileB, false); setReadable(fileB, true);//if we set read permission to false, then we can't zip the file, causing the test to fail with a permission exception //TESTS BEFORE ZIP assertTrue(fileA.exists() && fileB.exists()); assertTrue(canRead(fileA)); assertTrue(canRead(fileB)); assertTrue(doZipAndUnpack(dirName, ".zip", tmpDir)); //SAME TESTS AFTER ZIP & UNZIP assertTrue(fileA.exists() && fileB.exists()); assertTrue(canRead(fileA)); assertTrue(canRead(fileB)); } /** This is the only test that can be run on Windows to test that permissions are kept after zip and unzip. */ @Test public void testPreserveWriteFlag() throws Exception { String dirName = "FilePermissionsTest-w"; File tmpDir = File.createTempFile(dirName, null); tmpDir.delete(); tmpDir.mkdir(); File fileA = new File(tmpDir, "fileA.txt"); File fileB = new File(tmpDir, "fileB.txt"); FileUtils.copyFile(testFile, fileA, true); FileUtils.copyFile(testFile, fileB, true); //Assume.assumeTrue(setWritable(fileA, false)); //this is commented because there is no OS-specific logic for returning false in File.setWritable(), only "The operation will fail if the user does not have permission to change the access permissions of this abstract pathname." setWritable(fileA, true); setWritable(fileB, false); //TESTS BEFORE ZIP assertTrue(fileA.exists() && fileB.exists()); assertTrue(canWrite(fileA)); assertFalse(canWrite(fileB)); assertTrue(doZipAndUnpack(dirName, ".zip", tmpDir)); //SAME TESTS AFTER ZIP & UNZIP assertTrue(fileA.exists() && fileB.exists()); assertTrue(canWrite(fileA)); assertFalse(canWrite(fileB)); } private boolean doZipAndUnpack(String prefix, String suffix, File rootDir) throws IOException { File tmpZip = File.createTempFile(prefix, suffix); ZipUtil.pack(rootDir, tmpZip); FileUtils.deleteDirectory(rootDir); if(directoryHasFiles(rootDir)) {return false;}//if the directory isn't empty after the delete, we can't (easily) test to see if the unzip created files in that directory ZipUtil.unpack(tmpZip, rootDir); return directoryHasFiles(rootDir);//if the directory has files after they were all previously deleted, then the unzip worked } private static boolean directoryHasFiles(File directory) { if(directory==null || !directory.exists() || directory.listFiles()==null) {return false;} return directory.listFiles().length > 0; } private boolean canExecute(File file) throws Exception { return (Boolean) File.class.getDeclaredMethod("canExecute").invoke(file); } private boolean setExecutable(File file, boolean executable) throws Exception { return (Boolean) File.class.getDeclaredMethod("setExecutable", boolean.class).invoke(file, executable); } private boolean canWrite(File file) throws Exception { return (Boolean) File.class.getDeclaredMethod("canWrite").invoke(file); } private boolean setWritable(File file, boolean writable) throws Exception { return (Boolean) File.class.getDeclaredMethod("setWritable", boolean.class).invoke(file, writable); } private boolean canRead(File file) throws Exception { return (Boolean) File.class.getDeclaredMethod("canRead").invoke(file); } private boolean setReadable(File file, boolean readable) throws Exception { return (Boolean) File.class.getDeclaredMethod("setReadable", boolean.class).invoke(file, readable); } }