Chromium Code Reviews| Index: runtime/bin/directory_android.cc |
| diff --git a/runtime/bin/directory_android.cc b/runtime/bin/directory_android.cc |
| index f3f471fd0e21594fddde6158711f2a0c8013f06f..90d95f9d19a64c402c9ef16853db671748997425 100644 |
| --- a/runtime/bin/directory_android.cc |
| +++ b/runtime/bin/directory_android.cc |
| @@ -13,12 +13,35 @@ |
| #include "bin/file.h" |
| #include "bin/platform.h" |
| +class PathBuffer { |
| + public: |
| + PathBuffer() : length(0) { } |
| + |
| + |
| + |
| + char data[PATH_MAX + 1]; |
| + int length; |
| + |
| + bool Add(const char* name) { |
| + size_t written = snprintf(data + length, |
| + PATH_MAX - length, |
| + "%s", |
| + name); |
| + data[PATH_MAX] = '\0'; |
| + if (written == strnlen(name, PATH_MAX + 1)) { |
| + length += written; |
| + return true; |
| + } else { |
| + return false; |
|
Søren Gjesse
2013/02/08 08:49:29
I think we should try to set errno to something he
Bill Hesse
2013/02/08 12:11:37
Done. Also, call PostError in places where this r
|
| + } |
| + } |
| + |
| + void Reset(int new_length) { |
| + length = new_length; |
| + data[length] = '\0'; |
| + } |
| +}; |
| -static char* SafeStrNCpy(char* dest, const char* src, size_t n) { |
| - strncpy(dest, src, n); |
| - dest[n - 1] = '\0'; |
| - return dest; |
| -} |
| // Forward declarations. |
| @@ -28,67 +51,42 @@ static bool ListRecursively(const char* dir_name, |
| static bool DeleteRecursively(const char* dir_name); |
| -static bool ComputeFullPath(const char* dir_name, |
| - char* path, |
| - int* path_length) { |
| +static PathBuffer* ComputeFullPath(const char* dir_name) { |
| + PathBuffer* path = new PathBuffer(); |
| char* abs_path; |
| do { |
| - abs_path = realpath(dir_name, path); |
| + abs_path = realpath(dir_name, path->data); |
| } while (abs_path == NULL && errno == EINTR); |
| if (abs_path == NULL) { |
| - return false; |
| + delete path; |
| + return NULL; |
| } |
| - *path_length = strlen(path); |
| - size_t written = snprintf(path + *path_length, |
| - PATH_MAX - *path_length, |
| - "%s", |
| - File::PathSeparator()); |
| - if (written != strlen(File::PathSeparator())) { |
| - return false; |
| + path->length = strnlen(path->data, PATH_MAX); |
| + if (path->Add(File::PathSeparator())) { |
| + return path; |
| + } else { |
| + delete path; |
| + return NULL; |
| } |
| - *path_length += written; |
| - return true; |
| } |
| - |
| static bool HandleDir(char* dir_name, |
| - char* path, |
| - int path_length, |
| + PathBuffer* path, |
| bool recursive, |
| DirectoryListing *listing) { |
| - if (strcmp(dir_name, ".") != 0 && |
| - strcmp(dir_name, "..") != 0) { |
| - size_t written = snprintf(path + path_length, |
| - PATH_MAX - path_length, |
| - "%s", |
| - dir_name); |
| - if (written != strlen(dir_name)) { |
| - return false; |
| - } |
| - bool ok = listing->HandleDirectory(path); |
| - if (!ok) return ok; |
| - if (recursive) { |
| - return ListRecursively(path, recursive, listing); |
| - } |
| - } |
| - return true; |
| + if (strcmp(dir_name, ".") == 0) return true; |
| + if (strcmp(dir_name, "..") == 0) return true; |
| + return path->Add(dir_name) && |
| + listing->HandleDirectory(path->data) && |
| + (!recursive || ListRecursively(path->data, recursive, listing)); |
| } |
| - |
| static bool HandleFile(char* file_name, |
| - char* path, |
| - int path_length, |
| + PathBuffer* path, |
| DirectoryListing *listing) { |
| // TODO(sgjesse): Pass flags to indicate whether file responses are |
| // needed. |
| - size_t written = snprintf(path + path_length, |
| - PATH_MAX - path_length, |
| - "%s", |
| - file_name); |
| - if (written != strlen(file_name)) { |
| - return false; |
| - } |
| - return listing->HandleFile(path); |
| + return path->Add(file_name) && listing->HandleFile(path->data); |
| } |
| @@ -115,38 +113,32 @@ static bool ListRecursively(const char* dir_name, |
| // recursive traversal. path_length does not always equal |
| // strlen(path) but indicates the current prefix of path that is the |
| // path of the current directory in the traversal. |
| - char *path = static_cast<char*>(malloc(PATH_MAX)); |
| - ASSERT(path != NULL); |
| - int path_length = 0; |
| - bool valid = ComputeFullPath(dir_name, path, &path_length); |
| - if (!valid) { |
| - free(path); |
| + PathBuffer* path = ComputeFullPath(dir_name); |
| + if (path == NULL) { |
| PostError(listing, dir_name); |
| return false; |
| } |
| - |
| - // Iterated the directory and post the directories and files to the |
| + // Iterate the directory and post the directories and files to the |
| // ports. |
| - int read = 0; |
| + int path_length = path->length; |
| + int status = 0; |
| bool success = true; |
| dirent entry; |
| dirent* result; |
| - while ((read = TEMP_FAILURE_RETRY(readdir_r(dir_pointer, |
| - &entry, |
| - &result))) == 0 && |
| + while ((status = TEMP_FAILURE_RETRY(readdir_r(dir_pointer, |
| + &entry, |
| + &result))) == 0 && |
| result != NULL) { |
| switch (entry.d_type) { |
| case DT_DIR: |
| success = HandleDir(entry.d_name, |
| path, |
| - path_length, |
| recursive, |
| listing) && success; |
| break; |
| case DT_REG: |
| success = HandleFile(entry.d_name, |
| path, |
| - path_length, |
| listing) && success; |
| break; |
| case DT_LNK: |
| @@ -156,30 +148,25 @@ static bool ListRecursively(const char* dir_name, |
| // the actual entry type. Notice that stat returns the type of |
| // the file pointed to. |
| struct stat entry_info; |
| - size_t written = snprintf(path + path_length, |
| - PATH_MAX - path_length, |
| - "%s", |
| - entry.d_name); |
| - if (written != strlen(entry.d_name)) { |
| + if (!path->Add(entry.d_name)) { |
| success = false; |
| break; |
| } |
| - int stat_success = TEMP_FAILURE_RETRY(stat(path, &entry_info)); |
| + int stat_success = TEMP_FAILURE_RETRY(stat(path->data, &entry_info)); |
| if (stat_success == -1) { |
| success = false; |
| - PostError(listing, path); |
| + PostError(listing, path->data); |
| break; |
| } |
| + path->Reset(path_length); |
| if (S_ISDIR(entry_info.st_mode)) { |
| success = HandleDir(entry.d_name, |
| path, |
| - path_length, |
| recursive, |
| listing) && success; |
| } else if (S_ISREG(entry_info.st_mode)) { |
| success = HandleFile(entry.d_name, |
| path, |
| - path_length, |
| listing) && success; |
| } |
| ASSERT(!S_ISLNK(entry_info.st_mode)); |
| @@ -188,10 +175,11 @@ static bool ListRecursively(const char* dir_name, |
| default: |
| break; |
| } |
| + path->Reset(path_length); |
| } |
| - if (read != 0) { |
| - errno = read; |
| + if (status != 0) { |
| + errno = status; |
| success = false; |
| PostError(listing, dir_name); |
| } |
| @@ -200,41 +188,23 @@ static bool ListRecursively(const char* dir_name, |
| success = false; |
| PostError(listing, dir_name); |
| } |
| - free(path); |
| + delete path; |
| return success; |
| } |
| static bool DeleteFile(char* file_name, |
| - char* path, |
| - int path_length) { |
| - size_t written = snprintf(path + path_length, |
| - PATH_MAX - path_length, |
| - "%s", |
| - file_name); |
| - if (written != strlen(file_name)) { |
| - return false; |
| - } |
| - return (remove(path) == 0); |
| + PathBuffer* path) { |
| + return path->Add(file_name) && remove(path->data) == 0; |
| } |
| static bool DeleteDir(char* dir_name, |
| - char* path, |
| - int path_length) { |
| - if (strcmp(dir_name, ".") != 0 && |
| - strcmp(dir_name, "..") != 0) { |
| - size_t written = snprintf(path + path_length, |
| - PATH_MAX - path_length, |
| - "%s", |
| - dir_name); |
| - if (written != strlen(dir_name)) { |
| - return false; |
| - } |
| - return DeleteRecursively(path); |
| - } |
| - return true; |
| + PathBuffer* path) { |
| + if (strcmp(dir_name, ".") == 0) return true; |
| + if (strcmp(dir_name, "..") == 0) return true; |
| + return path->Add(dir_name) && DeleteRecursively(path->data); |
| } |
| @@ -260,19 +230,12 @@ static bool DeleteRecursively(const char* dir_name) { |
| // Compute full path for the directory currently being deleted. The |
| // path buffer will be used to construct the current path in the |
| - // recursive traversal. path_length does not always equal |
| - // strlen(path) but indicates the current prefix of path that is the |
| - // path of the current directory in the traversal. |
| - char *path = static_cast<char*>(malloc(PATH_MAX)); |
| - ASSERT(path != NULL); |
| - int path_length = 0; |
| - bool valid = ComputeFullPath(dir_name, path, &path_length); |
| - if (!valid) { |
| - free(path); |
| - return false; |
| - } |
| + // recursive traversal. |
| + PathBuffer* path = ComputeFullPath(dir_name); |
| + if (path == NULL) return false; |
| // Iterate the directory and delete all files and directories. |
| + int path_length = path->length; |
| int read = 0; |
| bool success = true; |
| dirent entry; |
| @@ -284,49 +247,46 @@ static bool DeleteRecursively(const char* dir_name) { |
| success) { |
| switch (entry.d_type) { |
| case DT_DIR: |
| - success = success && DeleteDir(entry.d_name, path, path_length); |
| + success = success && DeleteDir(entry.d_name, path); |
| break; |
| case DT_REG: |
| case DT_LNK: |
| // Treat all links as files. This will delete the link which |
| // is what we want no matter if the link target is a file or a |
| // directory. |
| - success = success && DeleteFile(entry.d_name, path, path_length); |
| + success = success && DeleteFile(entry.d_name, path); |
| break; |
| case DT_UNKNOWN: { |
| // On some file systems the entry type is not determined by |
| // readdir_r. For those we use lstat to determine the entry |
| // type. |
| struct stat entry_info; |
| - size_t written = snprintf(path + path_length, |
| - PATH_MAX - path_length, |
| - "%s", |
| - entry.d_name); |
| - if (written != strlen(entry.d_name)) { |
| + if (!path->Add(entry.d_name)) { |
| success = false; |
| break; |
| } |
| - int lstat_success = TEMP_FAILURE_RETRY(lstat(path, &entry_info)); |
| + int lstat_success = TEMP_FAILURE_RETRY(lstat(path->data, &entry_info)); |
| if (lstat_success == -1) { |
| success = false; |
| break; |
| } |
| + path->Reset(path_length); |
| if (S_ISDIR(entry_info.st_mode)) { |
| - success = success && DeleteDir(entry.d_name, path, path_length); |
| + success = success && DeleteDir(entry.d_name, path); |
| } else if (S_ISREG(entry_info.st_mode) || S_ISLNK(entry_info.st_mode)) { |
| // Treat links as files. This will delete the link which is |
| // what we want no matter if the link target is a file or a |
| // directory. |
| - success = success && DeleteFile(entry.d_name, path, path_length); |
| + success = success && DeleteFile(entry.d_name, path); |
| } |
| break; |
| } |
| default: |
| break; |
| } |
| + path->Reset(path_length); |
| } |
| - |
| - free(path); |
| + delete path; |
| if ((read != 0) || |
| (closedir(dir_pointer) == -1) || |
| @@ -393,7 +353,7 @@ bool Directory::Create(const char* dir_name) { |
| // process umask. |
| int result = TEMP_FAILURE_RETRY(mkdir(dir_name, 0777)); |
| // If the directory already exists, treat it as a success. |
| - if (result == -1 && errno == EEXISTS) { |
| + if (result == -1 && errno == EEXIST) { |
| return (Exists(dir_name) == EXISTS); |
| } |
| return (result == 0); |
| @@ -418,16 +378,9 @@ char* Directory::CreateTemp(const char* const_template) { |
| // dir_template. Creates the directory with the permissions specified |
| // by the process umask. |
| // The return value must be freed by the caller. |
| - char* path = static_cast<char*>(malloc(PATH_MAX + 1)); |
| - SafeStrNCpy(path, const_template, PATH_MAX + 1); |
| - int path_length = strlen(path); |
| - if (path_length > 0) { |
| - if ((path)[path_length - 1] == '/') { |
| - snprintf(path + path_length, PATH_MAX - path_length, "temp_dir_XXXXXX"); |
| - } else { |
| - snprintf(path + path_length, PATH_MAX - path_length, "XXXXXX"); |
| - } |
| - } else { |
| + PathBuffer* path = new PathBuffer(); |
| + path->Add(const_template); |
| + if (path->length == 0) { |
| // Android does not have a /tmp directory. A partial substitute, |
| // suitable for bring-up work and tests, is to create a tmp |
| // directory in /data/local/tmp. |
| @@ -439,17 +392,29 @@ char* Directory::CreateTemp(const char* const_template) { |
| if (stat(ANDROID_TEMP_DIR, &st) != 0) { |
| mkdir(ANDROID_TEMP_DIR, 0777); |
| } |
| - snprintf(path, PATH_MAX, ANDROID_TEMP_DIR "/temp_dir1_XXXXXX"); |
| + path->Add(ANDROID_TEMP_DIR "/tmp/temp_dir1_"); |
| + } else if ((path->data)[path->length - 1] == '/') { |
| + path->Add("temp_dir_"); |
| + } |
| + if (!path->Add("XXXXXX")) { |
| + // Pattern has overflowed. |
| + delete path; |
| + return NULL; |
| } |
| char* result; |
| do { |
| - result = MakeTempDirectory(path); |
| + result = MakeTempDirectory(path->data); |
| } while (result == NULL && errno == EINTR); |
| if (result == NULL) { |
| - free(path); |
| + delete path; |
| return NULL; |
| } |
| - return path; |
| + int length = strnlen(path->data, PATH_MAX); |
| + result = static_cast<char*>(malloc(length + 1)); |
| + strncpy(result, path->data, length); |
| + result[length] = '\0'; |
| + delete path; |
| + return result; |
| } |