Skip to content

Commit

Permalink
Made FileUtil to copy POSIX permissions
Browse files Browse the repository at this point in the history
  • Loading branch information
lkishalmi committed Jan 15, 2023
1 parent c171415 commit b0d67bc
Show file tree
Hide file tree
Showing 5 changed files with 104 additions and 7 deletions.
24 changes: 24 additions & 0 deletions platform/openide.filesystems/apichanges.xml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,30 @@
<apidef name="filesystems">Filesystems API</apidef>
</apidefs>
<changes>
<change id="fileutil.copyposixperms">
<api name="filesystems"/>
<summary>FileObject copy preserves source posix permissions.</summary>
<version major="9" minor="32"/>
<date day="12" month="1" year="2023"/>
<author login="lkishalmi"/>
<compatibility addition="yes" semantic="compatible"/>
<description>
<a href="@TOP@/org/openide/filesystems/FileUtil.html#copyFile-org.openide.filesystems.FileObject-org.openide.filesystems.FileObject-java.lang.String-java.lang.String-">FileUtil.copyFile(...)</a> now preserve ATTRIBUTES and POSIX permissions.
</description>
<class name="FileUtil" package="org.openide.filesystems"/>
</change>
<change id="fileutil.niofilepath">
<api name="filesystems"/>
<summary>FileUtil can convert FileObject to/from java.nio.file.Path.</summary>
<version major="9" minor="32"/>
<date day="12" month="1" year="2023"/>
<author login="lkishalmi"/>
<compatibility addition="yes" semantic="compatible"/>
<description>
<a href="@TOP@/org/openide/filesystems/FileUtil.html#">FileUtil</a> has a <code>toPath(FileObject fo)</code> and <code>toFileObject(Path path)</code> utility methods.
</description>
<class name="FileUtil" package="org.openide.filesystems"/>
</change>
<change id="fileutil.copyattr.trasnform">
<api name="filesystems"/>
<summary>Allow to filter or transform attribute values during copying.</summary>
Expand Down
2 changes: 1 addition & 1 deletion platform/openide.filesystems/manifest.mf
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@ Manifest-Version: 1.0
OpenIDE-Module: org.openide.filesystems
OpenIDE-Module-Localizing-Bundle: org/openide/filesystems/Bundle.properties
OpenIDE-Module-Layer: org/openide/filesystems/resources/layer.xml
OpenIDE-Module-Specification-Version: 9.31
OpenIDE-Module-Specification-Version: 9.32


Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,8 @@ public abstract void rename(FileLock lock, String name, String ext)

/** Copies this file. This allows the filesystem to perform any additional
* operation associated with the copy. But the default implementation is simple
* copy of the file and its attributes
* copy of the file and its attributes Since version 9.32, the file POSIX
* permissions are copied as well.
*
* @param target target folder to move this file to
* @param name new basename of file
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,11 @@
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLStreamHandler;
import java.nio.file.Files;
import java.nio.file.InvalidPathException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.attribute.PosixFilePermission;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
Expand Down Expand Up @@ -538,7 +540,8 @@ public static void copy(InputStream is, OutputStream os)
}

/** Copies file to the selected folder.
* This implementation simply copies the file by stream content.
* This implementation simply copies the file by stream content. Since version
* 9.32, the file POSIX permissions are copied as well.
* @param source source file object
* @param destFolder destination folder
* @param newName file name (without extension) of destination file
Expand Down Expand Up @@ -567,6 +570,7 @@ static FileObject copyFileImpl(FileObject source, FileObject destFolder, String
}

copy(bufIn, bufOut);
copyPosixPerms(source, dest);
copyAttributes(source, dest);
} finally {
if (bufIn != null) {
Expand All @@ -584,6 +588,17 @@ static FileObject copyFileImpl(FileObject source, FileObject destFolder, String

return dest;
}

static void copyPosixPerms(FileObject source, FileObject dest) throws IOException {
Path src = toPath(source);
Path dst = toPath(dest);
if ((src != null) && (dst != null)) {
try {
Set<PosixFilePermission> perms = Files.getPosixFilePermissions(src);
Files.setPosixFilePermissions(dst, perms);
} catch (UnsupportedOperationException ex) {}
}
}

//
// public methods
Expand All @@ -605,7 +620,9 @@ public static FileSystem createMemoryFileSystem() {
}

/** Copies file to the selected folder.
* This implementation simply copies the file by stream content.
* This implementation simply copies the file by stream content. Since version
* 9.32, the file POSIX permissions are copied as well.
*
* @param source source file object
* @param destFolder destination folder
* @param newName file name (without extension) of destination file
Expand All @@ -620,7 +637,8 @@ public static FileObject copyFile(FileObject source, FileObject destFolder, Stri
}

/** Copies file to the selected folder.
* This implementation simply copies the file by stream content.
* This implementation simply copies the file by stream content. Since version
* 9.32, the file POSIX permissions are copied as well.
* Uses the extension of the source file.
* @param source source file object
* @param destFolder destination folder
Expand Down Expand Up @@ -832,10 +850,22 @@ public static File toFile(FileObject fo) {
assert assertNormalized(retVal, BaseUtilities.isMac()); // #240180
return retVal;
}

/** Finds appropriate java.nio.file.Path to FileObject if possible.
* If not possible then null is returned.
* This is the inverse operation of {@link #toFileObject}.
* @param fo FileObject whose corresponding Path will be looked for
* @return java.nio.file.Path or null if no corresponding File exists.
* @since 9.32
*/
public static Path toPath(FileObject fo) {
File f = toFile(fo);
return f != null ? f.toPath() : null;
}

