def check_materialized_are_accessible( tracker: ProblemTracker, instance: EdenInstance, checkout: EdenCheckout, ) -> None: mismatched_mode = [] inaccessible_inodes = [] with instance.get_thrift_client_legacy() as client: materialized = client.debugInodeStatus( bytes(checkout.path), b"", flags=DIS_REQUIRE_MATERIALIZED, sync=SyncBehavior(), ) for materialized_dir in materialized: path = Path(os.fsdecode(materialized_dir.path)) try: st = os.lstat(checkout.path / path) except OSError: inaccessible_inodes += [path] continue if not stat.S_ISDIR(st.st_mode): mismatched_mode += [(path, stat.S_IFDIR, st.st_mode)] for dirent in materialized_dir.entries: if dirent.materialized: dirent_path = path / Path(os.fsdecode(dirent.name)) try: dirent_stat = os.lstat(checkout.path / dirent_path) except OSError: inaccessible_inodes += [dirent_path] continue # TODO(xavierd): Symlinks are for now recognized as files. dirent_mode = (stat.S_IFREG if stat.S_ISLNK( dirent_stat.st_mode) else stat.S_IFMT(dirent_stat.st_mode)) if dirent_mode != stat.S_IFMT(dirent.mode): mismatched_mode += [(dirent_path, dirent_stat.st_mode, dirent.mode)] if inaccessible_inodes != []: tracker.add_problem( MaterializedInodesAreInaccessible(inaccessible_inodes)) if mismatched_mode != []: tracker.add_problem( MaterializedInodesHaveDifferentModeOnDisk(mismatched_mode))
def check_loaded_content( tracker: ProblemTracker, instance: EdenInstance, checkout: EdenCheckout, query_prjfs_file: Callable[[Path], PRJ_FILE_STATE], ) -> None: with instance.get_thrift_client_legacy() as client: loaded = client.debugInodeStatus( bytes(checkout.path), b"", flags=DIS_REQUIRE_LOADED, sync=SyncBehavior(), ) errors = [] for loaded_dir in loaded: path = Path(os.fsdecode(loaded_dir.path)) for dirent in loaded_dir.entries: if not stat.S_ISREG(dirent.mode) or dirent.materialized: continue dirent_path = path / Path(os.fsdecode(dirent.name)) filestate = query_prjfs_file(checkout.path / dirent_path) if (filestate & PRJ_FILE_STATE.HydratedPlaceholder != PRJ_FILE_STATE.HydratedPlaceholder): # We should only compute the sha1 of files that have been read. continue def compute_file_sha1(file: Path) -> bytes: hasher = hashlib.sha1() with open(checkout.path / dirent_path, "rb") as f: while True: buf = f.read(1024 * 1024) if buf == b"": break hasher.update(buf) return hasher.digest() sha1 = client.getSHA1(bytes(checkout.path), [bytes(dirent_path)], sync=SyncBehavior())[0].get_sha1() on_disk_sha1 = compute_file_sha1(checkout.path / dirent_path) if sha1 != on_disk_sha1: errors += [(dirent_path, sha1, on_disk_sha1)] if errors != []: tracker.add_problem(LoadedFileHasDifferentContentOnDisk(errors))