Commit Diff


commit - c2939b27ec9c1ba93e59bd04d1001c1780cf25e7
commit + 56ea87282c8489752e54c45d0e4b68823c59b670
blob - dd9e363064e1368f3b90a3e93c374093dd942de1
blob + 490a7207b488c0f90940fda93e95a002abeb7a66
--- tests/test_open_file.cc
+++ tests/test_open_file.cc
@@ -18,7 +18,28 @@ namespace error
 std::ostream dev_null{nullptr};
 std::ostream &g_log = dev_null;
 }
+namespace
+{
+template <std::size_t N>
+void fill(std::vector<char> &v, const char (&arr)[N])
+{
+    v.resize(N);
+    std::copy(&arr[0], &arr[N], v.begin());
+}
 
+template <std::size_t N>
+bool is_tail(Span<const char> opened_path, const char (&arr)[N])
+{
+    if (opened_path.size() >= (N - 1))
+    {
+        opened_path = opened_path.subspan(opened_path.size() - (N - 1));
+        return std::equal(opened_path.begin(), opened_path.end(), &arr[0]);
+    }
+    return false;
+}
+
+}   // namespace <unnamed>
+
 TEST_START(test_open_file)
     std::ostringstream ss;
     ss << "/tmp/test_open_file." << getpid() << "." << time(nullptr);
@@ -27,11 +48,20 @@ TEST_START(test_open_file)
     const UniqueFd dir{open(ss.str().c_str(), O_RDONLY | O_DIRECTORY)};
     IS_TRUE_ERRNO(dir, "Open directory " << ss.str().c_str());
 
+
+    std::vector<char> sz_file_name;
+    Span<const char> opened_path;
     {
         UniqueFd opened_file;
-        IS_TRUE(open_file(dir.get(), "", opened_file) == FILE_NOT_FOUND and !opened_file);
-        IS_TRUE(open_file(dir.get(), "non-existent-file", opened_file) == FILE_NOT_FOUND and !opened_file);
-        IS_TRUE(open_file(dir.get(), "non-existent-dir/file", opened_file) == FILE_NOT_FOUND and !opened_file);
+
+        fill(sz_file_name, "");
+        IS_TRUE(open_file(dir.get(), sz_file_name , opened_file, opened_path) == FILE_NOT_FOUND and !opened_file);
+
+        fill(sz_file_name, "non-existent-file");
+        IS_TRUE(open_file(dir.get(), sz_file_name, opened_file, opened_path) == FILE_NOT_FOUND and !opened_file);
+
+        fill(sz_file_name, "non-existent-dir/file");
+        IS_TRUE(open_file(dir.get(), sz_file_name, opened_file, opened_path) == FILE_NOT_FOUND and !opened_file);
     }
 
     const UniqueFd index_gmi{openat(dir.get(), "index.gmi", O_RDONLY | O_CREAT | O_EXCL, S_IRWXU)};
@@ -41,7 +71,10 @@ TEST_START(test_open_file)
 
     {
         UniqueFd opened_file;
-        IS_TRUE(open_file(dir.get(), "", opened_file) == FILE_OPENED and opened_file);
+        fill(sz_file_name, "");
+        IS_TRUE(open_file(dir.get(), sz_file_name, opened_file, opened_path) == FILE_OPENED and opened_file);
+        IS_TRUE(is_tail(opened_path, "index.gmi"));
+
         struct stat sb2{};
         IS_TRUE_ERRNO(fstat(opened_file.get(), &sb2) != -1, "Stat file " << ss.str().c_str() << "/index.gmi");
         IS_TRUE((sb1.st_dev == sb2.st_dev) && (sb1.st_ino == sb2.st_ino));
@@ -49,7 +82,9 @@ TEST_START(test_open_file)
 
     {
         UniqueFd opened_file;
-        IS_TRUE(open_file(dir.get(), "index.gmi", opened_file) == FILE_OPENED and opened_file);
+        fill(sz_file_name, "index.gmi");
+        IS_TRUE(open_file(dir.get(), sz_file_name, opened_file, opened_path) == FILE_OPENED and opened_file);
+        IS_TRUE(is_tail(opened_path, "index.gmi"));
         struct stat sb2{};
         IS_TRUE_ERRNO(fstat(opened_file.get(), &sb2) != -1, "Stat file " << ss.str().c_str() << "/index.gmi");
         IS_TRUE((sb1.st_dev == sb2.st_dev) && (sb1.st_ino == sb2.st_ino));
@@ -58,8 +93,10 @@ TEST_START(test_open_file)
     IS_TRUE_ERRNO(mkdirat(dir.get(), "subdir", S_IRWXU) != -1,  "Create directory " << ss.str().c_str() << "/subdir");
     {
         UniqueFd opened_file;
-        IS_TRUE(open_file(dir.get(), "subdir", opened_file) == FILE_NOT_FOUND and !opened_file);
-        IS_TRUE(open_file(dir.get(), "subdir/", opened_file) == FILE_NOT_FOUND and !opened_file);
+        fill(sz_file_name, "subdir");
+        IS_TRUE(open_file(dir.get(), sz_file_name, opened_file, opened_path) == FILE_NOT_FOUND and !opened_file);
+        fill(sz_file_name, "subdir/");
+        IS_TRUE(open_file(dir.get(), sz_file_name, opened_file, opened_path) == FILE_NOT_FOUND and !opened_file);
     }
     const UniqueFd subdir{openat(dir.get(), "subdir", O_RDONLY | O_DIRECTORY)};
     IS_TRUE_ERRNO(subdir, "Open directory " << ss.str().c_str() << "/subdir");
@@ -70,7 +107,9 @@ TEST_START(test_open_file)
 
     {
         UniqueFd opened_file;
-        IS_TRUE(open_file(dir.get(), "subdir", opened_file) == FILE_OPENED and opened_file);
+        fill(sz_file_name, "subdir");
+        IS_TRUE(open_file(dir.get(), sz_file_name, opened_file, opened_path) == FILE_OPENED and opened_file);
+        IS_TRUE(is_tail(opened_path, "index.gmi"));
         struct stat sb2{};
         IS_TRUE_ERRNO(fstat(opened_file.get(), &sb2) != -1, "Stat file " << ss.str().c_str() << "/subdir/index.gmi");
         IS_TRUE((sb1.st_dev == sb2.st_dev) && (sb1.st_ino == sb2.st_ino));
@@ -78,7 +117,9 @@ TEST_START(test_open_file)
 
     {
         UniqueFd opened_file;
-        IS_TRUE(open_file(dir.get(), "subdir/", opened_file) == FILE_OPENED and opened_file);
+        fill(sz_file_name, "subdir/");
+        IS_TRUE(open_file(dir.get(), sz_file_name, opened_file, opened_path) == FILE_OPENED and opened_file);
+        IS_TRUE(is_tail(opened_path, "index.gmi"));
         struct stat sb2{};
         IS_TRUE_ERRNO(fstat(opened_file.get(), &sb2) != -1, "Stat file " << ss.str().c_str() << "/subdir/index.gmi");
         IS_TRUE((sb1.st_dev == sb2.st_dev) && (sb1.st_ino == sb2.st_ino));
@@ -86,7 +127,9 @@ TEST_START(test_open_file)
 
     {
         UniqueFd opened_file;
-        IS_TRUE(open_file(dir.get(), "subdir/index.gmi", opened_file) == FILE_OPENED and opened_file);
+        fill(sz_file_name, "subdir/index.gmi");
+        IS_TRUE(open_file(dir.get(), sz_file_name, opened_file, opened_path) == FILE_OPENED and opened_file);
+        IS_TRUE(is_tail(opened_path, "index.gmi"));
         struct stat sb2{};
         IS_TRUE_ERRNO(fstat(opened_file.get(), &sb2) != -1, "Stat file " << ss.str().c_str() << "/subdir/index.gmi");
         IS_TRUE((sb1.st_dev == sb2.st_dev) && (sb1.st_ino == sb2.st_ino));
@@ -97,7 +140,8 @@ TEST_START(test_open_file)
 
     {
         UniqueFd opened_file;
-        IS_TRUE(open_file(dir.get(), "subdir/EPERM.gmi", opened_file) == FILE_OPENING_ERROR and !opened_file);
+        fill(sz_file_name, "subdir/EPERM.gmi");
+        IS_TRUE(open_file(dir.get(), sz_file_name, opened_file, opened_path) == FILE_OPENING_ERROR and !opened_file);
     }
 
     IS_TRUE_ERRNO(unlinkat(subdir.get(), "EPERM.gmi", 0) != -1, "Remove file " << ss.str().c_str() << "/subdir/EPERM.gmi");
blob - 1fa3fbf6f7544b1b63f6fdfb18cabea02fe971c2
blob + bf7fc548d06c4122ff18d59004d8010ca6c8636c
--- vostok/open_file.cc
+++ vostok/open_file.cc
@@ -11,14 +11,28 @@ namespace vostok
 {
 namespace
 {
-NotNull<czstring> index_gmi = "index.gmi";
+const char index_gmi[] = "index.gmi";
 }   // namespace <unnamed>
 
 
-OpenFileResult open_file(int directory_fd, NotNull<czstring> file_name, UniqueFd &opened_file)
+OpenFileResult
+open_file(
+    /* in */ int directory_fd,
+    /* in */ const std::vector<char> &sz_file_name,
+    /* out */ UniqueFd &opened_file,
+    /* out */ Span<const char> &opened_path
+)
 {
+    assert(sz_file_name.size());
+
+    NotNull<czstring> file_name = sz_file_name.data();
+    opened_path = cut_null(sz_file_name);
+
     if (!*file_name)
+    {
         file_name = index_gmi;
+        opened_path = cut_null(index_gmi);
+    }
 
     opened_file.reset(openat(directory_fd, file_name, O_RDONLY));
     if (!opened_file)
@@ -48,6 +62,7 @@ OpenFileResult open_file(int directory_fd, NotNull<czs
     if (S_ISDIR(sb.st_mode))
     {
         const UniqueFd new_parent{opened_file.release()};
+        opened_path = cut_null(index_gmi);
         opened_file.reset(openat(new_parent.get(), index_gmi, O_RDONLY));
         if (!opened_file)
         {
blob - a16a4bda08cbdc43ea3f7d423708326518d3166d
blob + a69a53ff70dbd260bb80d14e0faa7e9017c6584a
--- vostok/open_file.h
+++ vostok/open_file.h
@@ -16,7 +16,14 @@ enum OpenFileResult
     FILE_NOT_FOUND,
     FILE_OPENING_ERROR,
 };
-OpenFileResult open_file(int directory_fd, NotNull<czstring> file_name, UniqueFd &opened_file);
 
+OpenFileResult
+open_file(
+    /* in */ int directory_fd,
+    /* in */ const std::vector<char> &sz_file_name,
+    /* out */ UniqueFd &opened_file,
+    /* out */ Span<const char> &opened_path
+);
 
+
 }   // namespace vostok
blob - e4e5c5bc74e604ca45c322c02d57bed199bdacdf
blob + 08c3def08a75168b755be2465e2b8845f5f517c3
--- vostok/transport.h
+++ vostok/transport.h
@@ -1,8 +1,6 @@
 /** Wrap libtls for gemini protocol */
 
 #include "utils.h"
-
-#include <vector>
 #include <tls.h>
 
 #pragma once
blob - bfc80dc82debb13758a5c46e0f023349e7870537
blob + 60749f41c58b753468d478666c6e0568f18c687b
--- vostok/utils.h
+++ vostok/utils.h
@@ -3,6 +3,7 @@
 #include <cstddef>
 #include <cassert>
 #include <array>
+#include <vector>
 
 #include <unistd.h>
 
@@ -72,6 +73,20 @@ class Span (public)
     constexpr Span(element_type (&arr)[N]) : m_p{arr}, m_count{N} {}
     template <std::size_t N>
     constexpr Span(const std::array<element_type, N> &arr) : m_p{arr.data()}, m_count{N} {}
+    template <typename other_element_type>
+    Span(const std::vector<other_element_type> &v)
+    {
+        if (v.size())
+        {
+            m_p = v.data();
+            m_count = v.size();
+        }
+        else
+        {
+            m_p = nullptr;
+            m_count = 0;
+        }
+    }
 
     constexpr std::size_t size() const {return m_count;}
 
@@ -108,6 +123,13 @@ constexpr Span<const char> cut_null(const char (&arr)[
     static_assert(N > 0, "!(N > 0)");
     return Span<const char>{arr, N - 1};
 }
+template <typename ElemT>
+Span<const char> cut_null(const std::vector<ElemT> &v)
+{
+    assert(v.size() > 0);
+    assert(v[v.size() - 1] == '\0');
+    return Span<const char>{v.data(), v.size() - 1};
+}
 
 
 /** Smart pointer for file descriptor */
blob - d4370280c07bcdf629918760944ebc867e2974ae
blob + 35c28e6faddbc3bc9f924773c695981ddadef313
--- vostok/vostok.cc
+++ vostok/vostok.cc
@@ -12,7 +12,6 @@
 #include <netinet/in.h>
 
 #include <thread>
-#include <vector>
 
 
 namespace vostok
@@ -94,7 +93,8 @@ void client_thread(const transport::AcceptedClient *ac
     }
 
     UniqueFd opened_file{};
-    const auto open_file_result = open_file(directory_fd, request.get_path().data(), opened_file);
+    Span<const char> opened_path;
+    const auto open_file_result = open_file(directory_fd, request.get_path(), opened_file, opened_path);
     switch (open_file_result)
     {
     case FILE_NOT_FOUND: