Merge "Improved how the Shell directories are created."
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 054db74..22fd2c3 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -368,6 +368,10 @@
 
 /* adds a new entry to the existing zip file. */
 static bool add_zip_entry_from_fd(const std::string& entry_name, int fd) {
+    if (!zip_writer) {
+        ALOGD("Not adding zip entry %s from fd because zip_writer is not set", entry_name.c_str());
+        return false;
+    }
     ALOGD("Adding zip entry %s", entry_name.c_str());
     int32_t err = zip_writer->StartEntryWithTime(entry_name.c_str(),
             ZipWriter::kCompress, get_mtime(fd, now));
@@ -420,14 +424,21 @@
 
 /* adds all files from a directory to the zipped bugreport file */
 void add_dir(const char *dir, bool recursive) {
-    if (!zip_writer) return;
+    if (!zip_writer) {
+        ALOGD("Not adding dir %s because zip_writer is not set", dir);
+        return;
+    }
     DurationReporter duration_reporter(dir, NULL);
     dump_files(NULL, dir, recursive ? skip_none : is_dir, _add_file_from_fd);
 }
 
 /* adds a text entry entry to the existing zip file. */
 static bool add_text_zip_entry(const std::string& entry_name, const std::string& content) {
-    ALOGD("Adding zip text entry %s (%s)", entry_name.c_str(), content.c_str());
+    if (!zip_writer) {
+        ALOGD("Not adding text zip entry %s because zip_writer is not set", entry_name.c_str());
+        return false;
+    }
+    ALOGD("Adding zip text entry %s", entry_name.c_str());
     int32_t err = zip_writer->StartEntryWithTime(entry_name.c_str(), ZipWriter::kCompress, now);
     if (err) {
         ALOGE("zip_writer->StartEntryWithTime(%s): %s\n", entry_name.c_str(),
@@ -772,7 +783,7 @@
             "  -s: write output to control socket (for init)\n"
             "  -q: disable vibrate\n"
             "  -B: send broadcast when finished (requires -o)\n"
-            "  -P: send broadacast when started and update system properties on progress (requires -o and -B)\n"
+            "  -P: send broadcast when started and update system properties on progress (requires -o and -B)\n"
             "  -R: take bugreport in remote mode (requires -o, -z, -d and -B, shouldn't be used with -P)\n"
             "  -V: sets the bugreport format version (%s or %s)\n",
             VERSION_DEFAULT.c_str(), VERSION_DUMPSYS_SPLIT.c_str());
@@ -794,6 +805,7 @@
     }
     if (!add_text_zip_entry("main_entry.txt", bugreport_name)) {
         ALOGE("Failed to add main_entry.txt to .zip file\n");
+        return false;
     }
 
     int32_t err = zip_writer->Finish();
@@ -1027,6 +1039,7 @@
         if (do_zip_file) {
             ALOGD("Creating initial .zip file");
             path = bugreport_dir + "/" + base_name + "-" + suffix + ".zip";
+            create_parent_dirs(path.c_str());
             zip_file.reset(fopen(path.c_str(), "wb"));
             if (!zip_file) {
                 ALOGE("fopen(%s, 'wb'): %s\n", path.c_str(), strerror(errno));
diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h
index 8332d22..a6afbf4 100644
--- a/cmds/dumpstate/dumpstate.h
+++ b/cmds/dumpstate/dumpstate.h
@@ -112,6 +112,9 @@
 /* redirect output to a file */
 void redirect_to_file(FILE *redirect, char *path);
 
+/* create leading directories, if necessary */
+void create_parent_dirs(const char *path);
+
 /* dump Dalvik and native stack traces, return the trace file location (NULL if none) */
 const char *dump_traces();
 
diff --git a/cmds/dumpstate/utils.cpp b/cmds/dumpstate/utils.cpp
index ee60f57..0c35430 100644
--- a/cmds/dumpstate/utils.cpp
+++ b/cmds/dumpstate/utils.cpp
@@ -657,23 +657,35 @@
     close(fd);
 }
 
-/* redirect output to a file */
-void redirect_to_file(FILE *redirect, char *path) {
-    char *chp = path;
+void create_parent_dirs(const char *path) {
+    char *chp = (char*) path;
 
     /* skip initial slash */
     if (chp[0] == '/')
         chp++;
 
     /* create leading directories, if necessary */
+    struct stat dir_stat;
     while (chp && chp[0]) {
         chp = strchr(chp, '/');
         if (chp) {
             *chp = 0;
-            mkdir(path, 0770);  /* drwxrwx--- */
+            if (stat(path, &dir_stat) == -1 || !S_ISDIR(dir_stat.st_mode)) {
+                ALOGI("Creating directory %s\n", path);
+                if (mkdir(path, 0770)) { /* drwxrwx--- */
+                    ALOGE("Unable to create directory %s: %s\n", path, strerror(errno));
+                } else if (chown(path, AID_SHELL, AID_SHELL)) {
+                    ALOGE("Unable to change ownership of dir %s: %s\n", path, strerror(errno));
+                }
+            }
             *chp++ = '/';
         }
     }
+}
+
+/* redirect output to a file */
+void redirect_to_file(FILE *redirect, char *path) {
+    create_parent_dirs(path);
 
     int fd = TEMP_FAILURE_RETRY(open(path, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW,
                                      S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH));