/FileExtraction/Java_unseen/PowerExplorer_PowerFileExplorer/PowerFileExplorer/src/main/java/com/amaze/filemanager/utils/RootUtils.java
package com.amaze.filemanager.utils;

/**
 * Created by arpitkh996 on 25-01-2016.
 */

import com.amaze.filemanager.exceptions.RootNotPermittedException;
import com.amaze.filemanager.filesystem.RootHelper;

import java.util.ArrayList;
import java.util.regex.Pattern;

public class RootUtils {
    public static final String DATA_APP_DIR = "/data/app";
    private static final String LS = "ls -lAnH \"%\" --color=never";
    private static final String LSDIR = "ls -land \"%\" --color=never";
    public static final String SYSTEM_APP_DIR = "/system/app";
    private static final Pattern mLsPattern;

    static {
        mLsPattern = Pattern.compile(".[rwxsStT-]{9}\\s+.*");
    }

    public static boolean isValid(String str) {
        return mLsPattern.matcher(str).matches();
    }

    public static boolean isUnixVirtualDirectory(String str) {
        return str.startsWith("/proc") || str.startsWith("/sys");
    }

    /**
     * Get a shell based listing
     * Context is superuser level shell
     * @param str
     * @return
     */
    public static ArrayList<String> getDirListingSu(String str) throws RootNotPermittedException {
        ArrayList<String> arrayLis=RootHelper.runShellCommand(LS.replace("%", str));
        return arrayLis;
    }

    /**
     * Change permissions (owner/group/others) of a specified path
     * @param path
     * @param octalNotation octal notation of permission
     * @throws RootNotPermittedException
     */
    public static void chmod(String path, int octalNotation) throws RootNotPermittedException {

        String mountPoint = mountFileSystemRW(path);

        String command = "chmod %d \"%s\"";

        RootHelper.runShellCommand(String.format(command, octalNotation, path));

        if (mountPoint!=null) {
            // we mounted the filesystem as rw, let's mount it back to ro
            mountFileSystemRO(mountPoint);
        }
    }


    /**
     * Mount filesystem associated with path for writable access (rw)
     * Since we don't have the root of filesystem to remount, we need to parse output of
     * # mount command.
     * @param path the path on which action to perform
     * @return String the root of mount point that was ro, and mounted to rw; null otherwise
     * @throws RootNotPermittedException
     */
    private static String mountFileSystemRW(String path) throws RootNotPermittedException {
        String command = "mount";
        ArrayList<String> output = RootHelper.runShellCommand(command);
        String mountPoint = "", types = null;
        for (String line : output) {
            String[] words = line.split(" ");

            if (path.contains(words[2])) {
                // current found point is bigger than last one, hence not a conflicting one
                // we're finding the best match, this omits for eg. / and /sys when we're actually
                // looking for /system
                if (words[2].length() > mountPoint.length()) {
                    mountPoint = words[2];
                    types = words[5];
                }
            }
        }

        if (!mountPoint.equals("") && types!=null) {

            // we have the mountpoint, check for mount options if already rw
            if (types.contains("rw")) {
                // already a rw filesystem return
                return null;
            } else if (types.contains("ro")) {
                // read-only file system, remount as rw
                String mountCommand = "mount -o rw,remount " + mountPoint;
                ArrayList<String> mountOutput = RootHelper.runShellCommand(mountCommand);

                if (mountOutput.size()!=0) {
                    // command failed, and we got a reason echo'ed
                    return null;
                } else return mountPoint;
            }
        }
        return null;
    }

    /**
     * Mount path for read-only access (ro)
     * @param path the root of device/filesystem to be mounted as ro
     * @throws RootNotPermittedException
     */
    private static void mountFileSystemRO(String path) throws RootNotPermittedException {
        String command = "umount -r \"" + path + "\"";
        RootHelper.runShellCommand(command);
    }

    /**
     * Copies file using root
     * @param source
     * @param destination
     * @throws RootNotPermittedException
     */
    public static void copy(String source, String destination) throws RootNotPermittedException {

        // remounting destination as rw
        String mountPoint = mountFileSystemRW(destination);

        RootHelper.runShellCommand("cp \"" + source + "\" \"" + destination + "\"");

        if (mountPoint!=null) {
            // we mounted the filesystem as rw, let's mount it back to ro
            mountFileSystemRO(mountPoint);
        }
    }

