• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.providers.media.util;
18 
19 import static com.android.providers.media.util.FileUtils.buildPath;
20 import static com.android.providers.media.util.FileUtils.buildPrimaryVolumeFile;
21 import static com.android.providers.media.util.FileUtils.extractFileName;
22 
23 import androidx.annotation.VisibleForTesting;
24 import android.text.TextUtils;
25 import android.util.Log;
26 
27 import java.io.File;
28 import java.io.IOException;
29 import java.io.RandomAccessFile;
30 import java.util.ArrayList;
31 import java.util.List;
32 import java.util.Locale;
33 
34 public final class SyntheticPathUtils {
35     private static final String TAG = "SyntheticPathUtils";
36 
37     private static final String TRANSFORMS_DIR = ".transforms";
38     private static final String SYNTHETIC_DIR = "synthetic";
39     private static final String REDACTED_DIR = "redacted";
40     private static final String PICKER_DIR = "picker";
41 
42     public static final String REDACTED_URI_ID_PREFIX = "RUID";
43     public static final int REDACTED_URI_ID_SIZE = 36;
44 
SyntheticPathUtils()45     private SyntheticPathUtils() {}
46 
getRedactedRelativePath()47     public static String getRedactedRelativePath() {
48         return buildPath(/* base */ null, TRANSFORMS_DIR, SYNTHETIC_DIR, REDACTED_DIR).getPath();
49     }
50 
getPickerRelativePath()51     public static String getPickerRelativePath() {
52         return buildPath(/* base */ null, TRANSFORMS_DIR, SYNTHETIC_DIR, PICKER_DIR).getPath();
53     }
54 
isRedactedPath(String path, int userId)55     public static boolean isRedactedPath(String path, int userId) {
56         if (path == null) return false;
57 
58         final String redactedDir = buildPrimaryVolumeFile(userId, getRedactedRelativePath())
59                 .getAbsolutePath();
60         final String fileName = extractFileName(path);
61 
62         return fileName != null
63                 && startsWith(path, redactedDir)
64                 && startsWith(fileName, REDACTED_URI_ID_PREFIX)
65                 && fileName.length() == REDACTED_URI_ID_SIZE;
66     }
67 
isPickerPath(String path, int userId)68     public static boolean isPickerPath(String path, int userId) {
69         final String pickerDir = buildPrimaryVolumeFile(userId, getPickerRelativePath())
70                 .getAbsolutePath();
71 
72         return path != null && startsWith(path, pickerDir);
73     }
74 
isSyntheticPath(String path, int userId)75     public static boolean isSyntheticPath(String path, int userId) {
76         final String syntheticDir = buildPrimaryVolumeFile(userId, getSyntheticRelativePath())
77                 .getAbsolutePath();
78 
79         return path != null && startsWith(path, syntheticDir);
80     }
81 
extractSyntheticRelativePathSegements(String path, int userId)82     public static List<String> extractSyntheticRelativePathSegements(String path, int userId) {
83         final List<String> segments = new ArrayList<>();
84         final String syntheticDir = buildPrimaryVolumeFile(userId,
85                 getSyntheticRelativePath()).getAbsolutePath();
86 
87         if (path.toLowerCase(Locale.ROOT).indexOf(syntheticDir.toLowerCase(Locale.ROOT)) < 0) {
88             return segments;
89         }
90 
91         final String[] segmentArray = path.substring(syntheticDir.length()).split("/");
92         for (String segment : segmentArray) {
93             if (TextUtils.isEmpty(segment)) {
94                 continue;
95             }
96             segments.add(segment);
97         }
98 
99         return segments;
100     }
101 
createSparseFile(File file, long size)102     public static boolean createSparseFile(File file, long size) {
103         if (size < 0) {
104             return false;
105         }
106 
107         try (RandomAccessFile raf = new RandomAccessFile(file, "rw")) {
108             raf.setLength(size);
109             return true;
110         } catch (IOException e) {
111             Log.e(TAG, "Failed to create sparse file: " + file, e);
112             file.delete();
113             return false;
114         }
115     }
116 
117     @VisibleForTesting
getSyntheticRelativePath()118     static String getSyntheticRelativePath() {
119         return buildPath(/* base */ null, TRANSFORMS_DIR, SYNTHETIC_DIR).getPath();
120     }
121 
startsWith(String value, String prefix)122     private static boolean startsWith(String value, String prefix) {
123         return value.toLowerCase(Locale.ROOT).startsWith(prefix.toLowerCase(Locale.ROOT));
124     }
125 }
126