llvm.org GIT mirror llvm / f1309ff
Revert "[VFS] Allow multiple RealFileSystem instances with independent CWDs." This reverts commit r351079, r351069 and r351050 as it broken the greendragon bots on macOS. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@351091 91177308-0d34-0410-b5e6-96231b3b80d8 Amara Emerson 1 year, 9 months ago
3 changed file(s) with 30 addition(s) and 161 deletion(s). Raw diff Collapse all Expand all
297297
298298 /// Gets an \p vfs::FileSystem for the 'real' file system, as seen by
299299 /// the operating system.
300 /// The working directory is linked to the process's working directory.
301 /// (This is usually thread-hostile).
302300 IntrusiveRefCntPtr getRealFileSystem();
303
304 /// Create an \p vfs::FileSystem for the 'real' file system, as seen by
305 /// the operating system.
306 /// It has its own working directory, independent of (but initially equal to)
307 /// that of the process.
308 std::unique_ptr createPhysicalFileSystem();
309301
310302 /// A file system that allows overlaying one \p AbstractFileSystem on top
311303 /// of another.
227227
228228 namespace {
229229
230 /// A file system according to your operating system.
231 /// This may be linked to the process's working directory, or maintain its own.
232 ///
233 /// Currently, its own working directory is emulated by storing the path and
234 /// sending absolute paths to llvm::sys::fs:: functions.
235 /// A more principled approach would be to push this down a level, modelling
236 /// the working dir as an llvm::sys::fs::WorkingDir or similar.
237 /// This would enable the use of openat()-style functions on some platforms.
230 /// The file system according to your operating system.
238231 class RealFileSystem : public FileSystem {
239232 public:
240 explicit RealFileSystem(bool LinkCWDToProcess) {
241 if (!LinkCWDToProcess) {
242 SmallString<128> PWD, RealPWD;
243 if (llvm::sys::fs::current_path(PWD))
244 return; // Awful, but nothing to do here.
245 if (llvm::sys::fs::real_path(PWD, RealPWD))
246 WD = {PWD, PWD};
247 else
248 WD = {PWD, RealPWD};
249 }
250 }
251
252233 ErrorOr status(const Twine &Path) override;
253234 ErrorOr> openFileForRead(const Twine &Path) override;
254235 directory_iterator dir_begin(const Twine &Dir, std::error_code &EC) override;
260241 SmallVectorImpl &Output) const override;
261242
262243 private:
263 // If this FS has its own working dir, use it to make Path absolute.
264 // The returned twine is safe to use as long as both Storage and Path live.
265 Twine adjustPath(const Twine &Path, SmallVectorImpl &Storage) const {
266 if (!WD)
267 return Path;
268 Path.toVector(Storage);
269 sys::fs::make_absolute(WD->Resolved, Storage);
270 return Storage;
271 }
272
273 struct WorkingDirectory {
274 // The current working directory, without symlinks resolved. (echo $PWD).
275 SmallString<128> Specified;
276 // The current working directory, with links resolved. (readlink .).
277 SmallString<128> Resolved;
278 };
279 Optional WD;
244 mutable std::mutex CWDMutex;
245 mutable std::string CWDCache;
280246 };
281247
282248 } // namespace
283249
284250 ErrorOr RealFileSystem::status(const Twine &Path) {
285 SmallString<256> Storage;
286251 sys::fs::file_status RealStatus;
287 if (std::error_code EC =
288 sys::fs::status(adjustPath(Path, Storage), RealStatus))
252 if (std::error_code EC = sys::fs::status(Path, RealStatus))
289253 return EC;
290254 return Status::copyWithNewName(RealStatus, Path.str());
291255 }
293257 ErrorOr>
294258 RealFileSystem::openFileForRead(const Twine &Name) {
295259 int FD;
296 SmallString<256> RealName, Storage;
297 if (std::error_code EC = sys::fs::openFileForRead(
298 adjustPath(Name, Storage), FD, sys::fs::OF_None, &RealName))
260 SmallString<256> RealName;
261 if (std::error_code EC =
262 sys::fs::openFileForRead(Name, FD, sys::fs::OF_None, &RealName))
299263 return EC;
300264 return std::unique_ptr(new RealFile(FD, Name.str(), RealName.str()));
301265 }
302266
303267 llvm::ErrorOr RealFileSystem::getCurrentWorkingDirectory() const {
304 if (WD)
305 return WD->Specified.str();
306
307 SmallString<128> Dir;
268 std::lock_guard Lock(CWDMutex);
269 if (!CWDCache.empty())
270 return CWDCache;
271 SmallString<256> Dir;
308272 if (std::error_code EC = llvm::sys::fs::current_path(Dir))
309273 return EC;
310 return Dir.str();
274 CWDCache = Dir.str();
275 return CWDCache;
311276 }
312277
313278 std::error_code RealFileSystem::setCurrentWorkingDirectory(const Twine &Path) {
314 if (!WD)
315 return llvm::sys::fs::set_current_path(Path);
316
317 SmallString<128> Absolute, Resolved, Storage;
318 adjustPath(Path, Storage).toVector(Absolute);
319 bool IsDir;
320 if (auto Err = llvm::sys::fs::is_directory(Absolute, IsDir))
321 return Err;
322 if (!IsDir)
323 return std::make_error_code(std::errc::not_a_directory);
324 if (auto Err = llvm::sys::fs::real_path(Absolute, Resolved))
325 return Err;
326 WD = {Absolute, Resolved};
279 // FIXME: chdir is thread hostile; on the other hand, creating the same
280 // behavior as chdir is complex: chdir resolves the path once, thus
281 // guaranteeing that all subsequent relative path operations work
282 // on the same path the original chdir resulted in. This makes a
283 // difference for example on network filesystems, where symlinks might be
284 // switched during runtime of the tool. Fixing this depends on having a
285 // file system abstraction that allows openat() style interactions.
286 if (auto EC = llvm::sys::fs::set_current_path(Path))
287 return EC;
288
289 // Invalidate cache.
290 std::lock_guard Lock(CWDMutex);
291 CWDCache.clear();
327292 return std::error_code();
328293 }
329294
330295 std::error_code RealFileSystem::isLocal(const Twine &Path, bool &Result) {
331 SmallString<256> Storage;
332 return llvm::sys::fs::is_local(adjustPath(Path, Storage), Result);
296 return llvm::sys::fs::is_local(Path, Result);
333297 }
334298
335299 std::error_code
336300 RealFileSystem::getRealPath(const Twine &Path,
337301 SmallVectorImpl &Output) const {
338 SmallString<256> Storage;
339 return llvm::sys::fs::real_path(adjustPath(Path, Storage), Output);
302 return llvm::sys::fs::real_path(Path, Output);
340303 }
341304
342305 IntrusiveRefCntPtr vfs::getRealFileSystem() {
343 static IntrusiveRefCntPtr FS(new RealFileSystem(true));
306 static IntrusiveRefCntPtr FS = new RealFileSystem();
344307 return FS;
345 }
346
347 std::unique_ptr vfs::createPhysicalFileSystem() {
348 return llvm::make_unique(false);
349308 }
350309
351310 namespace {
373332
374333 directory_iterator RealFileSystem::dir_begin(const Twine &Dir,
375334 std::error_code &EC) {
376 SmallString<128> Storage;
377 return directory_iterator(
378 std::make_shared(adjustPath(Dir, Storage), EC));
335 return directory_iterator(std::make_shared(Dir, EC));
379336 }
380337
381338 //===-----------------------------------------------------------------------===/
381381 }
382382 operator StringRef() { return Path.str(); }
383383 };
384
385 struct ScopedFile {
386 SmallString<128> Path;
387 ScopedFile(const Twine &Path, StringRef Contents) {
388 Path.toVector(this->Path);
389 std::error_code EC;
390 raw_fd_ostream OS(this->Path, EC);
391 EXPECT_FALSE(EC);
392 OS << Contents;
393 OS.flush();
394 EXPECT_FALSE(OS.error());
395 if (EC || OS.error())
396 this->Path = "";
397 }
398 ~ScopedFile() {
399 if (Path != "")
400 EXPECT_FALSE(llvm::sys::fs::remove(Path.str()));
401 }
402 };
403384 } // end anonymous namespace
404385
405386 TEST(VirtualFileSystemTest, BasicRealFSIteration) {
430411 }
431412
432413 #ifdef LLVM_ON_UNIX
433 TEST(VirtualFileSystemTest, MultipleWorkingDirs) {
434 // Our root contains a/aa, b/bb, c, where c is a link to a/.
435 // Run tests both in root/b/ and root/c/ (to test "normal" and symlink dirs).
436 // Interleave operations to show the working directories are independent.
437 ScopedDir Root("r", true), ADir(Root.Path + "/a"), BDir(Root.Path + "/b");
438 ScopedLink C(ADir.Path, Root.Path + "/c");
439 ScopedFile AA(ADir.Path + "/aa", "aaaa"), BB(BDir.Path + "/bb", "bbbb");
440 std::unique_ptr BFS = vfs::createPhysicalFileSystem(),
441 CFS = vfs::createPhysicalFileSystem();
442
443 ASSERT_FALSE(BFS->setCurrentWorkingDirectory(BDir.Path));
444 ASSERT_FALSE(CFS->setCurrentWorkingDirectory(C.Path));
445 EXPECT_EQ(BDir.Path, *BFS->getCurrentWorkingDirectory());
446 EXPECT_EQ(C.Path, *CFS->getCurrentWorkingDirectory());
447
448 // openFileForRead(), indirectly.
449 auto BBuf = BFS->getBufferForFile("bb");
450 ASSERT_TRUE(BBuf);
451 EXPECT_EQ("bbbb", (*BBuf)->getBuffer());
452
453 auto ABuf = CFS->getBufferForFile("aa");
454 ASSERT_TRUE(ABuf);
455 EXPECT_EQ("aaaa", (*ABuf)->getBuffer());
456
457 // status()
458 auto BStat = BFS->status("bb");
459 ASSERT_TRUE(BStat);
460 EXPECT_EQ("bb", BStat->getName());
461
462 auto AStat = CFS->status("aa");
463 ASSERT_TRUE(AStat);
464 EXPECT_EQ("aa", AStat->getName()); // unresolved name
465
466 // getRealPath()
467 SmallString<128> BPath;
468 ASSERT_FALSE(BFS->getRealPath("bb", BPath));
469 EXPECT_EQ(BB.Path, BPath);
470
471 SmallString<128> APath;
472 ASSERT_FALSE(CFS->getRealPath("aa", APath));
473 EXPECT_EQ(AA.Path, APath); // Reports resolved name.
474
475 // dir_begin
476 std::error_code EC;
477 auto BIt = BFS->dir_begin(".", EC);
478 ASSERT_FALSE(EC);
479 ASSERT_NE(BIt, vfs::directory_iterator());
480 EXPECT_EQ((BDir.Path + "/./bb").str(), BIt->path());
481 BIt.increment(EC);
482 ASSERT_FALSE(EC);
483 ASSERT_EQ(BIt, vfs::directory_iterator());
484
485 auto CIt = CFS->dir_begin(".", EC);
486 ASSERT_FALSE(EC);
487 ASSERT_NE(CIt, vfs::directory_iterator());
488 EXPECT_EQ((ADir.Path + "/./aa").str(), CIt->path()); // Partly resolved name!
489 CIt.increment(EC); // Because likely to read through this path.
490 ASSERT_FALSE(EC);
491 ASSERT_EQ(CIt, vfs::directory_iterator());
492 }
493
494414 TEST(VirtualFileSystemTest, BrokenSymlinkRealFSIteration) {
495415 ScopedDir TestDirectory("virtual-file-system-test", /*Unique*/ true);
496416 IntrusiveRefCntPtr FS = vfs::getRealFileSystem();