blob: 90041317635f8f256aaeba5ce2ae07c1bb885421 [file] [log] [blame]
// 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