From 20509b27f84320ce607d07174f39fcef7a9f4a1a Mon Sep 17 00:00:00 2001
From: juanf <juanf@ethz.ch>
Date: Fri, 26 May 2023 18:23:32 +0200
Subject: [PATCH] SSDM-13521: adding more methods to the Unix replacement
 library

---
 .../ch/systemsx/cisd/common/io/Posix.java     | 202 ++++++++++++++++--
 .../ch/systemsx/cisd/common/io/PosixTest.java |  13 ++
 2 files changed, 196 insertions(+), 19 deletions(-)

diff --git a/lib-commonbase/source/java/ch/systemsx/cisd/common/io/Posix.java b/lib-commonbase/source/java/ch/systemsx/cisd/common/io/Posix.java
index 7d74a6c5f35..054a6665639 100644
--- a/lib-commonbase/source/java/ch/systemsx/cisd/common/io/Posix.java
+++ b/lib-commonbase/source/java/ch/systemsx/cisd/common/io/Posix.java
@@ -17,13 +17,18 @@
 package ch.systemsx.cisd.common.io;
 
 import ch.systemsx.cisd.base.exceptions.IOExceptionUnchecked;
+import ch.systemsx.cisd.base.unix.FileLinkType;
 
 import java.io.BufferedReader;
 import java.io.IOException;
 import java.io.InputStreamReader;
+import java.nio.file.FileSystems;
 import java.nio.file.Files;
 import java.nio.file.Path;
+import java.nio.file.attribute.GroupPrincipal;
 import java.nio.file.attribute.PosixFilePermission;
+import java.nio.file.attribute.UserPrincipal;
+import java.nio.file.attribute.UserPrincipalLookupService;
 import java.util.HashSet;
 import java.util.Set;
 
@@ -38,6 +43,10 @@ public final class Posix
         return true;
     }
 
+    //
+    // User related methods
+    //
+
     public static int getGid()
     {
         try
@@ -95,58 +104,213 @@ public final class Posix
         }
     }
 
