fix(fs): keep listDir child keys under stable parent
This commit is contained in:
@@ -196,6 +196,11 @@ function listingIoError(displayPath: string, error: unknown): FsError {
|
|||||||
return new FsError(`cannot list "${displayPath}": ${errorMessage(error)}`, 'FS_IO_ERROR', { cause: error })
|
return new FsError(`cannot list "${displayPath}": ${errorMessage(error)}`, 'FS_IO_ERROR', { cause: error })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function resolveListedChildTarget(parent: LocalTarget, name: string): Promise<LocalTarget> {
|
||||||
|
const identity = await resolveLocalTarget(parent.targetKey, name)
|
||||||
|
return { displayPath: join(parent.displayPath, name), targetKey: identity.targetKey }
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* List direct children of a directory in stable name order. Each child includes
|
* List direct children of a directory in stable name order. Each child includes
|
||||||
* a resolved target plus stat metadata when still available; file contents are
|
* a resolved target plus stat metadata when still available; file contents are
|
||||||
@@ -225,7 +230,7 @@ export async function listDirectory(target: LocalTarget, signal?: AbortSignal):
|
|||||||
for (const entry of entries.sort((left, right) => left.name.localeCompare(right.name))) {
|
for (const entry of entries.sort((left, right) => left.name.localeCompare(right.name))) {
|
||||||
throwIfAborted(signal, 'list')
|
throwIfAborted(signal, 'list')
|
||||||
try {
|
try {
|
||||||
const childTarget = await resolveLocalTarget(target.displayPath, entry.name)
|
const childTarget = await resolveListedChildTarget(target, entry.name)
|
||||||
const childInfo = await probe(childTarget.targetKey)
|
const childInfo = await probe(childTarget.targetKey)
|
||||||
result.push({
|
result.push({
|
||||||
name: entry.name,
|
name: entry.name,
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { afterEach, beforeEach, describe, expect, it } from 'vitest'
|
import { afterEach, beforeEach, describe, expect, it } from 'vitest'
|
||||||
import { chmod, mkdtemp, readFile, rm, stat, symlink, writeFile, mkdir, readdir, realpath } from 'node:fs/promises'
|
import { chmod, mkdtemp, readFile, rm, stat, symlink, unlink, writeFile, mkdir, readdir, realpath } from 'node:fs/promises'
|
||||||
import { tmpdir } from 'node:os'
|
import { tmpdir } from 'node:os'
|
||||||
import { join } from 'node:path'
|
import { join } from 'node:path'
|
||||||
import { createServer } from 'node:net'
|
import { createServer } from 'node:net'
|
||||||
@@ -167,6 +167,32 @@ describe('listDirectory', () => {
|
|||||||
expect(entries.find(entry => entry.name === 'dir-skill')?.size).toBeUndefined()
|
expect(entries.find(entry => entry.name === 'dir-skill')?.size).toBeUndefined()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('derives child target keys from the listed parent identity', async () => {
|
||||||
|
const realOne = join(dir, 'real-one')
|
||||||
|
const realTwo = join(dir, 'real-two')
|
||||||
|
const link = join(dir, 'link')
|
||||||
|
await mkdir(realOne)
|
||||||
|
await mkdir(realTwo)
|
||||||
|
await writeFile(join(realOne, 'same.txt'), 'one')
|
||||||
|
await writeFile(join(realTwo, 'same.txt'), 'different two')
|
||||||
|
await symlink(realOne, link)
|
||||||
|
const target = await resolveLocalTarget(dir, 'link')
|
||||||
|
|
||||||
|
await unlink(link)
|
||||||
|
await symlink(realTwo, link)
|
||||||
|
|
||||||
|
const entries = await listDirectory(target)
|
||||||
|
expect(entries).toHaveLength(1)
|
||||||
|
expect(entries[0]).toMatchObject({
|
||||||
|
name: 'same.txt',
|
||||||
|
target: {
|
||||||
|
displayPath: join(link, 'same.txt'),
|
||||||
|
targetKey: await realpath(join(realOne, 'same.txt')),
|
||||||
|
},
|
||||||
|
size: 3,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
it('rejects missing, non-directory, and aborted listing requests', async () => {
|
it('rejects missing, non-directory, and aborted listing requests', async () => {
|
||||||
await expect(listDirectory(localTarget(join(dir, 'missing')))).rejects.toMatchObject({ code: 'FS_NOT_FOUND' })
|
await expect(listDirectory(localTarget(join(dir, 'missing')))).rejects.toMatchObject({ code: 'FS_NOT_FOUND' })
|
||||||
const file = join(dir, 'a.txt')
|
const file = join(dir, 'a.txt')
|
||||||
|
|||||||
Reference in New Issue
Block a user