Welcome to mirror list, hosted at ThFree Co, Russian Federation.

path_works.cpp « tests « test « attic - github.com/windirstat/llfio.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 6ac56147918bcd024ec080973fd019d613189615 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
#include "test_functions.hpp"

BOOST_AFIO_AUTO_TEST_CASE(path_works, "Tests that the path functions work as they are supposed to", 20)
{
    using namespace BOOST_AFIO_V2_NAMESPACE;
    auto dispatcher = make_dispatcher().get();
    auto dirh = dispatcher->dir(path_req("testdir", file_flags::create));
    dirh.get();
    {
#ifdef WIN32
#define BOOST_AFIO_PATH_WORKS_STR(s) L ## s
#else
#define BOOST_AFIO_PATH_WORKS_STR(s) s
#endif
      static const auto hellobabystr = BOOST_AFIO_PATH_WORKS_STR("hellobaby"), testfilestr = BOOST_AFIO_PATH_WORKS_STR("testfile"), foostr = BOOST_AFIO_PATH_WORKS_STR("foo");
#undef BOOST_AFIO_PATH_WORKS_STR
      {
        future<> op = dispatcher->file(path_req("testdir/testfile", file_flags::create | file_flags::read_write));
        auto h = op.get_handle();
        auto originalpath = h->path();
        print_stat(h);
        auto originalpath2 = h->path();
        BOOST_CHECK(originalpath == originalpath2);

#ifdef WIN32
        // Verify pass through
        path p("testfile");
        BOOST_CHECK(p.native() == L"testfile");

        p = path::make_absolute("testfile");
        BOOST_CHECK(p.native() != L"testfile");
        // Make sure it prepended \??\ to make a NT kernel path
        BOOST_CHECK((p.native()[0] == '\\' && p.native()[1] == '?' && p.native()[2] == '?' && p.native()[3] == '\\'));
        BOOST_CHECK((isalpha(p.native()[4]) && p.native()[5] == ':'));
        // Make sure it converts back via fast path
        auto fp = p.filesystem_path();
        BOOST_CHECK((fp.native()[0] == '\\' && fp.native()[1] == '\\' && fp.native()[2] == '?' && fp.native()[3] == '\\'));
        BOOST_CHECK(p.native().substr(4) == fp.native().substr(4));
        // Make sure it converts back perfectly via slow path
        fp = normalise_path(p);
        auto a = fp.native();
        auto b = filesystem::absolute("testfile").native();
        // Filesystem has been known to return lower case drive letters ...
        std::transform(a.begin(), a.end(), a.begin(), ::tolower);
        std::transform(b.begin(), b.end(), b.begin(), ::tolower);
        if (b.size() >= 260)
          b = L"\\\\?\\" + b;
        std::wcout << a << " (sized " << a.size() << ")" << std::endl;
        std::wcout << b << " (sized " << b.size() << ")" << std::endl;
        BOOST_CHECK(a == b);

        // Make sure it handles extended path inputs
        p = filesystem::path("\\\\?") / filesystem::absolute("testfile");
        BOOST_CHECK((p.native()[0] == '\\' && p.native()[1] == '?' && p.native()[2] == '?' && p.native()[3] == '\\'));
        BOOST_CHECK((isalpha(p.native()[4]) && p.native()[5] == ':'));

        // Make sure native NT path inputs are preserved
        filesystem::path o("\\\\.\\Device1");
        p = o;
        BOOST_CHECK(p.native() == L"\\Device1");
        fp = p.filesystem_path();
        BOOST_CHECK(fp == o);

#endif

        std::cout << "\nRenaming testfile to hellobaby using OS ..." << std::endl;
        filesystem::rename("testdir/testfile", "testdir/hellobaby");
        print_stat(h);
        auto afterrename = h->path();
#ifndef __FreeBSD__  // FreeBSD can't track file renames
        BOOST_CHECK((originalpath.parent_path() / hellobabystr) == afterrename);
#endif
        std::cout << "\nDeleting hellobaby file using OS ..." << std::endl;
        filesystem::remove("testdir/hellobaby");
        auto afterdelete = print_stat(h);
        BOOST_CHECK(h->path() == BOOST_AFIO_V2_NAMESPACE::path());
        std::cout << "\nEnumerating directory to make sure hellobaby is not there ..." << std::endl;
        auto contents = dispatcher->enumerate(enumerate_req(dirh, metadata_flags::All, 50)).get().first;
        for (auto &i : contents)
        {
          std::cout << "  " << i.name() << std::endl;
#ifndef WIN32  // Windows only marks for deletion, doesn't actually delete
          BOOST_CHECK(i.name() != hellobabystr);
#endif
        }
      }

      std::cout << "\nCreating hard links testfile2 and testfile3 from testfile ..." << std::endl;
      handle_ptr h;
      future<> op = dispatcher->file(path_req::relative(dirh, testfilestr, file_flags::create | file_flags::read_write));
      h = op.get_handle();
      BOOST_CHECK(h->path(true) == dirh->path() / testfilestr);
      bool supports_hard_links = true;
      try
      {
        h->link(path_req::relative(dirh, "testfile2"));
      }
      catch (...)
      {
        supports_hard_links = false;
        dispatcher->rmfile(path_req::relative(dirh, "testfile")).get();
      }
      if (supports_hard_links)
      {
        BOOST_CHECK(h->path(true) == dirh->path() / testfilestr);
        h->link(path_req::relative(dirh, "testfile3"));
        BOOST_CHECK(h->path(true) == dirh->path() / testfilestr);
        dispatcher->truncate(op, 78).get();
        dispatcher->sync(op).get();
        auto entry = h->lstat();
        BOOST_CHECK(entry.st_size == 78);
        auto contents = dispatcher->enumerate(enumerate_req(dirh, metadata_flags::All, 50)).get().first;
        BOOST_CHECK(contents.size() == 3);
        for (auto &i : contents)
        {
          print_stat(dirh.get_handle(), i);
          BOOST_CHECK(i.st_ino() == entry.st_ino);
#ifndef WIN32  // Windows takes too long to update this
          BOOST_CHECK(i.st_size() == entry.st_size);
#endif
          BOOST_CHECK(i.st_nlink() == 3);
        }

        std::cout << "\nRelinking hard link testfile to foo ..." << std::endl;
        h->atomic_relink(path_req::relative(dirh, foostr));
        BOOST_CHECK(h->path(true) == dirh->path() / foostr);
        dispatcher->truncate(op, 79).get();
        dispatcher->sync(op).get();
        entry = h->lstat();
        BOOST_CHECK(entry.st_size == 79);
        contents = dispatcher->enumerate(enumerate_req(dirh, metadata_flags::All, 50)).get().first;
        BOOST_CHECK(contents.size() == 3);
        for (auto &i : contents)
        {
          print_stat(dirh.get_handle(), i);
          BOOST_CHECK(i.name() != testfilestr);
          BOOST_CHECK(i.st_ino() == entry.st_ino);
#ifndef WIN32  // Windows takes too long to update this
          BOOST_CHECK(i.st_size() == entry.st_size);
#endif
          BOOST_CHECK(i.st_nlink() == 3);
        }

        std::cout << "\nUnlinking hard links ..." << std::endl;
        h->unlink();
#ifndef __FreeBSD__  // FreeBSD will not notice a file with multiple hard links is deleted
        BOOST_CHECK(h->path(true).empty());
#endif
        contents = dispatcher->enumerate(enumerate_req(dirh, metadata_flags::All, 50)).get().first;
        BOOST_CHECK(contents.size() == 2);
        for (auto &i : contents)
        {
          print_stat(dirh.get_handle(), i);
          BOOST_CHECK(i.name() != foostr); // This should get filtered out by AFIO on Windows due to magic naming
          BOOST_CHECK(i.st_nlink() == 2);
        }
        op = future<>();
        h.reset(); // Should actually cause the unlink to really happen on Windows
        contents = dispatcher->enumerate(enumerate_req(dirh, metadata_flags::All, 50)).get().first;
        BOOST_CHECK(contents.size() == 2);
        for (auto &i : contents)
        {
          print_stat(dirh.get_handle(), i);
          BOOST_CHECK(i.name() != foostr);
          BOOST_CHECK(i.st_nlink() == 2);
        }
        dispatcher->rmfile(path_req::relative(dirh, "testfile2")).get();
        dispatcher->rmfile(path_req::relative(dirh, "testfile3")).get();
        contents = dispatcher->enumerate(enumerate_req(dirh, metadata_flags::All, 50)).get().first;
        BOOST_CHECK(contents.size() == 0);
      }
    }

    // Reopen with write privs in order to unlink
    dirh = dispatcher->dir(path_req("testdir", file_flags::read_write));
    dirh->unlink();
}