/**
* Converts a disk file to a matching file object.
* This is the inverse operation of {@link #toFile}.
* This is the inverse operation of {@link #toFile(org.openide.filesystems.FileObject) }.
* <p class="nonnormative">
* If you are running with {@code org.netbeans.modules.masterfs} enabled,
* this method should never return null for a file which exists on disk.
Expand Down Expand Up @@ -896,7 +926,24 @@ public static FileObject toFileObject(File file) {
}
return retVal;
}


/**
* Converts a Path to a FileObject if that is possible. It uses the
* {@link #toFileObject(java.io.File)} method with {@code path.toFile()}.
* if the conversion is not possible for some reason {@code null} is returned.
*
* @param path the {@link Path} to be converted
* @return the {@link FileObject} representing the {@code path} or {@code null}
* @since 9.32
*/
public static FileObject toFileObject(Path path) {
try {
return toFileObject(path.toFile());
} catch (UnsupportedOperationException ex) {
return null;
}
}

/** Finds appropriate FileObjects to java.io.File if possible.
* If not possible then empty array is returned. More FileObjects may
* correspond to one java.io.File that`s why array is returned.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,18 +24,23 @@
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.attribute.PosixFilePermission;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.LogRecord;
import java.util.logging.Logger;
import junit.framework.Test;
import static org.junit.Assume.assumeFalse;
import org.netbeans.junit.Log;
import org.netbeans.junit.NbTestCase;
import org.netbeans.junit.NbTestSuite;
Expand All @@ -44,6 +49,7 @@
import org.openide.util.Lookup;
import org.openide.util.RequestProcessor;
import org.openide.util.BaseUtilities;
import org.openide.util.Utilities;
import org.openide.util.test.MockLookup;

/**
Expand Down Expand Up @@ -704,6 +710,25 @@ public void close() throws SecurityException {
assertTrue(result.toExternalForm().endsWith("/")); //NOI18N
}

public void testCopyPosixPerms() throws Exception {
assumeFalse(Utilities.isWindows());

LocalFileSystem lfs = new LocalFileSystem();
lfs.setRootDirectory(new File("/"));
FileObject workDir = lfs.findResource(getWorkDir().getAbsolutePath());
clearWorkDir();

FileObject source = workDir.createData("original.file");
Set<PosixFilePermission> perms = new HashSet<>(Files.getPosixFilePermissions(FileUtil.toPath(source)));
assertFalse(perms.contains(PosixFilePermission.OWNER_EXECUTE));
perms.add(PosixFilePermission.OWNER_EXECUTE);
Files.setPosixFilePermissions(FileUtil.toPath(source), perms);

FileObject dest = FileUtil.copyFile(source, workDir, "copied.file");
perms = Files.getPosixFilePermissions(FileUtil.toPath(dest));
assertTrue(perms.contains(PosixFilePermission.OWNER_EXECUTE));
}

public void testCopyAttributes() throws Exception {
FileObject testRoot = FileUtil.createMemoryFileSystem().getRoot();
FileObject aFile = testRoot.createData("a", "file");
Expand Down

0 comments on commit b0d67bc

Please sign in to comment.