-    public static Set<PosixFilePermission> getPermissions(String path) throws IOExceptionUnchecked {
+    public static String tryGetUserNameForUid(int uid)
+    {
         try
         {
-            return Files.getPosixFilePermissions(Path.of(path));
+            UserPrincipalLookupService service = FileSystems.getDefault().getUserPrincipalLookupService();
+            UserPrincipal user = service.lookupPrincipalByName(Integer.toString(uid));
+            return user.getName();
         } catch (IOException e)
         {
             throw new IOExceptionUnchecked(e);
         }
     }
 
-    public static void setAccessMode(String path, Set<PosixFilePermission> permissions) throws IOExceptionUnchecked {
-        try {
-            Files.setPosixFilePermissions(Path.of(path), permissions);
-        } catch (IOException e) {
+    public static String tryGetGroupNameForGid(int gid)
+    {
+        try
+        {
+            UserPrincipalLookupService service = FileSystems.getDefault().getUserPrincipalLookupService();
+            GroupPrincipal group = service.lookupPrincipalByGroupName(Integer.toString(gid));
+            return group.getName();
+        } catch (IOException e)
+        {
             throw new IOExceptionUnchecked(e);
         }
     }
 
-    public static void setAccessMode(String path, short mode) throws IOExceptionUnchecked {
-        Set<PosixFilePermission> permissions = new HashSet<>();
+    //
+    // File related methods
+    //
+
+    public static class Stat
+    {
+        private final short permissions;
+
+        private final FileLinkType linkType;
+
+        private final long lastModified;
+
+        private final int uid;
+
+        private final int gid;
+
+        private final String symbolicLinkOrNull;
+
+        private final long size;
 
-        if ((400 & mode) == 400) {
+        public Stat(short permissions, FileLinkType linkType, long lastModified, int uid, int gid,
+                String symbolicLinkOrNull, long size)
+        {
+            this.permissions = permissions;
+            this.linkType = linkType;
+            this.lastModified = lastModified;
+            this.uid = uid;
+            this.gid = gid;
+            this.symbolicLinkOrNull = symbolicLinkOrNull;
+            this.size = size;
+        }
+
+        public short getPermissions()
+        {
+            return permissions;
+        }
+
+        public FileLinkType getLinkType()
+        {
+            return linkType;
+        }
+
+        public long getLastModified()
+        {
+            return lastModified;
+        }
+
+        public int getUid()
+        {
+            return uid;
+        }
+
+        public int getGid()
+        {
+            return gid;
+        }
+
+        public String getSymbolicLinkOrNull()
+        {
+            return symbolicLinkOrNull;
+        }
+
+        public long getSize() {
+            return size;
+        }
+    }
+
+    private static short getNumericAccessMode(Set<PosixFilePermission> permissions) {
+        short mode = 0;
+        if (permissions.contains(PosixFilePermission.OWNER_READ)) {
+            mode |= 0400;
+        }
+        if (permissions.contains(PosixFilePermission.OWNER_WRITE)) {
+            mode |= 0200;
+        }
+        if (permissions.contains(PosixFilePermission.OWNER_EXECUTE)) {
+            mode |= 0100;
+        }
+        if (permissions.contains(PosixFilePermission.GROUP_READ)) {
+            mode |= 040;
+        }
+        if (permissions.contains(PosixFilePermission.GROUP_WRITE)) {
+            mode |= 020;
+        }
+        if (permissions.contains(PosixFilePermission.GROUP_EXECUTE)) {
+            mode |= 010;
+        }
+        if (permissions.contains(PosixFilePermission.OTHERS_READ)) {
+            mode |= 04;
+        }
+        if (permissions.contains(PosixFilePermission.OTHERS_WRITE)) {
+            mode |= 02;
+        }
+        if (permissions.contains(PosixFilePermission.OTHERS_EXECUTE)) {
+            mode |= 01;
+        }
+        return mode;
+    }
+
+    private static Set<PosixFilePermission> getFilePermissionsMode(short mode) {
+        Set<PosixFilePermission> permissions = new HashSet<>();
+        if ((0400 & mode) == 0400) {
             permissions.add(PosixFilePermission.OWNER_READ);
         }
-        if ((200 & mode) == 200) {
+        if ((0200 & mode) == 0200) {
             permissions.add(PosixFilePermission.OWNER_WRITE);
         }
-        if ((100 & mode) == 100) {
+        if ((0100 & mode) == 0100) {
             permissions.add(PosixFilePermission.OWNER_EXECUTE);
         }
-
-        if ((40 & mode) == 40) {
+        if ((040 & mode) == 040) {
             permissions.add(PosixFilePermission.GROUP_READ);
         }
-        if ((20 & mode) == 20) {
+        if ((020 & mode) == 020) {
             permissions.add(PosixFilePermission.GROUP_WRITE);
         }
-        if ((10 & mode) == 10) {
+        if ((010 & mode) == 010) {
             permissions.add(PosixFilePermission.GROUP_EXECUTE);
         }
-
-        if ((4 & mode) == 4) {
+        if ((04 & mode) == 04) {
             permissions.add(PosixFilePermission.OTHERS_READ);
         }
-        if ((2 & mode) == 2) {
+        if ((02 & mode) == 02) {
             permissions.add(PosixFilePermission.OWNER_WRITE);
         }
-        if ((1 & mode) == 1) {
+        if ((01 & mode) == 01) {
             permissions.add(PosixFilePermission.OTHERS_EXECUTE);
         }
+        return permissions;
+    }
+
+    public static Stat tryGetLinkInfo(String pathAsString) {
+        try
+        {
+            Path path = Path.of(pathAsString);
+            short permissions = getNumericAccessMode(Files.getPosixFilePermissions(path));
+            FileLinkType linkType;
+            if (Files.isSymbolicLink(path)) {
+                linkType = FileLinkType.SYMLINK;
+            } else if (Files.isDirectory(path)) {
+                linkType = FileLinkType.DIRECTORY;
+            } else {
+                linkType = FileLinkType.OTHER;
+            }
+            long lastModified = Files.getLastModifiedTime(path).toMillis();
+            int uid = (int) Files.getAttribute(path, "unix:uid");
+            int gid = (int) Files.getAttribute(path, "unix:gid");
+            String symbolicLinkOrNull = null;
+            if (linkType == FileLinkType.SYMLINK) {
+                symbolicLinkOrNull = Files.readSymbolicLink(path).toString();
+            }
+
+            long size = Files.size(path);
+            return new Stat(permissions, linkType, lastModified, uid, gid, symbolicLinkOrNull, size);
+        } catch (IOException e)
+        {
+            throw new IOExceptionUnchecked(e);
+        }
+    }
+    
+    public static Set<PosixFilePermission> getPermissions(String path) throws IOExceptionUnchecked {
+        try
+        {
+            return Files.getPosixFilePermissions(Path.of(path));
+        } catch (IOException e)
+        {
+            throw new IOExceptionUnchecked(e);
+        }
+    }
 
+    public static void setAccessMode(String path, Set<PosixFilePermission> permissions) throws IOExceptionUnchecked {
+        try {
+            Files.setPosixFilePermissions(Path.of(path), permissions);
+        } catch (IOException e) {
+            throw new IOExceptionUnchecked(e);
+        }
+    }
+
+    public static void setAccessMode(String path, short mode) throws IOExceptionUnchecked {
         try {
+            Set<PosixFilePermission> permissions = getFilePermissionsMode(mode);
             Files.setPosixFilePermissions(Path.of(path), permissions);
         } catch (IOException e) {
             throw new IOExceptionUnchecked(e);
diff --git a/lib-commonbase/sourceTest/java/ch/systemsx/cisd/common/io/PosixTest.java b/lib-commonbase/sourceTest/java/ch/systemsx/cisd/common/io/PosixTest.java
index f28bf92bdd6..6bcb80392bc 100644
--- a/lib-commonbase/sourceTest/java/ch/systemsx/cisd/common/io/PosixTest.java
+++ b/lib-commonbase/sourceTest/java/ch/systemsx/cisd/common/io/PosixTest.java
@@ -25,6 +25,12 @@ public class PosixTest
         int gid = Posix.getGid();
     }
 
+    @Test
+    public void testTryGetGroupNameForGid() {
+        int gid = Posix.getGid();
+        String group = Posix.tryGetGroupNameForGid(gid);
+    }
+
     @Test
     public void testSetOwner() throws IOException
     {
@@ -32,4 +38,11 @@ public class PosixTest
         Posix.setOwner(file.getPath(), Posix.getUid(), Posix.getGid());
         file.delete();
     }
+
+    @Test
+    public void testTryGetLinkInfo() throws IOException {
+        File file = File.createTempFile("pre", "su");
+        Posix.Stat stat = Posix.tryGetLinkInfo(file.toString());
+        file.delete();
+    }
 }
-- 
GitLab