aboutsummaryrefslogtreecommitdiffstats
path: root/ddms
diff options
context:
space:
mode:
authorOmari Stephens <xsdg@android.com>2012-08-23 17:48:54 -0700
committerOmari Stephens <xsdg@android.com>2012-08-23 18:51:44 -0700
commitec23849f42a2fe33a15152fa326977f738546b6d (patch)
tree9c6a965fc5e122873a3a02ca9fcca19a4325e10f /ddms
parent1933bff778c986e4de21efcad3a041db61836efa (diff)
downloadsdk-ec23849f42a2fe33a15152fa326977f738546b6d.zip
sdk-ec23849f42a2fe33a15152fa326977f738546b6d.tar.gz
sdk-ec23849f42a2fe33a15152fa326977f738546b6d.tar.bz2
Enable FileListingService to properly traverse symlinks-to-directories
Bug: 7048633 Change-Id: I85d4780286a663ab75555049f21b7215e45870d0
Diffstat (limited to 'ddms')
-rw-r--r--ddms/libs/ddmlib/src/com/android/ddmlib/FileListingService.java76
1 files changed, 68 insertions, 8 deletions
diff --git a/ddms/libs/ddmlib/src/com/android/ddmlib/FileListingService.java b/ddms/libs/ddmlib/src/com/android/ddmlib/FileListingService.java
index d731a4d..97c57b9 100644
--- a/ddms/libs/ddmlib/src/com/android/ddmlib/FileListingService.java
+++ b/ddms/libs/ddmlib/src/com/android/ddmlib/FileListingService.java
@@ -88,8 +88,13 @@ public final class FileListingService {
/**
* Regexp pattern to parse the result from ls.
*/
- private static Pattern sLsPattern = Pattern.compile(
- "^([bcdlsp-][-r][-w][-xsS][-r][-w][-xsS][-r][-w][-xstST])\\s+(\\S+)\\s+(\\S+)\\s+([\\d\\s,]*)\\s+(\\d{4}-\\d\\d-\\d\\d)\\s+(\\d\\d:\\d\\d)\\s+(.*)$"); //$NON-NLS-1$
+ private static final Pattern LS_L_PATTERN = Pattern.compile(
+ "^([bcdlsp-][-r][-w][-xsS][-r][-w][-xsS][-r][-w][-xstST])\\s+(\\S+)\\s+(\\S+)\\s+" +
+ "([\\d\\s,]*)\\s+(\\d{4}-\\d\\d-\\d\\d)\\s+(\\d\\d:\\d\\d)\\s+(.*)$"); //$NON-NLS-1$
+
+ private static final Pattern LS_LD_PATTERN = Pattern.compile(
+ "d[rwx-]{9}\\s+\\S+\\s+\\S+\\s+[0-9-]{10}\\s+\\d{2}:\\d{2}$"); //$NON-NLS-1$
+
private Device mDevice;
private FileEntry mRoot;
@@ -261,13 +266,20 @@ public final class FileListingService {
}
/**
- * Returns true if the entry is a directory, false otherwise;
+ * Returns the Entry type as an int, which will match one of the TYPE_(...) constants
*/
public int getType() {
return type;
}
/**
+ * Sets a new type.
+ */
+ public void setType(int type) {
+ this.type = type;
+ }
+
+ /**
* Returns if the entry is a folder or a link to a folder.
*/
public boolean isDirectory() {
@@ -404,7 +416,7 @@ public final class FileListingService {
}
}
- private class LsReceiver extends MultiLineReceiver {
+ private static class LsReceiver extends MultiLineReceiver {
private ArrayList<FileEntry> mEntryList;
private ArrayList<String> mLinkList;
@@ -438,7 +450,7 @@ public final class FileListingService {
}
// run the line through the regexp
- Matcher m = sLsPattern.matcher(line);
+ Matcher m = LS_L_PATTERN.matcher(line);
if (m.matches() == false) {
continue;
}
@@ -567,8 +579,50 @@ public final class FileListingService {
return false;
}
- public void finishLinks() {
- // TODO Handle links in the listing service
+ /**
+ * Determine if any symlinks in the <code entries> list are links-to-directories, and if so
+ * mark them as such. This allows us to traverse them properly later on.
+ */
+ public void finishLinks(IDevice device, ArrayList<FileEntry> entries)
+ throws TimeoutException, AdbCommandRejectedException,
+ ShellCommandUnresponsiveException, IOException {
+ final int[] nLines = {0};
+ MultiLineReceiver receiver = new MultiLineReceiver() {
+ @Override
+ public void processNewLines(String[] lines) {
+ for (String line : lines) {
+ Matcher m = LS_LD_PATTERN.matcher(line);
+ if (m.matches()) {
+ nLines[0]++;
+ }
+ }
+ }
+
+ @Override
+ public boolean isCancelled() {
+ return false;
+ }
+ };
+
+ for (FileEntry entry : entries) {
+ if (entry.getType() != TYPE_LINK) continue;
+
+ // We simply need to determine whether the referent is a directory or not.
+ // We do this by running `ls -ld ${link}/`. If the referent exists and is a
+ // directory, we'll see the normal directory listing. Otherwise, we'll see an
+ // error of some sort.
+ nLines[0] = 0;
+
+ final String command = String.format("ls -l -d %s%s", entry.getFullEscapedPath(),
+ FILE_SEPARATOR);
+
+ device.executeShellCommand(command, receiver);
+
+ if (nLines[0] > 0) {
+ // We saw lines matching the directory pattern, so it's a directory!
+ entry.setType(TYPE_DIRECTORY_LINK);
+ }
+ }
}
}
@@ -773,6 +827,12 @@ public final class FileListingService {
try {
// create the command
String command = "ls -l " + entry.getFullEscapedPath(); //$NON-NLS-1$
+ if (entry.isDirectory()) {
+ // If we expect a file to behave like a directory, we should stick a "/" at the end.
+ // This is a good habit, and is mandatory for symlinks-to-directories, which will
+ // otherwise behave like symlinks.
+ command += FILE_SEPARATOR;
+ }
// create the receiver object that will parse the result from ls
LsReceiver receiver = new LsReceiver(entry, entryList, linkList);
@@ -781,7 +841,7 @@ public final class FileListingService {
mDevice.executeShellCommand(command, receiver);
// finish the process of the receiver to handle links
- receiver.finishLinks();
+ receiver.finishLinks(mDevice, entryList);
} finally {
// at this point we need to refresh the viewer
entry.fetchTime = System.currentTimeMillis();