Created
January 2, 2025 14:21
-
-
Save teidesu/8bc54fb7e22fb2670937a5036335ba95 to your computer and use it in GitHub Desktop.
script to find and remove broken files from a gocryptfs-powered overlay filesystem
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import * as fsp from 'fs/promises' | |
| const BASE_PATH = '/mnt/s3-desu-priv-encrypted/music' | |
| const BASE_PATH_UNDERLYING = '/mnt/s3-desu-priv' | |
| async function* walk(path: string) { | |
| const entries = await fsp.readdir(path, { withFileTypes: true }) | |
| for (const entry of entries) { | |
| const fullPath = path + '/' + entry.name | |
| if (entry.isDirectory()) { | |
| yield* walk(fullPath) | |
| } else { | |
| yield fullPath | |
| } | |
| } | |
| } | |
| let _cachedWalk | |
| async function findUnderlyingPath(inode: number) { | |
| if (!_cachedWalk) { | |
| _cachedWalk = [] | |
| for await (const path of walk(BASE_PATH_UNDERLYING)) { | |
| _cachedWalk.push({ | |
| path, | |
| inode: await fsp.stat(path).then(stat => stat.ino) | |
| }) | |
| } | |
| } | |
| return _cachedWalk.find(it => it.inode === inode)?.path | |
| } | |
| const buffer = Buffer.alloc(100) | |
| async function validateFile(path: string) { | |
| // try reading the first few bytes of the file | |
| const fd = await fsp.open(path, 'r') | |
| try { | |
| await fd.read(fd, buffer, 0, 100, 0) | |
| await fd.close() | |
| return | |
| } catch (e) { | |
| if (e.code !== 'EIO') { | |
| throw e | |
| } | |
| } | |
| const stat = await fd.stat() | |
| const inode = stat.ino | |
| await fd.close() | |
| console.log(`found broken file at path ${path}, inode=${inode}. removing...`) | |
| const underlyingPath = await findUnderlyingPath(inode) | |
| if (!underlyingPath) { | |
| throw new Error(`Could not find underlying path for file ${path} (inode ${inode})`) | |
| } | |
| await fsp.rm(path, { recursive: true }) | |
| } | |
| for await (const path of walk(BASE_PATH)) { | |
| await validateFile(path) | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment