123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897 |
- #include "path.h"
- #include "pathsplit.h"
- #include "dirut.h"
- #include "tempdir.h"
- #include <library/cpp/testing/unittest/registar.h>
- #include <util/generic/scope.h>
- #include <util/system/platform.h>
- #include <util/system/yassert.h>
- #include <util/stream/output.h>
- #include <util/stream/file.h>
- #include <util/system/fs.h>
- #include <algorithm>
- #ifdef _win_
- #include <aclapi.h>
- #endif
- namespace {
- /// empty directory for test that needs filesystem
- /// recreates directory in constructor and removes directory in destructor
- class TTestDirectory {
- private:
- TFsPath Path_;
- public:
- TTestDirectory(const TString& name);
- ~TTestDirectory();
- TFsPath GetFsPath() const {
- return Path_;
- }
- TFsPath Child(const TString& name) const {
- return Path_.Child(name);
- }
- };
- TTestDirectory::TTestDirectory(const TString& name) {
- Y_ABORT_UNLESS(name.length() > 0, "have to specify name");
- Y_ABORT_UNLESS(name.find('.') == TString::npos, "must be simple name");
- Y_ABORT_UNLESS(name.find('/') == TString::npos, "must be simple name");
- Y_ABORT_UNLESS(name.find('\\') == TString::npos, "must be simple name");
- Path_ = TFsPath(name);
- Path_.ForceDelete();
- Path_.MkDir();
- }
- TTestDirectory::~TTestDirectory() {
- Path_.ForceDelete();
- }
- }
- Y_UNIT_TEST_SUITE(TFsPathTests) {
- Y_UNIT_TEST(TestMkDirs) {
- const TFsPath path = "a/b/c/d/e/f";
- path.ForceDelete();
- TFsPath current = path;
- ui32 checksCounter = 0;
- while (current != ".") {
- UNIT_ASSERT(!path.Exists());
- ++checksCounter;
- current = current.Parent();
- }
- UNIT_ASSERT_VALUES_EQUAL(checksCounter, 6);
- path.MkDirs();
- UNIT_ASSERT(path.Exists());
- current = path;
- while (current != ".") {
- UNIT_ASSERT(path.Exists());
- current = current.Parent();
- }
- }
- Y_UNIT_TEST(MkDirFreak) {
- TFsPath path;
- UNIT_ASSERT_EXCEPTION(path.MkDir(), TIoException);
- UNIT_ASSERT_EXCEPTION(path.MkDirs(), TIoException);
- path = ".";
- path.MkDir();
- path.MkDirs();
- }
- Y_UNIT_TEST(Parent) {
- #ifdef _win_
- UNIT_ASSERT_VALUES_EQUAL(TFsPath("\\etc/passwd").Parent(), TFsPath("\\etc"));
- UNIT_ASSERT_VALUES_EQUAL(TFsPath("\\etc").Parent(), TFsPath("\\"));
- UNIT_ASSERT_VALUES_EQUAL(TFsPath("\\").Parent(), TFsPath("\\"));
- UNIT_ASSERT_VALUES_EQUAL(TFsPath("etc\\passwd").Parent(), TFsPath("etc"));
- UNIT_ASSERT_VALUES_EQUAL(TFsPath("etc").Parent(), TFsPath("."));
- UNIT_ASSERT_VALUES_EQUAL(TFsPath(".\\etc").Parent(), TFsPath("."));
- UNIT_ASSERT_VALUES_EQUAL(TFsPath("C:\\etc/passwd").Parent(), TFsPath("C:\\etc"));
- UNIT_ASSERT_VALUES_EQUAL(TFsPath("C:\\etc").Parent(), TFsPath("C:\\"));
- UNIT_ASSERT_VALUES_EQUAL(TFsPath("C:\\").Parent(), TFsPath("C:\\"));
- #else
- UNIT_ASSERT_VALUES_EQUAL(TFsPath("/etc/passwd").Parent(), TFsPath("/etc"));
- UNIT_ASSERT_VALUES_EQUAL(TFsPath("/etc").Parent(), TFsPath("/"));
- UNIT_ASSERT_VALUES_EQUAL(TFsPath("/").Parent(), TFsPath("/"));
- UNIT_ASSERT_VALUES_EQUAL(TFsPath("etc/passwd").Parent(), TFsPath("etc"));
- UNIT_ASSERT_VALUES_EQUAL(TFsPath("etc").Parent(), TFsPath("."));
- UNIT_ASSERT_VALUES_EQUAL(TFsPath("./etc").Parent(), TFsPath("."));
- #endif
- #if 0
- UNIT_ASSERT_VALUES_EQUAL(TFsPath("./etc/passwd").Parent(), TFsPath("./etc"));
- UNIT_ASSERT_VALUES_EQUAL(TFsPath("./").Parent(), TFsPath(".."));
- UNIT_ASSERT_VALUES_EQUAL(TFsPath(".").Parent(), TFsPath(".."));
- UNIT_ASSERT_VALUES_EQUAL(TFsPath("..").Parent(), TFsPath("../.."));
- #endif
- }
- Y_UNIT_TEST(GetName) {
- TTestDirectory d("GetName");
- UNIT_ASSERT_VALUES_EQUAL(TString("dfgh"), d.Child("dfgh").GetName());
- // check does not fail
- TFsPath(".").GetName();
- #ifdef _unix_
- UNIT_ASSERT_VALUES_EQUAL(TString("/"), TFsPath("/").GetName());
- #endif
- }
- Y_UNIT_TEST(GetExtension) {
- TTestDirectory d("GetExtension");
- UNIT_ASSERT_VALUES_EQUAL("", d.Child("a").GetExtension());
- UNIT_ASSERT_VALUES_EQUAL("", d.Child(".a").GetExtension());
- UNIT_ASSERT_VALUES_EQUAL("", d.Child("zlib").GetExtension());
- UNIT_ASSERT_VALUES_EQUAL("zlib", d.Child("file.zlib").GetExtension());
- UNIT_ASSERT_VALUES_EQUAL("zlib", d.Child("file.ylib.zlib").GetExtension());
- }
- Y_UNIT_TEST(TestRename) {
- TTestDirectory xx("TestRename");
- TFsPath f1 = xx.Child("f1");
- TFsPath f2 = xx.Child("f2");
- f1.Touch();
- f1.RenameTo(f2);
- UNIT_ASSERT(!f1.Exists());
- UNIT_ASSERT(f2.Exists());
- }
- Y_UNIT_TEST(TestForceRename) {
- TTestDirectory xx("TestForceRename");
- TFsPath fMain = xx.Child("main");
- TFsPath f1 = fMain.Child("f1");
- f1.MkDirs();
- TFsPath f1Child = f1.Child("f1child");
- f1Child.Touch();
- TFsPath f2 = fMain.Child("f2");
- f2.MkDirs();
- fMain.ForceRenameTo("TestForceRename/main1");
- UNIT_ASSERT(!xx.Child("main").Exists());
- UNIT_ASSERT(xx.Child("main1").Child("f1").Exists());
- UNIT_ASSERT(xx.Child("main1").Child("f2").Exists());
- UNIT_ASSERT(xx.Child("main1").Child("f1").Child("f1child").Exists());
- }
- Y_UNIT_TEST(TestRenameFail) {
- UNIT_ASSERT_EXCEPTION(TFsPath("sfsfsfsdfsfsdfdf").RenameTo("sdfsdf"), TIoException);
- }
- #ifndef _win_
- Y_UNIT_TEST(TestRealPath) {
- UNIT_ASSERT(TFsPath(".").RealPath().IsDirectory());
- TTestDirectory td("TestRealPath");
- TFsPath link = td.Child("link");
- TFsPath target1 = td.Child("target1");
- target1.Touch();
- TFsPath target2 = td.Child("target2");
- target2.Touch();
- UNIT_ASSERT(NFs::SymLink(target1.RealPath(), link.GetPath()));
- UNIT_ASSERT_VALUES_EQUAL(link.RealPath(), target1.RealPath());
- UNIT_ASSERT(NFs::Remove(link.GetPath()));
- UNIT_ASSERT(NFs::SymLink(target2.RealPath(), link.GetPath()));
- UNIT_ASSERT_VALUES_EQUAL(link.RealPath(), target2.RealPath()); // must not cache old value
- }
- #endif
- Y_UNIT_TEST(TestSlashesAndBasename) {
- TFsPath p("/db/BASE/primus121-025-1380131338//");
- UNIT_ASSERT_VALUES_EQUAL(p.Basename(), TString("primus121-025-1380131338"));
- TFsPath testP = p / "test";
- #ifdef _win_
- UNIT_ASSERT_VALUES_EQUAL(testP.GetPath(), "\\db\\BASE\\primus121-025-1380131338\\test");
- #else
- UNIT_ASSERT_VALUES_EQUAL(testP.GetPath(), "/db/BASE/primus121-025-1380131338/test");
- #endif
- }
- Y_UNIT_TEST(TestSlashesAndBasenameWin) {
- TFsPath p("\\db\\BASE\\primus121-025-1380131338\\\\");
- TFsPath testP = p / "test";
- #ifdef _win_
- UNIT_ASSERT_VALUES_EQUAL(p.Basename(), TString("primus121-025-1380131338"));
- UNIT_ASSERT_VALUES_EQUAL(testP.GetPath(), "\\db\\BASE\\primus121-025-1380131338\\test");
- #else
- UNIT_ASSERT_VALUES_EQUAL(p.Basename(), TString("\\db\\BASE\\primus121-025-1380131338\\\\"));
- UNIT_ASSERT_VALUES_EQUAL(testP.GetPath(), "\\db\\BASE\\primus121-025-1380131338\\\\/test");
- #endif
- }
- Y_UNIT_TEST(TestSlashesAndBasenameWinDrive) {
- TFsPath p("C:\\db\\BASE\\primus121-025-1380131338\\\\");
- TFsPath testP = p / "test";
- #ifdef _win_
- UNIT_ASSERT_VALUES_EQUAL(p.Basename(), TString("primus121-025-1380131338"));
- UNIT_ASSERT_VALUES_EQUAL(testP.GetPath(), "C:\\db\\BASE\\primus121-025-1380131338\\test");
- #else
- UNIT_ASSERT_VALUES_EQUAL(p.Basename(), TString("C:\\db\\BASE\\primus121-025-1380131338\\\\"));
- UNIT_ASSERT_VALUES_EQUAL(testP.GetPath(), "C:\\db\\BASE\\primus121-025-1380131338\\\\/test");
- #endif
- }
- Y_UNIT_TEST(TestList) {
- TTestDirectory td("TestList-dir");
- TFsPath dir = td.GetFsPath();
- dir.Child("a").Touch();
- dir.Child("b").MkDir();
- dir.Child("b").Child("b-1").Touch();
- dir.Child("c").MkDir();
- dir.Child("d").Touch();
- TVector<TString> children;
- dir.ListNames(children);
- std::sort(children.begin(), children.end());
- TVector<TString> expected;
- expected.push_back("a");
- expected.push_back("b");
- expected.push_back("c");
- expected.push_back("d");
- UNIT_ASSERT_VALUES_EQUAL(expected, children);
- }
- #ifdef _unix_
- Y_UNIT_TEST(MkDirMode) {
- TTestDirectory td("MkDirMode");
- TFsPath subDir = td.Child("subdir");
- const int mode = MODE0775;
- subDir.MkDir(mode);
- TFileStat stat;
- UNIT_ASSERT(subDir.Stat(stat));
- // mkdir(2) places umask(2) on mode argument.
- const int mask = Umask(0);
- Umask(mask);
- UNIT_ASSERT_VALUES_EQUAL(stat.Mode& MODE0777, mode & ~mask);
- }
- #endif
- Y_UNIT_TEST(Cwd) {
- UNIT_ASSERT_VALUES_EQUAL(TFsPath::Cwd().RealPath(), TFsPath(".").RealPath());
- }
- Y_UNIT_TEST(TestSubpathOf) {
- UNIT_ASSERT(TFsPath("/a/b/c/d").IsSubpathOf("/a/b"));
- UNIT_ASSERT(TFsPath("/a").IsSubpathOf("/"));
- UNIT_ASSERT(!TFsPath("/").IsSubpathOf("/a"));
- UNIT_ASSERT(!TFsPath("/a").IsSubpathOf("/a"));
- UNIT_ASSERT(TFsPath("/a/b").IsSubpathOf("/a"));
- UNIT_ASSERT(TFsPath("a/b").IsSubpathOf("a"));
- UNIT_ASSERT(!TFsPath("/a/b").IsSubpathOf("/b"));
- UNIT_ASSERT(!TFsPath("a/b").IsSubpathOf("b"));
- // mixing absolute/relative
- UNIT_ASSERT(!TFsPath("a").IsSubpathOf("/"));
- UNIT_ASSERT(!TFsPath("a").IsSubpathOf("/a"));
- UNIT_ASSERT(!TFsPath("/a").IsSubpathOf("a"));
- UNIT_ASSERT(!TFsPath("a/b").IsSubpathOf("/a"));
- UNIT_ASSERT(!TFsPath("/a/b").IsSubpathOf("a"));
- #ifdef _win_
- UNIT_ASSERT(TFsPath("x:/a/b").IsSubpathOf("x:/a"));
- UNIT_ASSERT(!TFsPath("x:/a/b").IsSubpathOf("y:/a"));
- UNIT_ASSERT(!TFsPath("x:/a/b").IsSubpathOf("a"));
- #endif
- }
- Y_UNIT_TEST(TestNonStrictSubpathOf) {
- UNIT_ASSERT(TFsPath("/a/b/c/d").IsNonStrictSubpathOf("/a/b"));
- UNIT_ASSERT(TFsPath("/a").IsNonStrictSubpathOf("/"));
- UNIT_ASSERT(!TFsPath("/").IsNonStrictSubpathOf("/a"));
- UNIT_ASSERT(TFsPath("/a/b").IsNonStrictSubpathOf("/a"));
- UNIT_ASSERT(TFsPath("a/b").IsNonStrictSubpathOf("a"));
- UNIT_ASSERT(!TFsPath("/a/b").IsNonStrictSubpathOf("/b"));
- UNIT_ASSERT(!TFsPath("a/b").IsNonStrictSubpathOf("b"));
- // mixing absolute/relative
- UNIT_ASSERT(!TFsPath("a").IsNonStrictSubpathOf("/"));
- UNIT_ASSERT(!TFsPath("a").IsNonStrictSubpathOf("/a"));
- UNIT_ASSERT(!TFsPath("/a").IsNonStrictSubpathOf("a"));
- UNIT_ASSERT(!TFsPath("a/b").IsNonStrictSubpathOf("/a"));
- UNIT_ASSERT(!TFsPath("/a/b").IsNonStrictSubpathOf("a"));
- // equal paths
- UNIT_ASSERT(TFsPath("").IsNonStrictSubpathOf(""));
- UNIT_ASSERT(TFsPath("/").IsNonStrictSubpathOf("/"));
- UNIT_ASSERT(TFsPath("a").IsNonStrictSubpathOf("a"));
- UNIT_ASSERT(TFsPath("/a").IsNonStrictSubpathOf("/a"));
- UNIT_ASSERT(TFsPath("/a").IsNonStrictSubpathOf("/a/"));
- UNIT_ASSERT(TFsPath("/a/").IsNonStrictSubpathOf("/a"));
- UNIT_ASSERT(TFsPath("/a/").IsNonStrictSubpathOf("/a/"));
- #ifdef _win_
- UNIT_ASSERT(TFsPath("x:/a/b").IsNonStrictSubpathOf("x:/a"));
- UNIT_ASSERT(TFsPath("x:/a").IsNonStrictSubpathOf("x:/a"));
- UNIT_ASSERT(TFsPath("x:/a/").IsNonStrictSubpathOf("x:/a"));
- UNIT_ASSERT(TFsPath("x:/a").IsNonStrictSubpathOf("x:/a/"));
- UNIT_ASSERT(TFsPath("x:/a/").IsNonStrictSubpathOf("x:/a/"));
- UNIT_ASSERT(!TFsPath("x:/").IsNonStrictSubpathOf("y:/"));
- UNIT_ASSERT(!TFsPath("x:/a/b").IsNonStrictSubpathOf("y:/a"));
- UNIT_ASSERT(!TFsPath("x:/a/b").IsNonStrictSubpathOf("a"));
- #endif
- }
- Y_UNIT_TEST(TestRelativePath) {
- UNIT_ASSERT_VALUES_EQUAL(TFsPath("/a/b/c/d").RelativePath(TFsPath("/a/b")), TFsPath("c/d"));
- UNIT_ASSERT_VALUES_EQUAL(TFsPath("/a/b/c/d").RelativePath(TFsPath("/a/b/e/f")), TFsPath("../../c/d"));
- UNIT_ASSERT_VALUES_EQUAL(TFsPath("/").RelativePath(TFsPath("/")), TFsPath());
- UNIT_ASSERT_VALUES_EQUAL(TFsPath(".").RelativePath(TFsPath(".")), TFsPath());
- UNIT_ASSERT_VALUES_EQUAL(TFsPath("/a/c").RelativePath(TFsPath("/a/b/../c")), TFsPath());
- UNIT_ASSERT_VALUES_EQUAL(TFsPath("a/.././b").RelativePath(TFsPath("b/c")), TFsPath(".."));
- UNIT_ASSERT_EXCEPTION(TFsPath("a/b/c").RelativePath(TFsPath("d/e")), TIoException);
- }
- Y_UNIT_TEST(TestUndefined) {
- UNIT_ASSERT_VALUES_EQUAL(TFsPath(), TFsPath(""));
- UNIT_ASSERT_VALUES_EQUAL(TFsPath(), TFsPath().Fix());
- UNIT_ASSERT_VALUES_EQUAL(TFsPath() / TFsPath(), TFsPath());
- #ifdef _win_
- UNIT_ASSERT_VALUES_EQUAL(TFsPath("a\\b"), TFsPath() / TString("a\\b"));
- UNIT_ASSERT_VALUES_EQUAL(TFsPath("a\\b"), "a\\b" / TFsPath());
- UNIT_ASSERT_VALUES_EQUAL(TFsPath("\\a\\b"), TFsPath() / "\\a\\b");
- UNIT_ASSERT_VALUES_EQUAL(TFsPath("\\a\\b"), "\\a\\b" / TFsPath());
- #else
- UNIT_ASSERT_VALUES_EQUAL(TFsPath("a/b"), TFsPath() / TString("a/b"));
- UNIT_ASSERT_VALUES_EQUAL(TFsPath("a/b"), "a/b" / TFsPath());
- UNIT_ASSERT_VALUES_EQUAL(TFsPath("/a/b"), TFsPath() / "/a/b");
- UNIT_ASSERT_VALUES_EQUAL(TFsPath("/a/b"), "/a/b" / TFsPath());
- #endif
- UNIT_ASSERT_VALUES_EQUAL(TFsPath("."), TFsPath() / ".");
- UNIT_ASSERT_VALUES_EQUAL(TFsPath("."), "." / TFsPath());
- UNIT_ASSERT(TFsPath().PathSplit().empty());
- UNIT_ASSERT(!TFsPath().PathSplit().IsAbsolute);
- UNIT_ASSERT(TFsPath().IsRelative()); // undefined path is relative
- UNIT_ASSERT_VALUES_EQUAL(TFsPath().GetPath(), "");
- UNIT_ASSERT_VALUES_EQUAL(TFsPath().GetName(), "");
- UNIT_ASSERT_VALUES_EQUAL(TFsPath().GetExtension(), "");
- UNIT_ASSERT_VALUES_EQUAL(TFsPath().Parent(), TFsPath());
- UNIT_ASSERT_VALUES_EQUAL(TFsPath().Child("a"), TFsPath("a"));
- UNIT_ASSERT_VALUES_EQUAL(TFsPath().Basename(), "");
- UNIT_ASSERT_VALUES_EQUAL(TFsPath().Dirname(), "");
- UNIT_ASSERT(!TFsPath().IsSubpathOf("a/b"));
- UNIT_ASSERT(TFsPath().IsContainerOf("a/b"));
- UNIT_ASSERT(!TFsPath().IsContainerOf("/a/b"));
- #ifdef _win_
- UNIT_ASSERT_VALUES_EQUAL(TFsPath("a\\b").RelativeTo(TFsPath()), TFsPath("a\\b"));
- #else
- UNIT_ASSERT_VALUES_EQUAL(TFsPath("a/b").RelativeTo(TFsPath()), TFsPath("a/b"));
- #endif
- UNIT_ASSERT(!TFsPath().Exists());
- UNIT_ASSERT(!TFsPath().IsFile());
- UNIT_ASSERT(!TFsPath().IsDirectory());
- TFileStat stat;
- UNIT_ASSERT(!TFsPath().Stat(stat));
- }
- Y_UNIT_TEST(TestJoinFsPaths) {
- #ifdef _win_
- UNIT_ASSERT_VALUES_EQUAL(JoinFsPaths("a\\b", "c\\d"), "a\\b\\c\\d");
- UNIT_ASSERT_VALUES_EQUAL(JoinFsPaths("a\\b", "..\\c"), "a\\b\\..\\c");
- UNIT_ASSERT_VALUES_EQUAL(JoinFsPaths("a\\b\\..\\c", "d"), "a\\c\\d");
- UNIT_ASSERT_VALUES_EQUAL(JoinFsPaths("a", "b", "c", "d"), "a\\b\\c\\d");
- UNIT_ASSERT_VALUES_EQUAL(JoinFsPaths("a\\b\\..\\c"), "a\\b\\..\\c");
- UNIT_ASSERT_VALUES_EQUAL(JoinFsPaths("a\\b", ""), "a\\b");
- #else
- UNIT_ASSERT_VALUES_EQUAL(JoinFsPaths("a/b", "c/d"), "a/b/c/d");
- UNIT_ASSERT_VALUES_EQUAL(JoinFsPaths("a/b", "../c"), "a/b/../c");
- UNIT_ASSERT_VALUES_EQUAL(JoinFsPaths("a/b/../c", "d"), "a/c/d");
- UNIT_ASSERT_VALUES_EQUAL(JoinFsPaths("a", "b", "c", "d"), "a/b/c/d");
- UNIT_ASSERT_VALUES_EQUAL(JoinFsPaths("a/b/../c"), "a/b/../c");
- UNIT_ASSERT_VALUES_EQUAL(JoinFsPaths("a/b", ""), "a/b");
- #endif
- }
- Y_UNIT_TEST(TestStringCast) {
- TFsPath pathOne;
- UNIT_ASSERT(TryFromString<TFsPath>("/a/b", pathOne));
- UNIT_ASSERT_VALUES_EQUAL(pathOne, TFsPath{"/a/b"});
- TFsPath pathTwo;
- UNIT_ASSERT_NO_EXCEPTION(TryFromString<TFsPath>("/a/b", pathTwo));
- UNIT_ASSERT_VALUES_EQUAL(FromString<TFsPath>("/a/b"), TFsPath{"/a/b"});
- TFsPath pathThree{"/a/b"};
- UNIT_ASSERT_VALUES_EQUAL(ToString(pathThree), "/a/b");
- }
- #ifdef _unix_
- Y_UNIT_TEST(TestRemoveSymlinkToDir) {
- TTempDir tempDir;
- TFsPath tempDirPath(tempDir());
- const TString originDir = tempDirPath.Child("origin");
- MakePathIfNotExist(originDir.c_str());
- const TString originFile = TFsPath(originDir).Child("data");
- {
- TFixedBufferFileOutput out(originFile);
- out << "data111!!!";
- }
- const TString link = tempDirPath.Child("origin_symlink");
- NFs::SymLink(originDir, link);
- TFsPath(link).ForceDelete();
- UNIT_ASSERT(!NFs::Exists(link));
- UNIT_ASSERT(NFs::Exists(originFile));
- UNIT_ASSERT(NFs::Exists(originDir));
- }
- Y_UNIT_TEST(TestRemoveSymlinkToFile) {
- TTempDir tempDir;
- TFsPath tempDirPath(tempDir());
- const TString originDir = tempDirPath.Child("origin");
- MakePathIfNotExist(originDir.c_str());
- const TString originFile = TFsPath(originDir).Child("data");
- {
- TFixedBufferFileOutput out(originFile);
- out << "data111!!!";
- }
- const TString link = tempDirPath.Child("origin_symlink");
- NFs::SymLink(originFile, link);
- TFsPath(link).ForceDelete();
- UNIT_ASSERT(!NFs::Exists(link));
- UNIT_ASSERT(NFs::Exists(originFile));
- UNIT_ASSERT(NFs::Exists(originDir));
- }
- Y_UNIT_TEST(TestRemoveDirWithSymlinkToDir) {
- TTempDir tempDir;
- TFsPath tempDirPath(tempDir());
- const TString symlinkedDir = tempDirPath.Child("to_remove");
- MakePathIfNotExist(symlinkedDir.c_str());
- const TString originDir = tempDirPath.Child("origin");
- MakePathIfNotExist(originDir.c_str());
- const TString originFile = TFsPath(originDir).Child("data");
- {
- TFixedBufferFileOutput out(originFile);
- out << "data111!!!";
- }
- const TString symlinkedFile = TFsPath(symlinkedDir).Child("origin_symlink");
- NFs::SymLink(originDir, symlinkedFile);
- TFsPath(symlinkedDir).ForceDelete();
- UNIT_ASSERT(!NFs::Exists(symlinkedFile));
- UNIT_ASSERT(!NFs::Exists(symlinkedDir));
- UNIT_ASSERT(NFs::Exists(originFile));
- UNIT_ASSERT(NFs::Exists(originDir));
- }
- Y_UNIT_TEST(TestRemoveDirWithSymlinkToFile) {
- TTempDir tempDir;
- TFsPath tempDirPath(tempDir());
- const TString symlinkedDir = tempDirPath.Child("to_remove");
- MakePathIfNotExist(symlinkedDir.c_str());
- const TString originDir = tempDirPath.Child("origin");
- MakePathIfNotExist(originDir.c_str());
- const TString originFile = TFsPath(originDir).Child("data");
- {
- TFixedBufferFileOutput out(originFile);
- out << "data111!!!";
- }
- const TString symlinkedFile = TFsPath(symlinkedDir).Child("origin_symlink");
- NFs::SymLink(originFile, symlinkedFile);
- TFsPath(symlinkedDir).ForceDelete();
- UNIT_ASSERT(!NFs::Exists(symlinkedFile));
- UNIT_ASSERT(!NFs::Exists(symlinkedDir));
- UNIT_ASSERT(NFs::Exists(originFile));
- UNIT_ASSERT(NFs::Exists(originDir));
- }
- #endif
- Y_UNIT_TEST(TestForceDeleteNonexisting) {
- TTempDir tempDir;
- TFsPath nonexisting = TFsPath(tempDir()).Child("nonexisting");
- nonexisting.ForceDelete();
- }
- // Here we want to test that all possible errors during TFsPath::ForceDelete
- // are properly handled. To do so we have to trigger fs operation errors in
- // three points:
- // 1. stat/GetFileInformationByHandle
- // 2. opendir
- // 3. unlink/rmdir
- //
- // On unix systems we can achieve this by simply setting access rights on
- // entry being deleted and its parent. But on windows it is more complicated.
- // Current Chmod implementation on windows is not enough as it sets only
- // FILE_ATTRIBUTE_READONLY throught SetFileAttributes call. But doing so does
- // not affect directory access rights on older versions of Windows and Wine
- // that we use to run autocheck tests.
- //
- // To get required access rights we use DACL in SetSecurityInfo. This is wrapped
- // in RAII class that drops requested permissions on file/dir and grantss them
- // back in destructor.
- //
- // Another obstacle is FILE_LIST_DIRECTORY permission when running on Wine.
- // Dropping this permission is necessary to provoke error
- // in GetFileInformationByHandle. Wine allows dropping this permission, but I
- // have not found a way to grant it back. So tests crash during cleanup sequence.
- // To make it possible to run this tests natively we detect Wine with special
- // registry key and skip these tests only there.
- #ifdef _win_
- struct TLocalFree {
- static void Destroy(void* ptr) {
- LocalFree((HLOCAL)ptr);
- }
- };
- bool IsWine() {
- HKEY subKey = nullptr;
- LONG result = RegOpenKeyEx(HKEY_CURRENT_USER, "Software\\Wine", 0, KEY_READ, &subKey);
- if (result == ERROR_SUCCESS) {
- return true;
- }
- result = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "Software\\Wine", 0, KEY_READ, &subKey);
- if (result == ERROR_SUCCESS) {
- return true;
- }
- HMODULE hntdll = GetModuleHandle("ntdll.dll");
- if (!hntdll) {
- return false;
- }
- auto func = GetProcAddress(hntdll, "wine_get_version");
- return func != nullptr;
- }
- class TWinFileDenyAccessScope {
- public:
- TWinFileDenyAccessScope(const TFsPath& name, DWORD permissions)
- : Name_(name)
- , Perms_(permissions)
- {
- DWORD res = 0;
- PACL oldAcl = nullptr;
- PSECURITY_DESCRIPTOR sd = nullptr;
- res = GetNamedSecurityInfoA((LPSTR)name.c_str(),
- SE_FILE_OBJECT,
- DACL_SECURITY_INFORMATION,
- nullptr,
- nullptr,
- &oldAcl,
- nullptr,
- &sd);
- SdHolder_.Reset(sd);
- if (res != ERROR_SUCCESS) {
- ythrow TSystemError(res) << "error in GetNamedSecurityInfoA";
- }
- Acl_ = SetAcl(oldAcl, DENY_ACCESS);
- }
- ~TWinFileDenyAccessScope() {
- try {
- const TFsPath parent = Name_.Parent();
- Chmod(parent.c_str(), MODE0777);
- Chmod(Name_.c_str(), MODE0777);
- SetAcl((PACL)Acl_.Get(), GRANT_ACCESS);
- } catch (const yexception& ex) {
- Cerr << "~TWinFileDenyAccessScope failed: " << ex.AsStrBuf() << Endl;
- }
- }
- THolder<void, TLocalFree> SetAcl(PACL oldAcl, ACCESS_MODE accessMode) {
- DWORD res = 0;
- EXPLICIT_ACCESS ea;
- PACL newAcl = nullptr;
- THolder<void, TLocalFree> newAclHolder;
- memset(&ea, 0, sizeof(EXPLICIT_ACCESS));
- ea.grfAccessPermissions = Perms_;
- ea.grfAccessMode = accessMode;
- ea.grfInheritance = NO_INHERITANCE;
- ea.Trustee.TrusteeForm = TRUSTEE_IS_NAME;
- ea.Trustee.ptstrName = (LPSTR) "CURRENT_USER";
- res = SetEntriesInAcl(1, &ea, oldAcl, &newAcl);
- newAclHolder.Reset(newAcl);
- if (res != ERROR_SUCCESS) {
- ythrow TSystemError(res) << "error in SetEntriesInAcl";
- }
- res = SetNamedSecurityInfoA((LPSTR)Name_.c_str(),
- SE_FILE_OBJECT,
- DACL_SECURITY_INFORMATION,
- nullptr,
- nullptr,
- newAcl,
- nullptr);
- if (res != ERROR_SUCCESS) {
- ythrow TSystemError(res) << "error in SetNamedSecurityInfoA";
- }
- return std::move(newAclHolder);
- }
- private:
- const TFsPath Name_;
- const DWORD Perms_;
- THolder<void, TLocalFree> SdHolder_;
- THolder<void, TLocalFree> Acl_;
- };
- #endif
- Y_UNIT_TEST(TestForceDeleteErrorUnlink) {
- TTempDir tempDir;
- const TFsPath testDir = TFsPath(tempDir()).Child("dir");
- MakePathIfNotExist(testDir.c_str());
- const TFsPath testFile = testDir.Child("file");
- {
- TFixedBufferFileOutput out(testFile);
- out << "data111!!!";
- }
- #ifdef _win_
- Chmod(testFile.c_str(), S_IRUSR);
- Y_DEFER {
- Chmod(testFile.c_str(), MODE0777);
- };
- #else
- Chmod(testDir.c_str(), S_IRUSR | S_IXUSR);
- Y_DEFER {
- Chmod(testDir.c_str(), MODE0777);
- };
- #endif
- UNIT_ASSERT_EXCEPTION_CONTAINS(testFile.ForceDelete(), TIoException, "failed to delete");
- }
- Y_UNIT_TEST(TestForceDeleteErrorRmdir) {
- TTempDir tempDir;
- const TFsPath testDir = TFsPath(tempDir()).Child("dir");
- const TFsPath testSubdir = testDir.Child("file");
- MakePathIfNotExist(testSubdir.c_str());
- #ifdef _win_
- Chmod(testSubdir.c_str(), 0);
- Y_DEFER {
- Chmod(testSubdir.c_str(), MODE0777);
- };
- TWinFileDenyAccessScope dirAcl(testDir, FILE_WRITE_DATA);
- #else
- Chmod(testDir.c_str(), S_IRUSR | S_IXUSR);
- Y_DEFER {
- Chmod(testDir.c_str(), MODE0777);
- };
- #endif
- UNIT_ASSERT_EXCEPTION_CONTAINS(testSubdir.ForceDelete(), TIoException, "failed to delete");
- }
- Y_UNIT_TEST(TestForceDeleteErrorStatDir) {
- TTempDir tempDir;
- const TFsPath testDir = TFsPath(tempDir()).Child("dir");
- const TFsPath testSubdir = testDir.Child("file");
- MakePathIfNotExist(testSubdir.c_str());
- #ifdef _win_
- if (IsWine()) {
- // FILE_LIST_DIRECTORY seem to be irreversible on wine
- return;
- }
- TWinFileDenyAccessScope subdirAcl(testSubdir, FILE_READ_ATTRIBUTES);
- TWinFileDenyAccessScope dirAcl(testDir, FILE_LIST_DIRECTORY);
- #else
- Chmod(testDir.c_str(), 0);
- Y_DEFER {
- Chmod(testDir.c_str(), MODE0777);
- };
- #endif
- UNIT_ASSERT_EXCEPTION_CONTAINS(testSubdir.ForceDelete(), TIoException, "failed to stat");
- }
- Y_UNIT_TEST(TestForceDeleteErrorStatFile) {
- TTempDir tempDir;
- const TFsPath testDir = TFsPath(tempDir()).Child("dir");
- MakePathIfNotExist(testDir.c_str());
- const TFsPath testFile = testDir.Child("file");
- {
- TFixedBufferFileOutput out(testFile);
- out << "data111!!!";
- }
- #ifdef _win_
- if (IsWine()) {
- // FILE_LIST_DIRECTORY seem to be irreversible on wine
- return;
- }
- TWinFileDenyAccessScope fileAcl(testFile, FILE_READ_ATTRIBUTES);
- TWinFileDenyAccessScope dirAcl(testDir, FILE_LIST_DIRECTORY);
- #else
- Chmod(testDir.c_str(), 0);
- Y_DEFER {
- Chmod(testDir.c_str(), MODE0777);
- };
- #endif
- UNIT_ASSERT_EXCEPTION_CONTAINS(testFile.ForceDelete(), TIoException, "failed to stat");
- }
- Y_UNIT_TEST(TestForceDeleteErrorListDir) {
- TTempDir tempDir;
- const TFsPath testDir = TFsPath(tempDir()).Child("dir");
- const TFsPath testSubdir = testDir.Child("file");
- MakePathIfNotExist(testSubdir.c_str());
- #ifdef _win_
- if (IsWine()) {
- // FILE_LIST_DIRECTORY seem to be irreversible on wine
- return;
- }
- TWinFileDenyAccessScope subdirAcl(testSubdir, FILE_LIST_DIRECTORY);
- #else
- Chmod(testSubdir.c_str(), 0);
- Y_DEFER {
- Chmod(testSubdir.c_str(), MODE0777);
- };
- #endif
- UNIT_ASSERT_EXCEPTION_CONTAINS(testSubdir.ForceDelete(), TIoException, "failed to opendir");
- }
- #ifdef _unix_
- Y_UNIT_TEST(TestForceDeleteErrorSymlink) {
- TTempDir tempDir;
- const TFsPath testDir = TFsPath(tempDir()).Child("dir");
- MakePathIfNotExist(testDir.c_str());
- const TFsPath testSymlink = testDir.Child("symlink");
- NFs::SymLink("something", testSymlink);
- Chmod(testSymlink.c_str(), S_IRUSR);
- Chmod(testDir.c_str(), S_IRUSR | S_IXUSR);
- Y_DEFER {
- Chmod(testDir.c_str(), MODE0777);
- Chmod(testSymlink.c_str(), MODE0777);
- };
- UNIT_ASSERT_EXCEPTION_CONTAINS(testSymlink.ForceDelete(), TIoException, "failed to delete");
- }
- #endif
- Y_UNIT_TEST(TestCopyWithInitializedSplit) {
- const TFsPath path1 = TFsPath("some_folder_with_file") / TFsPath("file_in_folder");
- path1.PathSplit();
- const TFsPath path2 = path1;
- const TPathSplit& split2 = path2.PathSplit();
- for (const auto& it : split2) {
- UNIT_ASSERT(path2.GetPath().begin() <= it.begin());
- UNIT_ASSERT(it.end() <= path2.GetPath().end());
- }
- }
- Y_UNIT_TEST(TestAssignmentWithInitializedSplit) {
- TFsPath path1 = TFsPath("some_folder_with_file_1") / TFsPath("file_in_folder_1");
- TFsPath path2 = TFsPath("some_folder_with_file_2") / TFsPath("file_in_folder_2");
- path1.PathSplit();
- path1 = path2;
- UNIT_ASSERT_VALUES_EQUAL(path1.PathSplit().at(1), "file_in_folder_2");
- }
- #ifdef TSTRING_IS_STD_STRING
- Y_UNIT_TEST(TestCopySplitSSO) {
- // Summary length of path must be less minimal SSO length 19 bytes
- constexpr TStringBuf A("a");
- constexpr TStringBuf B("b");
- constexpr TStringBuf C("c");
- for (auto constructorType = 0; constructorType < 2; ++constructorType) {
- TFsPath path1 = TFsPath(A) / TFsPath(B);
- const auto& split1 = path1.PathSplit();
- // Check split of path1
- UNIT_ASSERT_VALUES_EQUAL(split1.size(), 2);
- UNIT_ASSERT_VALUES_EQUAL(split1.at(0), A);
- UNIT_ASSERT_VALUES_EQUAL(split1.at(1), B);
- TFsPath path2;
- if (constructorType == 0) { // copy
- path2 = TFsPath(path1); // copy constructor
- } else if (constructorType == 1) { // move
- path2 = TFsPath(std::move(path1)); // move constructor
- }
- const auto& split2 = path2.PathSplit();
- path1 = TFsPath(C); // invalidate previous Path_ in path1
- const auto& newsplit1 = path1.PathSplit();
- // Check that split of path1 was overwrited (invalidate previous TStringBuf)
- UNIT_ASSERT_VALUES_EQUAL(newsplit1.size(), 1);
- UNIT_ASSERT_VALUES_EQUAL(newsplit1.at(0), C);
- // Check split of path2 without segfault
- UNIT_ASSERT_VALUES_EQUAL(split2.size(), 2);
- UNIT_ASSERT_VALUES_EQUAL(split2.at(0), A);
- UNIT_ASSERT_VALUES_EQUAL(split2.at(1), B);
- }
- }
- #endif
- Y_UNIT_TEST(TestCopySplitNoneSSO) {
- // Lenght of directory name must overhead SSO length 19-23 bytes
- const TString DIR_A = TString("Dir") + TString(32, 'A');
- const TString DIR_B = TString("Dir") + TString(64, 'B');
- const TString DIR_C = TString("Dir") + TString(128, 'C');
- for (auto constructorType = 0; constructorType < 2; ++constructorType) {
- TFsPath path1 = TFsPath(DIR_A) / TFsPath(DIR_B);
- auto& split1 = path1.PathSplit();
- // Check split of path1
- UNIT_ASSERT_VALUES_EQUAL(split1.size(), 2);
- UNIT_ASSERT_VALUES_EQUAL(split1.at(0), DIR_A);
- UNIT_ASSERT_VALUES_EQUAL(split1.at(1), DIR_B);
- TFsPath path2;
- if (constructorType == 0) { // copy
- path2 = TFsPath(path1); // copy constructor
- } else if (constructorType == 1) { // move
- path2 = TFsPath(std::move(path1)); // move constructor
- }
- const auto& split2 = path2.PathSplit();
- path1 = TFsPath(DIR_C); // invalidate previous Path_ in path1
- const auto& newsplit1 = path1.PathSplit();
- // Check that split of path1 was overwrited (invalidate previous TStringBuf)
- UNIT_ASSERT_VALUES_EQUAL(newsplit1.size(), 1);
- UNIT_ASSERT_VALUES_EQUAL(newsplit1.at(0), DIR_C);
- // Check split of path2 without segfault
- UNIT_ASSERT_VALUES_EQUAL(split2.size(), 2);
- UNIT_ASSERT_VALUES_EQUAL(split2.at(0), DIR_A);
- UNIT_ASSERT_VALUES_EQUAL(split2.at(1), DIR_B);
- }
- }
- }
|