| // Copyright 2016 The Fuchsia Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| #include "src/lib/files/directory.h" | |
| #include <dirent.h> | |
| #include <errno.h> | |
| #include <fcntl.h> | |
| #include <limits.h> | |
| #include <sys/stat.h> | |
| #include <unistd.h> | |
| #include <string> | |
| #include <vector> | |
| #include "src/lib/files/path.h" | |
| namespace files { | |
| std::string GetCurrentDirectory() { | |
| char buffer[PATH_MAX]; | |
| if (!getcwd(buffer, sizeof(buffer))) { | |
| // Failed to get cwd | |
| abort(); | |
| } | |
| return std::string(buffer); | |
| } | |
| bool IsDirectory(const std::string& path) { return IsDirectoryAt(AT_FDCWD, path); } | |
| bool IsDirectoryAt(int root_fd, const std::string& path) { | |
| struct stat buf; | |
| if (fstatat(root_fd, path.c_str(), &buf, 0) != 0) | |
| return false; | |
| return S_ISDIR(buf.st_mode); | |
| } | |
| bool CreateDirectory(const std::string& full_path) { | |
| return CreateDirectoryAt(AT_FDCWD, full_path); | |
| } | |
| bool CreateDirectoryAt(int root_fd, const std::string& full_path) { | |
| std::vector<std::string> subpaths; | |
| // Collect a list of all parent directories. | |
| std::string last_path = full_path; | |
| subpaths.push_back(full_path); | |
| for (std::string path = GetDirectoryName(full_path); !path.empty() && path != last_path; | |
| path = GetDirectoryName(path)) { | |
| subpaths.push_back(path); | |
| last_path = path; | |
| } | |
| // Iterate through the parents and create the missing ones. | |
| for (auto it = subpaths.rbegin(); it != subpaths.rend(); ++it) { | |
| if (IsDirectoryAt(root_fd, *it)) | |
| continue; | |
| if (mkdirat(root_fd, it->c_str(), 0700) == 0) | |
| continue; | |
| // Mkdir failed, but it might be due to the directory appearing out of thin | |
| // air. This can occur if two processes are trying to create the same file | |
| // system tree at the same time. Check to see if it exists and make sure it | |
| // is a directory. | |
| if (!IsDirectoryAt(root_fd, *it)) | |
| return false; | |
| } | |
| return true; | |
| } | |
| bool ReadDirContents(const std::string& path, std::vector<std::string>* out) { | |
| return ReadDirContentsAt(AT_FDCWD, path, out); | |
| } | |
| bool ReadDirContentsAt(int root_fd, const std::string& path, std::vector<std::string>* out) { | |
| out->clear(); | |
| int fd = openat(root_fd, path.c_str(), O_RDONLY | O_DIRECTORY); | |
| if (fd < 0) { | |
| return false; | |
| } | |
| DIR* dir = fdopendir(fd); | |
| if (!dir) { | |
| close(fd); | |
| return false; | |
| } | |
| struct dirent* de; | |
| errno = 0; | |
| while ((de = readdir(dir)) != nullptr) { | |
| out->push_back(de->d_name); | |
| } | |
| closedir(dir); | |
| return !errno; | |
| } | |
| } // namespace files |