def _verify_orphans_extracted(self, log_dir: Path, expected_errors: List[ExpectedError], new_fsck=False) -> None: # Build the state that we expect to find in the lost+found directory expected = verify_mod.ExpectedFileSet() for error in expected_errors: if isinstance(error, OrphanInodes): self._build_expected_orphans(expected, error, new_fsck) elif isinstance(error, InvalidMaterializedInode): # The Python fsck code extracts broken data files into a separate # "broken_inodes" subdirectory, but the newer C++ logic puts everything # into the single "lost+found" directory. if new_fsck: extracted_path = os.path.join( str(error.parent_inode_number), os.path.basename(error.path)) expected.add_file(extracted_path, error.bad_data, perms=0o644) verifier = verify_mod.SnapshotVerifier() verifier.verify_directory(log_dir / "lost+found", expected) if verifier.errors: self.fail(f"found errors when checking extracted orphan inodes: " f"{verifier.errors}")
def _verify_orphans_extracted(self, log_dir: Path, orphan_errors: OrphanInodes) -> None: # Build the state that we expect to find in the lost+found directory expected = verify_mod.ExpectedFileSet() # All of the orphan files should be extracted as regular files using their inode # number as the path. We cannot tell if the inodes were originally regular # files, symlinks, or sockets, so everything just gets extracted as a regular # file. for orphan_file in orphan_errors.files: expected.add_file( str(orphan_file.inode_number), orphan_file.file_info.contents, perms=0o600, ) # All of the orphan directories will be extracted as directories. # For their contents we know file types but not permissions. for orphan_dir in orphan_errors.dirs: dir_inode = Path(str(orphan_dir.inode_number)) for expected_file in orphan_dir.contents: orphan_path = dir_inode / expected_file.path.relative_to( orphan_dir.path) if expected_file.file_type == stat_mod.S_IFSOCK: # socket files are ignored and never extracted continue elif expected_file.file_type == stat_mod.S_IFLNK: expected.add_symlink(orphan_path, expected_file.contents, perms=0o777) elif expected_file.file_type == stat_mod.S_IFREG: expected.add_file(orphan_path, expected_file.contents, perms=0o600) else: raise Exception( "unknown file type for expected orphan inode") verifier = verify_mod.SnapshotVerifier() verifier.verify_directory(log_dir / "lost+found", expected) if verifier.errors: self.fail(f"found errors when checking extracted orphan inodes: " f"{verifier.errors}")
def get_expected_files(self) -> verify_mod.ExpectedFileSet: # Confirm that the files look like what we expect files = verify_mod.ExpectedFileSet() # TODO: These symlink permissions should ideally be 0o777 files.add_symlink(".eden/root", bytes(self.checkout_path), 0o770) files.add_symlink(".eden/client", bytes(self.eden_state_dir / "clients" / "checkout"), 0o770) files.add_symlink(".eden/socket", bytes(self.eden_state_dir / "socket"), 0o770) files.add_symlink(".eden/this-dir", bytes(self.checkout_path / ".eden"), 0o770) files.add_file("README.md", b"project docs", 0o644) files.add_file(".gitignore", b"ignored.txt\n", 0o644) files.add_file("main/loaded_dir/loaded_file.c", b"loaded", 0o644) files.add_file("main/loaded_dir/not_loaded_file.c", b"not loaded", 0o644) files.add_file("main/loaded_dir/not_loaded_exe.sh", b"not loaded", 0o755) files.add_file("main/loaded_dir/loaded_subdir/dir1/file1.txt", b"text\n", 0o644) files.add_file("main/loaded_dir/loaded_subdir/dir2/file2.txt", b"more text\n", 0o644) files.add_file("main/loaded_dir/not_loaded_subdir/a.txt", b"some contents\n", 0o644) files.add_file("main/loaded_dir/not_loaded_subdir/b.exe", b"other contents", 0o755) files.add_file("main/materialized_subdir/script.sh", b"new script contents", 0o755) files.add_file("main/materialized_subdir/test.c", b"new test contents", 0o644) files.add_file("main/materialized_subdir/unmodified.txt", b"original contents", 0o644) files.add_symlink("main/materialized_subdir/modified_symlink.lnk", b"new link", 0o770) files.add_symlink("main/materialized_subdir/new_symlink.lnk", b"new link", 0o770) files.add_socket("main/materialized_subdir/test/socket.sock", 0o600) files.add_file("main/mode_changes/normal_to_exe.txt", b"will change mode", 0o755) files.add_file("main/mode_changes/exe_to_normal.txt", b"will change mode", 0o644) files.add_file("main/mode_changes/normal_to_readonly.txt", b"will be readonly", 0o400) files.add_file("main/untracked.txt", b"new new untracked file", 0o644) files.add_file("main/ignored.txt", b"new ignored file", 0o644) files.add_file("main/untracked_dir/foo.txt", b"foobar", 0o644) files.add_file("never_accessed/foo/bar/baz.txt", b"baz\n", 0o644) files.add_file("never_accessed/foo/bar/xyz.txt", b"xyz\n", 0o644) files.add_file("never_accessed/foo/file.txt", b"data\n", 0o644) files.add_symlink("never_accessed/foo/some.lnk", b"link destination", 0o755) files.add_file("untracked/new/normal.txt", b"new src contents", 0o644) files.add_file("untracked/new/normal2.txt", b"extra src contents", 0o644) files.add_file("untracked/new/readonly.txt", b"new readonly contents", 0o400) files.add_file("untracked/new/subdir/abc.txt", b"abc", 0o644) files.add_file("untracked/new/subdir/xyz.txt", b"xyz", 0o644) files.add_file("untracked/executable.exe", b"do stuff", 0o755) files.add_socket("untracked/everybody.sock", 0o666) files.add_socket("untracked/owner_only.sock", 0o600) return files