/*
* Copyright (C) 2012 The CyanogenMod Project
*
* 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 com.cyanogenmod.filemanager.util;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.Resources;
import android.util.Log;
import com.cyanogenmod.filemanager.FileManagerApplication;
import com.cyanogenmod.filemanager.R;
import com.cyanogenmod.filemanager.commands.shell.ResolveLinkCommand;
import com.cyanogenmod.filemanager.console.ExecutionException;
import com.cyanogenmod.filemanager.model.AID;
import com.cyanogenmod.filemanager.model.BlockDevice;
import com.cyanogenmod.filemanager.model.CharacterDevice;
import com.cyanogenmod.filemanager.model.Directory;
import com.cyanogenmod.filemanager.model.DomainSocket;
import com.cyanogenmod.filemanager.model.FileSystemObject;
import com.cyanogenmod.filemanager.model.Group;
import com.cyanogenmod.filemanager.model.NamedPipe;
import com.cyanogenmod.filemanager.model.ParentDirectory;
import com.cyanogenmod.filemanager.model.Permissions;
import com.cyanogenmod.filemanager.model.RegularFile;
import com.cyanogenmod.filemanager.model.Symlink;
import com.cyanogenmod.filemanager.model.SystemFile;
import com.cyanogenmod.filemanager.model.User;
import com.cyanogenmod.filemanager.preferences.DisplayRestrictions;
import com.cyanogenmod.filemanager.preferences.FileManagerSettings;
import com.cyanogenmod.filemanager.preferences.NavigationSortMode;
import com.cyanogenmod.filemanager.preferences.ObjectIdentifier;
import com.cyanogenmod.filemanager.preferences.Preferences;
import com.cyanogenmod.filemanager.util.MimeTypeHelper.MimeTypeCategory;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
/**
* A helper class with useful methods for deal with files.
*/
public final class FileHelper {
private static final String TAG = "FileHelper"; //$NON-NLS-1$
/**
* Special extension for compressed tar files
*/
private static final String[] COMPRESSED_TAR =
{
"tar.gz", "tar.bz2", "tar.lzma" //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
};
/**
* The root directory.
* @hide
*/
public static final String ROOT_DIRECTORY = "/"; //$NON-NLS-1$
/**
* The parent directory string.
* @hide
*/
public static final String PARENT_DIRECTORY = ".."; //$NON-NLS-1$
/**
* The current directory string.
* @hide
*/
public static final String CURRENT_DIRECTORY = "."; //$NON-NLS-1$
/**
* The administrator user.
* @hide
*/
public static final String USER_ROOT = "root"; //$NON-NLS-1$
/**
* The newline string.
* @hide
*/
public static final String NEWLINE = System.getProperty("line.separator"); //$NON-NLS-1$
/**
* Constructor of <code>FileHelper</code>.
*/
private FileHelper() {
super();
}
/**
* Method that check if a file is a symbolic link.
*
* @param file File to check
* @return boolean If file is a symbolic link
* @throws IOException If real file couldn't be checked
*/
public static boolean isSymlink(File file) throws IOException {
return file.getAbsolutePath().compareTo(file.getCanonicalPath()) != 0;
}
/**
* Method that resolves a symbolic link to the real file or directory.
*
* @param file File to check
* @return File The real file or directory
* @throws IOException If real file couldn't be resolved
*/
public static File resolveSymlink(File file) throws IOException {
return file.getCanonicalFile();
}
/**
* Method that returns a more human readable of the size
* of a file system object.
*
* @param fso File system object
* @return String The human readable size (void if fso don't supports size)
*/
public static String getHumanReadableSize(FileSystemObject fso) {
//Only if has size
if (fso instanceof Directory) {
return ""; //$NON-NLS-1$
}
if (hasSymlinkRef(fso)) {
if (isSymlinkRefDirectory(fso)) {
return ""; //$NON-NLS-1$
}
return getHumanReadableSize(((Symlink)fso).getLinkRef().getSize());
}
return getHumanReadableSize(fso.getSize());
}
/**
* Method that returns a more human readable of a size in bytes.
*
* @param size The size in bytes
* @return String The human readable size
*/
public static String getHumanReadableSize(long size) {
Resources res = FileManagerApplication.getInstance().getResources();
final String format = "%d %s"; //$NON-NLS-1$
final int[] magnitude = {
R.string.size_bytes,
R.string.size_kilobytes,
R.string.size_megabytes,
R.string.size_gigabytes
};
long aux = size;
int cc = magnitude.length;
for (int i = 0; i < cc; i++) {
long s = aux / 1024;
if (aux < 1024) {
return String.format(format, Long.valueOf(aux), res.getString(magnitude[i]));
}
aux = s;
}
return String.format(
format, Long.valueOf(aux), res.getString(magnitude[magnitude.length - 1]));
}
/**
* Method that returns if an file system object requires elevated privileges.
* This occurs when the user is "root" or when the user console doesn't have
* sufficient permissions over the file system object.
*
* @param fso File system object
* @return boolean If the file system object requires elevated privileges
*/
public static boolean isPrivileged(FileSystemObject fso) {
//Parent directory doesn't require privileges
if (fso instanceof ParentDirectory) {
return false;
}
//Checks if user is the administrator user
if (fso.getUser().getName().compareTo(USER_ROOT) == 0) {
return true;
}
//No privileged
return false;
}
/**
* Method that returns if the file system object if the root directory.
*
* @param fso The file system object to check
* @return boolean if the file system object if the root directory
*/
public static boolean isRootDirectory(FileSystemObject fso) {
if (fso.getName() == null) return true;
return fso.getName().compareTo(FileHelper.ROOT_DIRECTORY) == 0;
}
/**
* Method that returns if the folder if the root directory.
*
* @param folder The folder
* @return boolean if the folder if the root directory
*/
public static boolean isRootDirectory(String folder) {
if (folder == null) return true;
return isRootDirectory(new File(folder));
}
/**
* Method that returns if the folder if the root directory.
*
* @param folder The folder
* @return boolean if the folder if the root directory
*/
public static boolean isRootDirectory(File folder) {
if (folder.getPath() == null) return true;
return folder.getPath().compareTo(FileHelper.ROOT_DIRECTORY) == 0;
}
/**
* Method that returns if the parent file system object if the root directory.
*
* @param fso The parent file system object to check
* @return boolean if the parent file system object if the root directory
*/
public static boolean isParentRootDirectory(FileSystemObject fso) {
if (fso.getParent() == null) return true;
return fso.getParent().compareTo(FileHelper.ROOT_DIRECTORY) == 0;
}
/**
* Method that returns the name without the extension of a file system object.
*
* @param fso The file system object
* @return The name without the extension of the file system object.
*/
public static String getName(FileSystemObject fso) {
return getName(fso.getName());
}
/**
* Method that returns the name without the extension of a file system object.
*
* @param name The name of file system object
* @return The name without the extension of the file system object.
*/
public static String getName(String name) {
String ext = getExtension(name);
if (ext == null) return name;
return name.substring(0, name.length() - ext.length() - 1);
}
/**
* Method that returns the extension of a file system object.
*
* @param fso The file system object
* @return The extension of the file system object, or <code>null</code>
* if <code>fso</code> has no extension.
*/
public static String getExtension(FileSystemObject fso) {
return getExtension(fso.getName());
}
/**
* Method that returns the extension of a file system object.
*
* @param name The name of file system object
* @return The extension of the file system object, or <code>null</code>
* if <code>fso</code> has no extension.
*/
public static String getExtension(String name) {
final char dot = '.';
int pos = name.lastIndexOf(dot);
if (pos == -1 || pos == 0) { // Hidden files doesn't have extensions
return null;
}
// Exceptions to the general extraction method
int cc = COMPRESSED_TAR.length;
for (int i = 0; i < cc; i++) {
if (name.endsWith("." + COMPRESSED_TAR[i])) { //$NON-NLS-1$
return COMPRESSED_TAR[i];
}
}
// General extraction method
return name.substring(pos + 1);
}
/**
* Method that returns the parent directory of a file/folder
*
* @param path The file/folder
* @return String The parent directory
*/
public static String getParentDir(String path) {
return getParentDir(new File(path));
}
/**
* Method that returns the parent directory of a file/folder
*
* @param path The file/folder
* @return String The parent directory
*/
public static String getParentDir(File path) {
String parent = path.getParent();
if (parent == null && path.getAbsolutePath().compareTo(FileHelper.ROOT_DIRECTORY) != 0) {
parent = FileHelper.ROOT_DIRECTORY;
}
return parent;
}
/**
* Method that evaluates if a path is relative.
*
* @param src The path to check
* @return boolean If a path is relative
*/
public static boolean isRelativePath(String src) {
if (src.startsWith(CURRENT_DIRECTORY + File.separator)) {
return true;
}
if (src.startsWith(PARENT_DIRECTORY + File.separator)) {
return true;
}
if (src.indexOf(File.separator + CURRENT_DIRECTORY + File.separator) != -1) {
return true;
}
if (src.indexOf(File.separator + PARENT_DIRECTORY + File.separator) != -1) {
return true;
}
if (!src.startsWith(ROOT_DIRECTORY)) {
return true;
}
return false;
}
/**
* Method that check if the file system object is a {@link Symlink} and
* has a link reference.
*
* @param fso The file system object to check
* @return boolean If file system object the has a link reference
*/
public static boolean hasSymlinkRef(FileSystemObject fso) {
if (fso instanceof Symlink) {
return ((Symlink)fso).getLinkRef() != null;
}
return false;
}
/**
* Method that check if the file system object is a {@link Symlink} and
* the link reference is a directory.
*
* @param fso The file system object to check
* @return boolean If file system object the link reference is a directory
*/
public static boolean isSymlinkRefDirectory(FileSystemObject fso) {
if (!hasSymlinkRef(fso)) {
return false;
}
return ((Symlink)fso).getLinkRef() instanceof Directory;
}
/**
* Method that check if the file system object is a {@link Symlink} and
* the link reference is a system file.
*
* @param fso The file system object to check
* @return boolean If file system object the link reference is a system file
*/
public static boolean isSymlinkRefSystemFile(FileSystemObject fso) {
if (!hasSymlinkRef(fso)) {
return false;
}
return ((Symlink)fso).getLinkRef() instanceof SystemFile;
}
/**
* Method that check if the file system object is a {@link Symlink} and
* the link reference is a block device.
*
* @param fso The file system object to check
* @return boolean If file system object the link reference is a block device
*/
public static boolean isSymlinkRefBlockDevice(FileSystemObject fso) {
if (!hasSymlinkRef(fso)) {
return false;
}
return ((Symlink)fso).getLinkRef() instanceof BlockDevice;
}
/**
* Method that check if the file system object is a {@link Symlink} and
* the link reference is a character device.
*
* @param fso The file system object to check
* @return boolean If file system object the link reference is a character device
*/
public static boolean isSymlinkRefCharacterDevice(FileSystemObject fso) {
if (!hasSymlinkRef(fso)) {
return false;
}
return ((Symlink)fso).getLinkRef() instanceof CharacterDevice;
}
/**
* Method that check if the file system object is a {@link Symlink} and
* the link reference is a named pipe.
*
* @param fso The file system object to check
* @return boolean If file system object the link reference is a named pipe
*/
public static boolean isSymlinkRefNamedPipe(FileSystemObject fso) {
if (!hasSymlinkRef(fso)) {
return false;
}
return ((Symlink)fso).getLinkRef() instanceof NamedPipe;
}
/**
* Method that check if the file system object is a {@link Symlink} and
* the link reference is a domain socket.
*
* @param fso The file system object to check
* @return boolean If file system object the link reference is a domain socket
*/
public static boolean isSymlinkRefDomainSocket(FileSystemObject fso) {
if (!hasSymlinkRef(fso)) {
return false;
}
return ((Symlink)fso).getLinkRef() instanceof DomainSocket;
}
/**
* Method that checks if a file system object is a directory (real o symlink).
*
* @param fso The file system object to check
* @return boolean If file system object is a directory
*/
public static boolean isDirectory(FileSystemObject fso) {
if (fso instanceof Directory) {
return true;
}
if (isSymlinkRefDirectory(fso)) {
return true;
}
return false;
}
/**
* Method that checks if a file system object is a system file (real o symlink).
*
* @param fso The file system object to check
* @return boolean If file system object is a system file
*/
public static boolean isSystemFile(FileSystemObject fso) {
if (fso instanceof SystemFile) {
return true;
}
if (isSymlinkRefSystemFile(fso)) {
return true;
}
return false;
}
/**
* Method that returns the real reference of a file system object
* (the reference file system object if the file system object is a symlink.
* Otherwise the same reference).
*
* @param fso The file system object to check
* @return FileSystemObject The real file system object reference
*/
public static FileSystemObject getReference(FileSystemObject fso) {
if (hasSymlinkRef(fso)) {
return ((Symlink)fso).getLinkRef();
}
return fso;
}
/**
* Method that applies the configuration modes to the listed files
* (sort mode, hidden files, ...).
*
* @param files The listed files
* @param restrictions The restrictions to apply when displaying files
* @param chRooted If app run with no privileges
* @return List<FileSystemObject> The applied mode listed files
*/
public static List<FileSystemObject> applyUserPreferences(
List<FileSystemObject> files, Map<DisplayRestrictions,
Object> restrictions, boolean chRooted) {
return applyUserPreferences(files, restrictions, false, chRooted);
}
/**
* Method that applies the configuration modes to the listed files
* (sort mode, hidden files, ...).
*
* @param files The listed files
* @param restrictions The restrictions to apply when displaying files
* @param noSort If sort must be applied
* @param chRooted If app run with no privileges
* @return List<FileSystemObject> The applied mode listed files
*/
public static List<FileSystemObject> applyUserPreferences(
List<FileSystemObject> files, Map<DisplayRestrictions, Object> restrictions,
boolean noSort, boolean chRooted) {
//Retrieve user preferences
SharedPreferences prefs = Preferences.getSharedPreferences();
FileManagerSettings sortModePref = FileManagerSettings.SETTINGS_SORT_MODE;
FileManagerSettings showDirsFirstPref = FileManagerSettings.SETTINGS_SHOW_DIRS_FIRST;
FileManagerSettings showHiddenPref = FileManagerSettings.SETTINGS_SHOW_HIDDEN;
FileManagerSettings showSystemPref = FileManagerSettings.SETTINGS_SHOW_SYSTEM;
FileManagerSettings showSymlinksPref = FileManagerSettings.SETTINGS_SHOW_SYMLINKS;
//Remove all unnecessary files (no required by the user)
int cc = files.size();
for (int i = cc - 1; i >= 0; i--) {
FileSystemObject file = files.get(i);
//Hidden files
if (!prefs.getBoolean(
showHiddenPref.getId(),
((Boolean)showHiddenPref.getDefaultValue()).booleanValue()) || chRooted) {
if (file.isHidden()) {
files.remove(i);
continue;
}
}
//System files
if (!prefs.getBoolean(
showSystemPref.getId(),
((Boolean)showSystemPref.getDefaultValue()).booleanValue()) || chRooted) {
if (file instanceof SystemFile) {
files.remove(i);
continue;
}
}
//Symlinks files
if (!prefs.getBoolean(
showSymlinksPref.getId(),
((Boolean)showSymlinksPref.getDefaultValue()).booleanValue()) || chRooted) {
if (file instanceof Symlink) {
files.remove(i);
continue;
}
}
// Restrictions (only apply to files)
if (restrictions != null) {
if (!isDirectory(file)) {
if (!isDisplayAllowed(file, restrictions)) {
files.remove(i);
continue;
}
}
}
}
//Apply sort mode
if (!noSort) {
final boolean showDirsFirst =
prefs.getBoolean(
showDirsFirstPref.getId(),
((Boolean)showDirsFirstPref.getDefaultValue()).booleanValue());
final NavigationSortMode sortMode =
NavigationSortMode.fromId(
prefs.getInt(sortModePref.getId(),
((ObjectIdentifier)sortModePref.getDefaultValue()).getId()));
Collections.sort(files, new Comparator<FileSystemObject>() {
@Override
public int compare(FileSystemObject lhs, FileSystemObject rhs) {
//Parent directory always goes first
boolean isLhsParentDirectory = lhs instanceof ParentDirectory;
boolean isRhsParentDirectory = rhs instanceof ParentDirectory;
if (isLhsParentDirectory || isRhsParentDirectory) {
if (isLhsParentDirectory && isRhsParentDirectory) {
return 0;
}
return (isLhsParentDirectory) ? -1 : 1;
}
//Need to sort directory first?
if (showDirsFirst) {
boolean isLhsDirectory = FileHelper.isDirectory(lhs);
boolean isRhsDirectory = FileHelper.isDirectory(rhs);
if (isLhsDirectory || isRhsDirectory) {
if (isLhsDirectory && isRhsDirectory) {
//Apply sort mode
return FileHelper.doCompare(lhs, rhs, sortMode);
}
return (isLhsDirectory) ? -1 : 1;
}
}
//Apply sort mode
return FileHelper.doCompare(lhs, rhs, sortMode);
}
});
}
//Return the files
return files;
}
/**
* Method that check if a file should be displayed according to the restrictions
*
* @param fso The file system object to check
* @param restrictions The restrictions map
* @return boolean If the file should be displayed
*/
private static boolean isDisplayAllowed(
FileSystemObject fso, Map<DisplayRestrictions, Object> restrictions) {
Iterator<DisplayRestrictions> it = restrictions.keySet().iterator();
while (it.hasNext()) {
DisplayRestrictions restriction = it.next();
Object value = restrictions.get(restriction);
if (value == null) {
continue;
}
switch (restriction) {
case CATEGORY_TYPE_RESTRICTION:
if (value instanceof MimeTypeCategory) {
MimeTypeCategory cat1 = (MimeTypeCategory)value;
// NOTE: We don't need the context here, because mime-type
// database should be loaded prior to this call
MimeTypeCategory cat2 = MimeTypeHelper.getCategory(null, fso);
if (cat1.compareTo(cat2) != 0) {
return false;
}
}
break;
case MIME_TYPE_RESTRICTION:
if (value instanceof String) {
String mimeType = (String)value;
if (mimeType.compareTo(MimeTypeHelper.ALL_MIME_TYPES) != 0) {
// NOTE: We don't need the context here, because mime-type
// database should be loaded prior to this call
if (!MimeTypeHelper.matchesMimeType(null, fso, mimeType)) {
return false;
}
}
}
break;
case SIZE_RESTRICTION:
if (value instanceof Long) {
Long maxSize = (Long)value;
if (fso.getSize() > maxSize.longValue()) {
return false;
}
}
break;
case LOCAL_FILESYSTEM_ONLY_RESTRICTION:
if (value instanceof Boolean) {
Boolean localOnly = (Boolean)value;
if (localOnly.booleanValue()) {
/** TODO Needed when CMFM gets networking **/
}
}
break;
default:
break;
}
}
return true;
}
/**
* Method that resolve the symbolic links of the list of files passed as argument.<br />
* This method invokes the {@link ResolveLinkCommand} in those files that hasn't a valid
* symlink reference
*
* @param context The current context
* @param files The listed files
*/
public static void resolveSymlinks(Context context, List<FileSystemObject> files) {
int cc = files.size();
for (int i = 0; i < cc; i++) {
FileSystemObject fso = files.get(i);
if (fso instanceof Symlink && ((Symlink)fso).getLinkRef() == null) {
try {
FileSystemObject symlink =
CommandHelper.resolveSymlink(context, fso.getFullPath(), null);
((Symlink)fso).setLinkRef(symlink);
} catch (Throwable ex) {/**NON BLOCK**/}
}
}
}
/**
* Method that do a comparison between 2 file system objects.
*
* @param fso1 The first file system objects
* @param fso2 The second file system objects
* @param mode The sort mode
* @return int a negative integer if {@code fso1} is less than {@code fso2};
* a positive integer if {@code fso1} is greater than {@code fso2};
* 0 if {@code fso1} has the same order as {@code fso2}.
*/
public static int doCompare(
final FileSystemObject fso1,
final FileSystemObject fso2,
final NavigationSortMode mode) {
// Retrieve the user preference for case sensitive sort
boolean caseSensitive =
Preferences.getSharedPreferences().
getBoolean(
FileManagerSettings.SETTINGS_CASE_SENSITIVE_SORT.getId(),
((Boolean)FileManagerSettings.SETTINGS_CASE_SENSITIVE_SORT.
getDefaultValue()).booleanValue());
//Name (ascending)
if (mode.getId() == NavigationSortMode.NAME_ASC.getId()) {
if (!caseSensitive) {
return fso1.getName().compareToIgnoreCase(fso2.getName());
}
return fso1.getName().compareTo(fso2.getName());
}
//Name (descending)
if (mode.getId() == NavigationSortMode.NAME_DESC.getId()) {
if (!caseSensitive) {
return fso1.getName().compareToIgnoreCase(fso2.getName()) * -1;
}
return fso1.getName().compareTo(fso2.getName()) * -1;
}
//Date (ascending)
if (mode.getId() == NavigationSortMode.DATE_ASC.getId()) {
return fso1.getLastModifiedTime().compareTo(fso2.getLastModifiedTime());
}
//Date (descending)
if (mode.getId() == NavigationSortMode.DATE_DESC.getId()) {
return fso1.getLastModifiedTime().compareTo(fso2.getLastModifiedTime()) * -1;
}
//Comparison between files directly
return fso1.compareTo(fso2);
}
/**
* Method that add to the path the trailing slash
*
* @param path The path
* @return String The path with the trailing slash
*/
public static String addTrailingSlash(String path) {
if (path == null) return null;
return path.endsWith(File.separator) ? path : path + File.separator;
}
/**
* Method that cleans the path and removes the trailing slash
*
* @param path The path to clean
* @return String The path without the trailing slash
*/
public static String removeTrailingSlash(String path) {
if (path == null) return null;
if (path.trim().compareTo(ROOT_DIRECTORY) == 0) return path;
if (path.endsWith(File.separator)) {
return path.substring(0, path.length()-1);
}
return path;
}
/**
* Method that creates a new name based on the name of the {@link FileSystemObject}
* that is not current used by the filesystem.
*
* @param ctx The current context
* @param files The list of files of the current directory
* @param attemptedName The attempted name
* @param regexp The resource of the regular expression to create the new name
* @return String The new non-existing name
*/
public static String createNonExistingName(
final Context ctx, final List<FileSystemObject> files,
final String attemptedName, int regexp) {
// Find a non-exiting name
String newName = attemptedName;
if (!isNameExists(files, newName)) return newName;
do {
String name = FileHelper.getName(newName);
String ext = FileHelper.getExtension(newName);
if (ext == null) {
ext = ""; //$NON-NLS-1$
} else {
ext = String.format(".%s", ext); //$NON-NLS-1$
}
newName = ctx.getString(regexp, name, ext);
} while (isNameExists(files, newName));
return newName;
}
/**
* Method that checks if a name exists in the current directory.
*
* @param files The list of files of the current directory
* @param name The name to check
* @return boolean Indicate if the name exists in the current directory
*/
public static boolean isNameExists(List<FileSystemObject> files, String name) {
//Verify if the name exists in the current file list
int cc = files.size();
for (int i = 0; i < cc; i++) {
FileSystemObject fso = files.get(i);
if (fso.getName().compareTo(name) == 0) {
return true;
}
}
return false;
}
/**
* Method that returns is a {@link FileSystemObject} can be handled by this application
* allowing the uncompression of the file
*
* @param fso The file system object to verify
* @return boolean If the file is supported
*/
@SuppressWarnings("nls")
public static boolean isSupportedUncompressedFile(FileSystemObject fso) {
// Valid uncompressed formats are:
final String[] VALID =
{
"tar", "tgz", "tar.gz", "tar.bz2", "tar.lzma",
"zip", "gz", "bz2", "lzma", "xz", "Z"
};
// Check that have a valid file
if (fso == null) return false;
//Only regular files
if (isDirectory(fso) || fso instanceof Symlink) {
return false;
}
String ext = getExtension(fso);
if (ext != null) {
int cc = VALID.length;
for (int i = 0; i < cc; i++) {
if (VALID[i].compareToIgnoreCase(ext) == 0) {
return true;
}
}
}
return false;
}
/**
* Method that converts an absolute path to a relative path
*
* @param path The absolute path to convert
* @param relativeTo The absolute path from which make path relative to (a folder)
* @return String The relative path
*/
public static String toRelativePath(String path, String relativeTo) {
// Normalize the paths
File f1 = new File(path);
File f2 = new File(relativeTo);
String s1 = f1.getAbsolutePath();
String s2 = f2.getAbsolutePath();
if (!s2.endsWith(File.separator)) {
s2 = s2 + File.separator;
}
// If s2 contains s1 then the relative is replace of the start of the path
if (s1.startsWith(s2)) {
return s1.substring(s2.length());
}
StringBuffer relative = new StringBuffer();
do {
File f3 = new File(s2);
relative.append(String.format("..%s", File.separator)); //$NON-NLS-1$
s2 = f3.getParent() + File.separator;
} while (!s1.startsWith(s2) && !s1.startsWith(new File(s2).getAbsolutePath()));
s2 = new File(s2).getAbsolutePath();
return relative.toString() + s1.substring(s2.length());
}
/**
* Method that creates a {@link FileSystemObject} from a {@link File}
*
* @param file The file or folder reference
* @return FileSystemObject The file system object reference
*/
public static FileSystemObject createFileSystemObject(File file) {
try {
// The user and group name of the files. In ChRoot, aosp give restrict access to
// this user and group.
final String USER = "system"; //$NON-NLS-1$
final String GROUP = "sdcard_r"; //$NON-NLS-1$
final String PERMISSIONS = "----rwxr-x"; //$NON-NLS-1$
// The user and group name of the files. In ChRoot, aosp give restrict access to
// this user and group. This applies for permission also. This has no really much
// interest if we not allow to change the permissions
AID userAID = AIDHelper.getAIDFromName(USER);
AID groupAID = AIDHelper.getAIDFromName(GROUP);
User user = new User(userAID.getId(), userAID.getName());
Group group = new Group(groupAID.getId(), groupAID.getName());
Permissions perm = Permissions.fromRawString(PERMISSIONS);
// Build a directory?
Date lastModified = new Date(file.lastModified());
if (file.isDirectory()) {
return
new Directory(
file.getName(),
file.getParent(),
user, group, perm,
lastModified, lastModified, lastModified); // The only date we have
}
// Build a regular file
return
new RegularFile(
file.getName(),
file.getParent(),
user, group, perm,
file.length(),
lastModified, lastModified, lastModified); // The only date we have
} catch (Exception e) {
Log.e(TAG, "Exception retrieving the fso", e); //$NON-NLS-1$
}
return null;
}
/**
* Method that copies recursively to the destination
*
* @param src The source file or folder
* @param dst The destination file or folder
* @param bufferSize The buffer size for the operation
* @return boolean If the operation complete successfully
* @throws ExecutionException If a problem was detected in the operation
*/
public static boolean copyRecursive(
final File src, final File dst, int bufferSize) throws ExecutionException {
if (src.isDirectory()) {
// Create the directory
if (dst.exists() && !dst.isDirectory()) {
Log.e(TAG,
String.format("Failed to check destionation dir: %s", dst)); //$NON-NLS-1$
throw new ExecutionException("the path exists but is not a folder"); //$NON-NLS-1$
}
if (!dst.exists()) {
if (!dst.mkdir()) {
Log.e(TAG, String.format("Failed to create directory: %s", dst)); //$NON-NLS-1$
return false;
}
}
File[] files = src.listFiles();
if (files != null) {
for (int i = 0; i < files.length; i++) {
if (!copyRecursive(files[i], new File(dst, files[i].getName()), bufferSize)) {
return false;
}
}
}
} else {
// Copy the directory
if (!bufferedCopy(src, dst,bufferSize)) {
return false;
}
}
return true;
}
/**
* Method that copies a file
*
* @param src The source file
* @param dst The destination file
* @param bufferSize The buffer size for the operation
* @return boolean If the operation complete successfully
*/
public static boolean bufferedCopy(final File src, final File dst, int bufferSize) {
BufferedInputStream bis = null;
BufferedOutputStream bos = null;
try {
bis = new BufferedInputStream(new FileInputStream(src), bufferSize);
bos = new BufferedOutputStream(new FileOutputStream(dst), bufferSize);
int read = 0;
byte[] data = new byte[bufferSize];
while ((read = bis.read(data, 0, bufferSize)) != -1) {
bos.write(data, 0, read);
}
return true;
} catch (Throwable e) {
Log.e(TAG,
String.format(TAG, "Failed to copy from %s to %d", src, dst), e); //$NON-NLS-1$
return false;
} finally {
try {
if (bis != null) {
bis.close();
}
} catch (Throwable e) {/**NON BLOCK**/}
try {
if (bos != null) {
bos.close();
}
} catch (Throwable e) {/**NON BLOCK**/}
}
}
/**
* Method that deletes a folder recursively
*
* @param folder The folder to delete
* @return boolean If the folder was deleted
*/
public static boolean deleteFolder(File folder) {
File[] files = folder.listFiles();
if (files != null) {
for (int i = 0; i < files.length; i++) {
if (files[i].isDirectory()) {
if (!deleteFolder(files[i])) {
return false;
}
} else {
if (!files[i].delete()) {
return false;
}
}
}
}
return folder.delete();
}
}