You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficserver.apache.org by dr...@apache.org on 2018/09/20 16:13:53 UTC
[trafficserver] branch master updated: ts_file: Simple sketch of
std::filesystem for internal use.
This is an automated email from the ASF dual-hosted git repository.
dragon pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/trafficserver.git
The following commit(s) were added to refs/heads/master by this push:
new 8c6be99 ts_file: Simple sketch of std::filesystem for internal use.
8c6be99 is described below
commit 8c6be99dbe637101561a806a8ea5756ec5804ea7
Author: Alan M. Carroll <am...@apache.org>
AuthorDate: Wed Sep 12 09:49:37 2018 -0500
ts_file: Simple sketch of std::filesystem for internal use.
---
include/tscore/ts_file.h | 247 ++++++++++++++++++++++++++++++++++
src/tscore/Makefile.am | 4 +-
src/tscore/ts_file.cc | 126 +++++++++++++++++
src/tscore/unit_tests/test_ts_file.cc | 69 ++++++++++
4 files changed, 445 insertions(+), 1 deletion(-)
diff --git a/include/tscore/ts_file.h b/include/tscore/ts_file.h
new file mode 100644
index 0000000..0d2ecf9
--- /dev/null
+++ b/include/tscore/ts_file.h
@@ -0,0 +1,247 @@
+/** @file
+
+ Simple path and file utilities.
+
+ @section license License
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ */
+
+#pragma once
+
+#include <string>
+#include <string_view>
+#include <array>
+#include <system_error>
+#include <sys/stat.h>
+#include "tscore/ink_memory.h"
+#include "tscpp/util/TextView.h"
+#include "tscore/BufferWriter.h"
+
+namespace ts
+{
+namespace file
+{
+ /** Utility class for file system paths.
+ */
+ class path
+ {
+ using self_type = path;
+
+ public:
+ using value_type = char;
+ using string_type = std::string;
+ static constexpr char preferred_separator = value_type{'/'};
+
+ /// Default construct empty path.
+ path() = default;
+
+ /// Copy constructor - copies the path.
+ path(const self_type &that) = default;
+
+ /// Move constructor.
+ path(self_type &&that) = default;
+
+ /// Construct from a null terminated string.
+ explicit path(const char *src);
+
+ /// Construct from a string view.
+ path(std::string_view src);
+ // template < typename ... Args > explicit path(std::string_view base, Args... rest);
+
+ /// Move from an existing string
+ path(std::string &&that);
+
+ /// Replace the path with a copy of @a that.
+ self_type &operator=(const self_type &that) = default;
+
+ /// Replace the path with the contents of @a that.
+ self_type &operator=(self_type &&that) = default;
+
+ /// Assign @a p as the path.
+ self_type &operator=(std::string_view p);
+
+ /** Append or replace path with @a that.
+ *
+ * If @a that is absolute, it replaces @a this. Otherwise @a that is appended with exactly one
+ * separator.
+ *
+ * @param that Filesystem path.
+ * @return @a this
+ */
+ self_type &operator/=(const self_type &that);
+ self_type &operator/=(std::string_view that);
+
+ /// Check if the path is empty.
+ bool empty() const;
+
+ /// Check if the path is absolute.
+ bool is_absolute() const;
+
+ /// Check if the path is not absolute.
+ bool is_relative() const;
+
+ /// Access the path explicitly.
+ char const *c_str() const;
+
+ /// Get a copy of the path.
+ std::string string() const;
+
+ protected:
+ std::string _path; ///< File path.
+ };
+
+ /// Information about a file.
+ class file_status
+ {
+ using self_type = file_status;
+
+ public:
+ protected:
+ struct ::stat _stat; ///< File information.
+
+ friend self_type status(const path &, std::error_code &) noexcept;
+
+ friend int file_type(const self_type &);
+ friend uintmax_t file_size(const self_type &);
+ friend bool is_regular_file(const file_status &);
+ friend bool is_dir(const file_status &);
+ friend bool is_char_device(const file_status &);
+ friend bool is_block_device(const file_status &);
+ };
+
+ /** Get the status of the file at @a p.
+ *
+ * @param p Path to file.
+ * @param ec Error code return.
+ * @return Status of the file.
+ */
+ file_status status(const path &p, std::error_code &ec) noexcept;
+
+ // Related free functions.
+ // These are separate because they are not part of std::filesystem::path.
+
+ /// Return the file type value.
+ int file_type(const file_status &fs);
+
+ /// Check if the path is to a regular file.
+ bool is_regular_file(const file_status &fs);
+
+ /// Check if the path is to a directory.
+ bool is_dir(const file_status &p);
+
+ /// Check if the path is to a character device.
+ bool is_char_device(const file_status &fs);
+
+ /// Check if the path is to a block device.
+ bool is_block_device(const file_status &fs);
+
+ /// Size of the file or block device.
+ uintmax_t file_size(const file_status &fs);
+
+ /// Check if file is readable.
+ bool is_readable(const path &s);
+
+ /** Load the file at @a p into a @c std::string.
+ *
+ * @param p Path to file
+ * @return The contents of the file.
+ */
+ std::string load(const path &p, std::error_code &ec);
+ /* ------------------------------------------------------------------- */
+
+ inline path::path(char const *src) : _path(src) {}
+
+ inline path::path(std::string_view base) : _path(base) {}
+
+ inline path::path(std::string &&that) : _path(std::move(that)) {}
+
+ inline path &
+ path::operator=(std::string_view p)
+ {
+ _path.assign(p);
+ return *this;
+ }
+
+ inline char const *
+ path::c_str() const
+ {
+ return _path.c_str();
+ }
+
+ inline std::string
+ path::string() const
+ {
+ return _path;
+ }
+
+ inline bool
+ path::empty() const
+ {
+ return _path.empty();
+ }
+
+ inline bool
+ path::is_absolute() const
+ {
+ return !_path.empty() && preferred_separator == _path[0];
+ }
+
+ inline bool
+ path::is_relative() const
+ {
+ return !this->is_absolute();
+ }
+
+ inline path &
+ path::operator/=(const self_type &that)
+ {
+ return *this /= std::string_view(that._path);
+ }
+
+ /** Combine two strings as file paths.
+
+ @return A @c path with the combined path.
+ */
+ inline path
+ operator/(const path &lhs, const path &rhs)
+ {
+ return path(lhs) /= rhs;
+ }
+
+ inline path
+ operator/(path &&lhs, const path &rhs)
+ {
+ return path(std::move(lhs)) /= rhs;
+ }
+
+ inline path
+ operator/(const path &lhs, std::string_view rhs)
+ {
+ return path(lhs) /= rhs;
+ }
+
+ inline path
+ operator/(path &&lhs, std::string_view rhs)
+ {
+ return path(std::move(lhs)) /= rhs;
+ }
+
+ /* ------------------------------------------------------------------- */
+} // namespace file
+} // namespace ts
+/* ------------------------------------------------------------------- */
diff --git a/src/tscore/Makefile.am b/src/tscore/Makefile.am
index 8e82d16..297b341 100644
--- a/src/tscore/Makefile.am
+++ b/src/tscore/Makefile.am
@@ -208,6 +208,7 @@ libtscore_la_SOURCES = \
Tokenizer.h \
Trie.h \
TsBuffer.h \
+ ts_file. h ts_file.cc \
Version.cc \
X509HostnameValidator.cc \
X509HostnameValidator.h
@@ -274,7 +275,8 @@ test_tscore_SOURCES = \
unit_tests/test_Ptr.cc \
unit_tests/test_Regex.cc \
unit_tests/test_Scalar.cc \
- unit_tests/test_scoped_resource.cc
+ unit_tests/test_scoped_resource.cc \
+ unit_tests/test_ts_file.cc
CompileParseRules_SOURCES = CompileParseRules.cc
diff --git a/src/tscore/ts_file.cc b/src/tscore/ts_file.cc
new file mode 100644
index 0000000..3467176
--- /dev/null
+++ b/src/tscore/ts_file.cc
@@ -0,0 +1,126 @@
+/** @file
+
+ Minimalist version of std::filesystem.
+
+ @section license License
+
+ Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ agreements. See the NOTICE file distributed with this work for additional information regarding
+ copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with the License. You may
+ obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software distributed under the
+ License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+ express or implied. See the License for the specific language governing permissions and
+ limitations under the License.
+ */
+
+#include "tscore/ts_file.h"
+#include <fcntl.h>
+
+namespace ts
+{
+namespace file
+{
+ path &
+ path::operator/=(std::string_view that)
+ {
+ if (!that.empty()) { // don't waste time appending nothing.
+ if (that.front() == preferred_separator || _path.empty()) {
+ _path.assign(that);
+ } else {
+ if (_path.back() == preferred_separator) {
+ _path.reserve(_path.size() + that.size());
+ } else {
+ _path.reserve(_path.size() + that.size() + 1);
+ _path.push_back(preferred_separator);
+ }
+ _path.append(that);
+ }
+ }
+ return *this;
+ }
+
+ file_status
+ status(const path &p, std::error_code &ec) noexcept
+ {
+ file_status zret;
+ if (::stat(p.c_str(), &zret._stat) >= 0) {
+ ec.clear();
+ } else {
+ ec = std::error_code(errno, std::system_category());
+ }
+ return zret;
+ }
+
+ int
+ file_type(const file_status &fs)
+ {
+ return fs._stat.st_mode & S_IFMT;
+ }
+
+ uintmax_t
+ file_size(const file_status &fs)
+ {
+ return fs._stat.st_size;
+ }
+
+ bool
+ is_char_device(const file_status &fs)
+ {
+ return file_type(fs) == S_IFCHR;
+ }
+
+ bool
+ is_block_device(const file_status &fs)
+ {
+ return file_type(fs) == S_IFBLK;
+ }
+
+ bool
+ is_regular_file(const file_status &fs)
+ {
+ return file_type(fs) == S_IFREG;
+ }
+
+ bool
+ is_dir(const file_status &fs)
+ {
+ return file_type(fs) == S_IFDIR;
+ }
+
+ bool
+ is_readable(const path &p)
+ {
+ return 0 == access(p.c_str(), R_OK);
+ }
+
+ std::string
+ load(const path &p, std::error_code &ec)
+ {
+ std::string zret;
+ ats_scoped_fd fd(::open(p.c_str(), O_RDONLY));
+ ec.clear();
+ if (fd < 0) {
+ ec = std::error_code(errno, std::system_category());
+ } else {
+ struct stat info;
+ if (0 != ::fstat(fd, &info)) {
+ ec = std::error_code(errno, std::system_category());
+ } else {
+ int n = info.st_size;
+ zret.resize(n);
+ auto read_len = ::read(fd, const_cast<char *>(zret.data()), n);
+ if (read_len < n) {
+ ec = std::error_code(errno, std::system_category());
+ }
+ }
+ }
+ return zret;
+ }
+
+} // namespace file
+} // namespace ts
diff --git a/src/tscore/unit_tests/test_ts_file.cc b/src/tscore/unit_tests/test_ts_file.cc
new file mode 100644
index 0000000..e7a49db
--- /dev/null
+++ b/src/tscore/unit_tests/test_ts_file.cc
@@ -0,0 +1,69 @@
+/** @file
+
+ ts::file unit tests.
+
+ @section license License
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+#include <iostream>
+
+#include "tscore/ts_file.h"
+#include "../../../tests/include/catch.hpp"
+
+using ts::file::path;
+
+// --------------------
+TEST_CASE("ts_file", "[libts][ts_file]")
+{
+ path p1("/home");
+ REQUIRE(p1.string() == "/home");
+ auto p2 = p1 / "bob";
+ REQUIRE(p2.string() == "/home/bob");
+ p2 = p2 / "git/ats/";
+ REQUIRE(p2.string() == "/home/bob/git/ats/");
+ p2 /= "lib/ts";
+ REQUIRE(p2.string() == "/home/bob/git/ats/lib/ts");
+ p2 /= "/home/dave";
+ REQUIRE(p2.string() == "/home/dave");
+ path p3 = path("/home/dave") / "git/tools";
+ REQUIRE(p3.string() == "/home/dave/git/tools");
+}
+
+TEST_CASE("ts_file_io", "[libts][ts_file_io]")
+{
+ path file("unit_tests/test_ts_file.cc");
+ std::error_code ec;
+ std::string content = ts::file::load(file, ec);
+ REQUIRE(ec.value() == 0);
+ REQUIRE(content.size() > 0);
+ REQUIRE(content.find("ts::file::path") != content.npos);
+
+ // Check some file properties.
+ REQUIRE(ts::file::is_readable(file) == true);
+ auto fs = ts::file::status(file, ec);
+ REQUIRE(ec.value() == 0);
+ REQUIRE(ts::file::is_dir(fs) == false);
+ REQUIRE(ts::file::is_regular_file(fs) == true);
+
+ // Failure case.
+ file = "unit-tests/no_such_file.txt";
+ content = ts::file::load(file, ec);
+ REQUIRE(ec.value() == 2);
+ REQUIRE(ts::file::is_readable(file) == false);
+}