    /**
     * Creates an empty directory using root
     * @param path path to new directory
     * @param name name of directory
     * @throws RootNotPermittedException
     */
    public static void mkDir(String path, String name) throws RootNotPermittedException {

        String mountPoint = mountFileSystemRW(path);

        RootHelper.runShellCommand("mkdir \"" + path + "/" + name + "\"");
        if (mountPoint!=null) {
            // we mounted the filesystem as rw, let's mount it back to ro
            mountFileSystemRO(mountPoint);
        }
    }

    /**
     * Creates an empty file using root
     * @param path path to new file
     * @throws RootNotPermittedException
     */
    public static void mkFile(String path) throws RootNotPermittedException {

        String mountPoint = mountFileSystemRW(path);

        RootHelper.runShellCommand("touch \"" + path +"\"");
        if (mountPoint!=null) {
            // we mounted the filesystem as rw, let's mount it back to ro
            mountFileSystemRO(mountPoint);
        }
    }


    /**
     * Returns file permissions in octal notation
     * Method requires busybox
     * @param path
     * @return
     */
    private static int getFilePermissions(String path) throws RootNotPermittedException {
        String line = RootHelper.runShellCommand("stat -c  %a \"" + path + "\"").get(0);

        return Integer.valueOf(line).intValue();
    }

    /**
     * Recursively removes a path with it's contents (if any)
     * @param path
     * @return boolean whether file was deleted or not
     * @throws RootNotPermittedException
     */
    public static boolean delete(String path) throws RootNotPermittedException {

        String mountPoint = mountFileSystemRW(path);

        ArrayList<String> result = RootHelper.runShellCommand("rm -rf \"" + path + "\"");

        if (mountPoint!=null) {
            // we mounted the filesystem as rw, let's mount it back to ro
            mountFileSystemRO(mountPoint);
        }

        return result.size()!=0;
    }

    /*public static boolean isBusyboxAvailable() throws RootNotPermittedException {
        ArrayList<String> output = RootHelper.runShellCommand("busybox");
        return output.size()!=0;
    }*/

    /**
     * Moves file using root
     * @param path
     * @param destination
     * @throws RootNotPermittedException
     */
    public static void move(String path, String destination)
            throws RootNotPermittedException {

        // remounting destination as rw
        String mountPoint = mountFileSystemRW(destination);

        //mountOwnerRW(mountPath);
        RootHelper.runShellCommand("mv \"" + path + "\" \"" + destination + "\"");

        if (mountPoint!=null) {
            // we mounted the filesystem as rw, let's mount it back to ro
            mountFileSystemRO(mountPoint);
        }
    }

    /**
     * Renames file using root
     * @param oldPath path to file before rename
     * @param newPath path to file after rename
     * @throws RootNotPermittedException
     * @return if rename was successful or not
     */
    public static boolean rename(String oldPath, String newPath)
            throws RootNotPermittedException {

        String mountPoint = mountFileSystemRW(oldPath);

        ArrayList<String> output = RootHelper.runShellCommand("mv \"" + oldPath + "\" \"" + newPath + "\"");

        if (mountPoint!=null) {
            // we mounted the filesystem as rw, let's mount it back to ro
            mountFileSystemRO(mountPoint);
        }

        return output.size()==0;
    }

    public static void cat(String sourcePath, String destinationPath)
            throws RootNotPermittedException {

        String mountPoint = mountFileSystemRW(destinationPath);

        RootHelper.runShellCommand("cat \"" + sourcePath + "\" > \"" + destinationPath + "\"");
        if (mountPoint!=null) {
            // we mounted the filesystem as rw, let's mount it back to ro
            mountFileSystemRO(mountPoint);
        }
    }

    public static String parsePermission(String permLine) {
        int owner = 0;
        int READ = 4;
        int WRITE = 2;
        int EXECUTE = 1;
        if (permLine.charAt(1) == 'r') {
            owner += READ;
        }
        if (permLine.charAt(2) == 'w') {
            owner += WRITE;
        }
        if (permLine.charAt(3) == 'x') {
            owner += EXECUTE;
        }
        int group = 0;
        if (permLine.charAt(4) == 'r') {
            group += READ;
        }
        if (permLine.charAt(5) == 'w') {
            group += WRITE;
        }
        if (permLine.charAt(6) == 'x') {
            group += EXECUTE;
        }
        int world = 0;
        if (permLine.charAt(7) == 'r') {
            world += READ;
        }
        if (permLine.charAt(8) == 'w') {
            world += WRITE;
        }
        if (permLine.charAt(9) == 'x') {
            world += EXECUTE;
        }
        String finalValue = owner + "" + group + "" + world;
        return finalValue;
    }
}

