Files
packages_apps_Messaging/src/com/android/messaging/util/FileUtil.java
Jake Klinker 27e27d944b Use UriUtil when checking if a URI is a file.
UriUtil.isFileUri contains several additional fixes, so this ensure that existing instances where we check for the file scheme use this method as well. This covers all existing instances in the app of SCHEME_FILE.

Change-Id: I1f3131b33823eae3e620aa9608be8e72b2e84aa2
Bug: 215212561
2022-01-31 20:30:24 +00:00

153 lines
6.0 KiB
Java

/*
* Copyright (C) 2015 The Android Open Source 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.android.messaging.util;
import android.content.ContentResolver;
import android.content.Context;
import android.net.Uri;
import android.os.Environment;
import android.text.TextUtils;
import com.android.messaging.Factory;
import com.android.messaging.R;
import com.google.common.io.Files;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
public class FileUtil {
/** Returns a new file name, ensuring that such a file does not already exist. */
private static synchronized File getNewFile(File directory, String extension,
String fileNameFormat) throws IOException {
final Date date = new Date(System.currentTimeMillis());
final SimpleDateFormat dateFormat = new SimpleDateFormat(fileNameFormat);
final String numberedFileNameFormat = dateFormat.format(date) + "_%02d" + "." + extension;
for (int i = 1; i <= 99; i++) { // Only save 99 of the same file name.
final String newName = String.format(Locale.US, numberedFileNameFormat, i);
File testFile = new File(directory, newName);
if (!testFile.exists()) {
testFile.createNewFile();
return testFile;
}
}
LogUtil.e(LogUtil.BUGLE_TAG, "Too many duplicate file names: " + numberedFileNameFormat);
return null;
}
/**
* Creates an unused name to use for creating a new file. The format happens to be similar
* to that used by the Android camera application.
*
* @param directory directory that the file should be saved to
* @param contentType of the media being saved
* @return file name to be used for creating the new file. The caller is responsible for
* actually creating the file.
*/
public static File getNewFile(File directory, String contentType) throws IOException {
String fileExtension = ContentType.getExtensionFromMimeType(contentType);
final Context context = Factory.get().getApplicationContext();
String fileNameFormat = context.getString(ContentType.isImageType(contentType)
? R.string.new_image_file_name_format : R.string.new_file_name_format);
return getNewFile(directory, fileExtension, fileNameFormat);
}
/** Delete everything below and including root */
public static void removeFileOrDirectory(File root) {
removeFileOrDirectoryExcept(root, null);
}
/** Delete everything below and including root except for the given file */
public static void removeFileOrDirectoryExcept(File root, File exclude) {
if (root.exists()) {
if (root.isDirectory()) {
for (File file : root.listFiles()) {
if (exclude == null || !file.equals(exclude)) {
removeFileOrDirectoryExcept(file, exclude);
}
}
root.delete();
} else if (root.isFile()) {
root.delete();
}
}
}
/**
* Move all files and folders under a directory into the target.
*/
public static void moveAllContentUnderDirectory(File sourceDir, File targetDir) {
if (sourceDir.isDirectory() && targetDir.isDirectory()) {
if (isSameOrSubDirectory(sourceDir, targetDir)) {
LogUtil.e(LogUtil.BUGLE_TAG, "Can't move directory content since the source " +
"directory is a parent of the target");
return;
}
for (File file : sourceDir.listFiles()) {
if (file.isDirectory()) {
final File dirTarget = new File(targetDir, file.getName());
dirTarget.mkdirs();
moveAllContentUnderDirectory(file, dirTarget);
} else {
try {
final File fileTarget = new File(targetDir, file.getName());
Files.move(file, fileTarget);
} catch (IOException e) {
LogUtil.e(LogUtil.BUGLE_TAG, "Failed to move files", e);
// Try proceed with the next file.
}
}
}
}
}
// Checks if the file is in /data, and don't allow any app to send personal information.
// We're told it's possible to create world readable hardlinks to other apps private data
// so we ban all /data file uris.
public static boolean isInPrivateDir(Uri uri) {
if (!UriUtil.isFileUri(uri)) {
return false;
}
final File file = new File(uri.getPath());
return FileUtil.isSameOrSubDirectory(Environment.getDataDirectory(), file);
}
/**
* Checks, whether the child directory is the same as, or a sub-directory of the base
* directory.
*/
private static boolean isSameOrSubDirectory(File base, File child) {
try {
base = base.getCanonicalFile();
child = child.getCanonicalFile();
File parentFile = child;
while (parentFile != null) {
if (base.equals(parentFile)) {
return true;
}
parentFile = parentFile.getParentFile();
}
return false;
} catch (IOException ex) {
LogUtil.e(LogUtil.BUGLE_TAG, "Error while accessing file", ex);
return false;
}
}
}