Skip to content

Commit b2cd20c

Browse files
Use FileUtils for bootstrap and shared storage symlinks setup
1 parent d4fc34c commit b2cd20c

File tree

2 files changed

+36
-56
lines changed

2 files changed

+36
-56
lines changed

app/src/main/java/com/termux/app/TermuxActivity.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,7 @@ public void onServiceConnected(ComponentName componentName, IBinder service) {
251251

252252
if (mTermuxService.isTermuxSessionsEmpty()) {
253253
if (mIsVisible) {
254-
TermuxInstaller.setupIfNeeded(TermuxActivity.this, () -> {
254+
TermuxInstaller.setupBootstrapIfNeeded(TermuxActivity.this, () -> {
255255
if (mTermuxService == null) return; // Activity might have been destroyed.
256256
try {
257257
Bundle bundle = getIntent().getExtras();

app/src/main/java/com/termux/app/TermuxInstaller.java

+35-55
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,13 @@
1111
import android.view.WindowManager;
1212

1313
import com.termux.R;
14+
import com.termux.app.file.FileUtils;
1415
import com.termux.app.utils.Logger;
1516

1617
import java.io.BufferedReader;
1718
import java.io.ByteArrayInputStream;
1819
import java.io.File;
1920
import java.io.FileOutputStream;
20-
import java.io.IOException;
2121
import java.io.InputStreamReader;
2222
import java.util.ArrayList;
2323
import java.util.List;
@@ -32,7 +32,7 @@
3232
* <p/>
3333
* (2) A progress dialog is shown with "Installing..." message and a spinner.
3434
* <p/>
35-
* (3) A staging directory, $STAGING_PREFIX, is {@link #deleteDirectory(File)} if left over from broken installation below.
35+
* (3) A staging directory, $STAGING_PREFIX, is cleared if left over from broken installation below.
3636
* <p/>
3737
* (4) The zip file is loaded from a shared library.
3838
* <p/>
@@ -47,10 +47,8 @@ final class TermuxInstaller {
4747

4848
private static final String LOG_TAG = "TermuxInstaller";
4949

50-
/** Performs setup if necessary. */
51-
static void setupIfNeeded(final Activity activity, final Runnable whenDone) {
52-
Logger.logInfo(LOG_TAG, "Installing " + TermuxConstants.TERMUX_APP_NAME + " bootstrap packages.");
53-
50+
/** Performs bootstrap setup if necessary. */
51+
static void setupBootstrapIfNeeded(final Activity activity, final Runnable whenDone) {
5452
// Termux can only be run as the primary user (device owner) since only that
5553
// account has the expected file system paths. Verify that:
5654
UserManager um = (UserManager) activity.getSystemService(Context.USER_SERVICE);
@@ -63,7 +61,6 @@ static void setupIfNeeded(final Activity activity, final Runnable whenDone) {
6361
return;
6462
}
6563

66-
Logger.logInfo(LOG_TAG, "Creating prefix directory \"" + TermuxConstants.TERMUX_PREFIX_DIR_PATH + "\".");
6764
final File PREFIX_FILE = TermuxConstants.TERMUX_PREFIX_DIR;
6865
if (PREFIX_FILE.isDirectory()) {
6966
whenDone.run();
@@ -75,12 +72,16 @@ static void setupIfNeeded(final Activity activity, final Runnable whenDone) {
7572
@Override
7673
public void run() {
7774
try {
75+
Logger.logInfo(LOG_TAG, "Installing " + TermuxConstants.TERMUX_APP_NAME + " bootstrap packages.");
76+
77+
String errmsg;
78+
7879
final String STAGING_PREFIX_PATH = TermuxConstants.TERMUX_STAGING_PREFIX_DIR_PATH;
7980
final File STAGING_PREFIX_FILE = new File(STAGING_PREFIX_PATH);
8081

81-
if (STAGING_PREFIX_FILE.exists()) {
82-
Logger.logInfo(LOG_TAG, "Deleting prefix staging directory \"" + TermuxConstants.TERMUX_STAGING_PREFIX_DIR_PATH + "\".");
83-
deleteDirectory(STAGING_PREFIX_FILE);
82+
errmsg = FileUtils.clearDirectory(activity, "prefix staging directory", STAGING_PREFIX_PATH);
83+
if (errmsg != null) {
84+
throw new RuntimeException(errmsg);
8485
}
8586

8687
Logger.logInfo(LOG_TAG, "Extracting bootstrap zip to prefix staging directory \"" + TermuxConstants.TERMUX_STAGING_PREFIX_DIR_PATH + "\".");
@@ -103,14 +104,14 @@ public void run() {
103104
String newPath = STAGING_PREFIX_PATH + "/" + parts[1];
104105
symlinks.add(Pair.create(oldPath, newPath));
105106

106-
ensureDirectoryExists(new File(newPath).getParentFile());
107+
ensureDirectoryExists(activity, new File(newPath).getParentFile());
107108
}
108109
} else {
109110
String zipEntryName = zipEntry.getName();
110111
File targetFile = new File(STAGING_PREFIX_PATH, zipEntryName);
111112
boolean isDirectory = zipEntry.isDirectory();
112113

113-
ensureDirectoryExists(isDirectory ? targetFile : targetFile.getParentFile());
114+
ensureDirectoryExists(activity, isDirectory ? targetFile : targetFile.getParentFile());
114115

115116
if (!isDirectory) {
116117
try (FileOutputStream outStream = new FileOutputStream(targetFile)) {
@@ -151,7 +152,7 @@ public void run() {
151152
activity.finish();
152153
}).setPositiveButton(R.string.bootstrap_error_try_again, (dialog, which) -> {
153154
dialog.dismiss();
154-
TermuxInstaller.setupIfNeeded(activity, whenDone);
155+
TermuxInstaller.setupBootstrapIfNeeded(activity, whenDone);
155156
}).show();
156157
} catch (WindowManager.BadTokenException e1) {
157158
// Activity already dismissed - ignore.
@@ -170,37 +171,6 @@ public void run() {
170171
}.start();
171172
}
172173

173-
private static void ensureDirectoryExists(File directory) {
174-
if (!directory.isDirectory() && !directory.mkdirs()) {
175-
throw new RuntimeException("Unable to create directory: " + directory.getAbsolutePath());
176-
}
177-
}
178-
179-
public static byte[] loadZipBytes() {
180-
// Only load the shared library when necessary to save memory usage.
181-
System.loadLibrary("termux-bootstrap");
182-
return getZip();
183-
}
184-
185-
public static native byte[] getZip();
186-
187-
/** Delete a directory and all its content or throw. Don't follow symlinks. */
188-
static void deleteDirectory(File fileOrDirectory) throws IOException {
189-
if (fileOrDirectory.getCanonicalPath().equals(fileOrDirectory.getAbsolutePath()) && fileOrDirectory.isDirectory()) {
190-
File[] children = fileOrDirectory.listFiles();
191-
192-
if (children != null) {
193-
for (File child : children) {
194-
deleteDirectory(child);
195-
}
196-
}
197-
}
198-
199-
if (!fileOrDirectory.delete()) {
200-
throw new RuntimeException("Unable to delete " + (fileOrDirectory.isDirectory() ? "directory " : "file ") + fileOrDirectory.getAbsolutePath());
201-
}
202-
}
203-
204174
static void setupStorageSymlinks(final Context context) {
205175
final String LOG_TAG = "termux-storage";
206176

@@ -209,19 +179,12 @@ static void setupStorageSymlinks(final Context context) {
209179
new Thread() {
210180
public void run() {
211181
try {
182+
String errmsg;
212183
File storageDir = TermuxConstants.TERMUX_STORAGE_HOME_DIR;
213184

214-
if (storageDir.exists()) {
215-
try {
216-
deleteDirectory(storageDir);
217-
} catch (IOException e) {
218-
Logger.logStackTraceWithMessage(LOG_TAG, "Failed to delete old ~/storage directory", e);
219-
return;
220-
}
221-
}
222-
223-
if (!storageDir.mkdirs()) {
224-
Logger.logError(LOG_TAG, "Unable to create ~/storage directory.");
185+
errmsg = FileUtils.clearDirectory(context, "~/storage", storageDir.getAbsolutePath());
186+
if (errmsg != null) {
187+
Logger.logErrorAndShowToast(context, LOG_TAG, errmsg);
225188
return;
226189
}
227190

@@ -264,4 +227,21 @@ public void run() {
264227
}.start();
265228
}
266229

230+
private static void ensureDirectoryExists(Context context, File directory) {
231+
String errmsg;
232+
233+
errmsg = FileUtils.createDirectoryFile(context, directory.getAbsolutePath());
234+
if (errmsg != null) {
235+
throw new RuntimeException(errmsg);
236+
}
237+
}
238+
239+
public static byte[] loadZipBytes() {
240+
// Only load the shared library when necessary to save memory usage.
241+
System.loadLibrary("termux-bootstrap");
242+
return getZip();
243+
}
244+
245+
public static native byte[] getZip();
246+
267247
}

0 commit comments

Comments
 (0)