xref: /aosp_15_r20/external/vogar/src/vogar/android/DeviceFilesystem.java (revision e17b455832b152077f3f109e08c3a59761ae9ee5)
1*e17b4558SAndroid Build Coastguard Worker /*
2*e17b4558SAndroid Build Coastguard Worker  * Copyright (C) 2011 The Android Open Source Project
3*e17b4558SAndroid Build Coastguard Worker  *
4*e17b4558SAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*e17b4558SAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*e17b4558SAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*e17b4558SAndroid Build Coastguard Worker  *
8*e17b4558SAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*e17b4558SAndroid Build Coastguard Worker  *
10*e17b4558SAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*e17b4558SAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*e17b4558SAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*e17b4558SAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*e17b4558SAndroid Build Coastguard Worker  * limitations under the License.
15*e17b4558SAndroid Build Coastguard Worker  */
16*e17b4558SAndroid Build Coastguard Worker 
17*e17b4558SAndroid Build Coastguard Worker package vogar.android;
18*e17b4558SAndroid Build Coastguard Worker 
19*e17b4558SAndroid Build Coastguard Worker import com.google.common.collect.ImmutableList;
20*e17b4558SAndroid Build Coastguard Worker import java.io.File;
21*e17b4558SAndroid Build Coastguard Worker import java.io.FileNotFoundException;
22*e17b4558SAndroid Build Coastguard Worker import java.util.ArrayList;
23*e17b4558SAndroid Build Coastguard Worker import java.util.HashSet;
24*e17b4558SAndroid Build Coastguard Worker import java.util.LinkedList;
25*e17b4558SAndroid Build Coastguard Worker import java.util.List;
26*e17b4558SAndroid Build Coastguard Worker import java.util.Set;
27*e17b4558SAndroid Build Coastguard Worker import vogar.Log;
28*e17b4558SAndroid Build Coastguard Worker import vogar.commands.Command;
29*e17b4558SAndroid Build Coastguard Worker import vogar.commands.CommandFailedException;
30*e17b4558SAndroid Build Coastguard Worker 
31*e17b4558SAndroid Build Coastguard Worker /**
32*e17b4558SAndroid Build Coastguard Worker  * Make directories on a remote filesystem.
33*e17b4558SAndroid Build Coastguard Worker  */
34*e17b4558SAndroid Build Coastguard Worker public final class DeviceFilesystem {
35*e17b4558SAndroid Build Coastguard Worker     private final Set<File> mkdirCache = new HashSet<File>();
36*e17b4558SAndroid Build Coastguard Worker     private final List<String> targetProcessPrefix;
37*e17b4558SAndroid Build Coastguard Worker     private final Log log;
38*e17b4558SAndroid Build Coastguard Worker 
DeviceFilesystem(Log log, ImmutableList<String> targetProcessPrefix)39*e17b4558SAndroid Build Coastguard Worker     public DeviceFilesystem(Log log, ImmutableList<String> targetProcessPrefix) {
40*e17b4558SAndroid Build Coastguard Worker         this.log = log;
41*e17b4558SAndroid Build Coastguard Worker         this.targetProcessPrefix = targetProcessPrefix;
42*e17b4558SAndroid Build Coastguard Worker     }
43*e17b4558SAndroid Build Coastguard Worker 
mkdirs(File name)44*e17b4558SAndroid Build Coastguard Worker     public void mkdirs(File name) {
45*e17b4558SAndroid Build Coastguard Worker         LinkedList<File> directoryStack = new LinkedList<File>();
46*e17b4558SAndroid Build Coastguard Worker         File dir = name;
47*e17b4558SAndroid Build Coastguard Worker         // Do some directory bootstrapping since "mkdir -p" doesn't work in adb shell. Don't bother
48*e17b4558SAndroid Build Coastguard Worker         // trying to create /sdcard or /. This might reach dir == null if given a relative path,
49*e17b4558SAndroid Build Coastguard Worker         // otherwise it should terminate with "/sdcard" or "/".
50*e17b4558SAndroid Build Coastguard Worker         while (dir != null && !dir.getPath().equals("/sdcard") && !dir.getPath().equals("/")) {
51*e17b4558SAndroid Build Coastguard Worker             directoryStack.addFirst(dir);
52*e17b4558SAndroid Build Coastguard Worker             dir = dir.getParentFile();
53*e17b4558SAndroid Build Coastguard Worker         }
54*e17b4558SAndroid Build Coastguard Worker         // would love to do "adb shell mkdir DIR1 DIR2 DIR3 ..." but unfortunately this will stop
55*e17b4558SAndroid Build Coastguard Worker         // if any of the directories fail to be created (even for a reason like "file exists"), so
56*e17b4558SAndroid Build Coastguard Worker         // they have to be created one by one.
57*e17b4558SAndroid Build Coastguard Worker         for (File createDir : directoryStack) {
58*e17b4558SAndroid Build Coastguard Worker             // to reduce adb traffic, only try to make a directory if we haven't tried before.
59*e17b4558SAndroid Build Coastguard Worker             if (!mkdirCache.contains(createDir)) {
60*e17b4558SAndroid Build Coastguard Worker                 mkdir(createDir);
61*e17b4558SAndroid Build Coastguard Worker                 mkdirCache.add(createDir);
62*e17b4558SAndroid Build Coastguard Worker             }
63*e17b4558SAndroid Build Coastguard Worker         }
64*e17b4558SAndroid Build Coastguard Worker     }
65*e17b4558SAndroid Build Coastguard Worker 
mkdir(File name)66*e17b4558SAndroid Build Coastguard Worker     private void mkdir(File name) {
67*e17b4558SAndroid Build Coastguard Worker         List<String> args = new ArrayList<String>();
68*e17b4558SAndroid Build Coastguard Worker         args.addAll(targetProcessPrefix);
69*e17b4558SAndroid Build Coastguard Worker         args.add("mkdir");
70*e17b4558SAndroid Build Coastguard Worker         args.add(name.getPath());
71*e17b4558SAndroid Build Coastguard Worker 
72*e17b4558SAndroid Build Coastguard Worker         List<String> rawResult = new Command.Builder(log)
73*e17b4558SAndroid Build Coastguard Worker                 .args(args)
74*e17b4558SAndroid Build Coastguard Worker                 .permitNonZeroExitStatus(true)
75*e17b4558SAndroid Build Coastguard Worker                 .execute();
76*e17b4558SAndroid Build Coastguard Worker         // fail if this failed for any reason other than the file existing.
77*e17b4558SAndroid Build Coastguard Worker         if (!rawResult.isEmpty() && !rawResult.get(0).contains("File exists")) {
78*e17b4558SAndroid Build Coastguard Worker             throw new CommandFailedException(args, rawResult);
79*e17b4558SAndroid Build Coastguard Worker         }
80*e17b4558SAndroid Build Coastguard Worker     }
81*e17b4558SAndroid Build Coastguard Worker 
ls(File dir)82*e17b4558SAndroid Build Coastguard Worker     public List<File> ls(File dir) throws FileNotFoundException {
83*e17b4558SAndroid Build Coastguard Worker         List<String> args = new ArrayList<String>();
84*e17b4558SAndroid Build Coastguard Worker         args.addAll(targetProcessPrefix);
85*e17b4558SAndroid Build Coastguard Worker         args.add("ls");
86*e17b4558SAndroid Build Coastguard Worker         args.add(dir.getPath());
87*e17b4558SAndroid Build Coastguard Worker 
88*e17b4558SAndroid Build Coastguard Worker         List<String> rawResult = new Command.Builder(log)
89*e17b4558SAndroid Build Coastguard Worker                 .args(args)
90*e17b4558SAndroid Build Coastguard Worker                 // Note: When all supported versions of Android correctly return the exit code
91*e17b4558SAndroid Build Coastguard Worker                 // from adb we can rely on the exit code to detect failure. Until then: no.
92*e17b4558SAndroid Build Coastguard Worker                 .permitNonZeroExitStatus(true)
93*e17b4558SAndroid Build Coastguard Worker                 .execute();
94*e17b4558SAndroid Build Coastguard Worker         List<File> files = new ArrayList<File>();
95*e17b4558SAndroid Build Coastguard Worker         for (String fileString : rawResult) {
96*e17b4558SAndroid Build Coastguard Worker             // Try to match outputs like:
97*e17b4558SAndroid Build Coastguard Worker             //
98*e17b4558SAndroid Build Coastguard Worker             //   ls: <path>: No such file or directory
99*e17b4558SAndroid Build Coastguard Worker             if (fileString.contains(dir.getPath() + ": No such file or directory")) {
100*e17b4558SAndroid Build Coastguard Worker                 throw new FileNotFoundException(dir + " not found.");
101*e17b4558SAndroid Build Coastguard Worker             }
102*e17b4558SAndroid Build Coastguard Worker             if (fileString.equals(dir.getPath())) {
103*e17b4558SAndroid Build Coastguard Worker                 // The argument must have been a file or symlink, not a directory
104*e17b4558SAndroid Build Coastguard Worker                 files.add(dir);
105*e17b4558SAndroid Build Coastguard Worker             } else {
106*e17b4558SAndroid Build Coastguard Worker                 files.add(new File(dir, fileString));
107*e17b4558SAndroid Build Coastguard Worker             }
108*e17b4558SAndroid Build Coastguard Worker         }
109*e17b4558SAndroid Build Coastguard Worker         return files;
110*e17b4558SAndroid Build Coastguard Worker     }
111*e17b4558SAndroid Build Coastguard Worker }
112