// Copyright 2018 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 "fixture.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace fuzzing { namespace testing { // Public methods Fixture::~Fixture() { Reset(); } fbl::String Fixture::path(const char* fmt, ...) const { va_list ap; va_start(ap, fmt); fbl::String result = path(fmt, ap); va_end(ap); return result; } fbl::String Fixture::path(const char* fmt, va_list ap) const { if (!fmt) { return root_; } fbl::StringBuffer buffer; buffer.AppendVPrintf(fmt, ap); fbl::String relpath = buffer.ToString(); if (relpath[0] == '/') { return relpath; } buffer.Clear(); buffer.Append(root_); buffer.Append(relpath); return buffer.ToString(); } // Protected methods Fixture::Fixture() {} bool Fixture::Create() { BEGIN_HELPER; Reset(); uint64_t randnum; zx_cprng_draw(&randnum, sizeof(randnum)); root_ = fbl::StringPrintf("/tmp/path-unit-test-%" PRIu64 "/", randnum); ASSERT_TRUE(CreateDirectory(nullptr)); END_HELPER; } bool Fixture::CreateFile(const char* pathname, const char* contents) { BEGIN_HELPER; ASSERT_NONNULL(pathname); fbl::String local = path(pathname); pathname = local.c_str(); const char* sep = strrchr(pathname, '/'); fbl::String basename(pathname, sep - pathname); ASSERT_TRUE(CreateDirectory(basename.c_str())); fbl::unique_fd fd(open(pathname, O_RDWR | O_CREAT, 0777)); ASSERT_TRUE(!!fd); if (contents) { ASSERT_GE(write(fd.get(), contents, strlen(contents) + 1), 0); } END_HELPER; } bool Fixture::CreateDirectory(const char* pathname) { BEGIN_HELPER; fbl::String local = path(pathname); pathname = local.c_str(); struct stat buf; if (stat(pathname, &buf) == 0) { ASSERT_TRUE(S_ISDIR(buf.st_mode)); } else { ASSERT_EQ(errno, ENOENT); // Trim trailing slashes size_t len = strlen(pathname); while (len > 0 && pathname[len - 1] == '/') { --len; } local.Set(pathname, len); pathname = local.c_str(); // Find last segment const char* sep = strrchr(pathname, '/'); ASSERT_NONNULL(sep); fbl::String basename(pathname, sep - pathname); ASSERT_TRUE(CreateDirectory(basename.c_str())); ASSERT_GE(mkdir(pathname, 0777), 0); } END_HELPER; } bool Fixture::RemoveDirectory(const char* pathname) { BEGIN_HELPER; ASSERT_NONNULL(pathname); char buffer[PATH_MAX]; DIR* dir = opendir(pathname); if (dir) { struct dirent* ent; while ((ent = readdir(dir))) { if (strcmp(".", ent->d_name) == 0) { continue; } snprintf(buffer, sizeof(buffer), "%s/%s", pathname, ent->d_name); if (ent->d_type == DT_DIR) { EXPECT_TRUE(RemoveDirectory(buffer)); } else { EXPECT_GE(unlink(buffer), 0); } } closedir(dir); EXPECT_GE(rmdir(pathname), 0); } END_HELPER; } void Fixture::Reset() { if (!root_.empty()) { RemoveDirectory(root_.c_str()); } root_.clear(); unsafe_.clear(); } } // namespace testing } // namespace fuzzing