Compare commits

...

3 Commits

Author SHA1 Message Date
debian
eed3d72f75 fix incorrect parentage issue 2026-02-17 11:55:01 -05:00
debian
cb85e44aec fix isDirectory 2026-02-17 10:17:18 -05:00
debian
29b7a67dc3 fix backup health check & added debug 2026-02-17 08:44:36 -05:00
4 changed files with 67 additions and 24 deletions

View File

@@ -89,6 +89,7 @@ export class RemoteDisk extends RandomAccessDisk {
}
/**
* Abstract
* Gets the indexes of all blocks in the VHD.
* @returns {Array<number>}
*/
@@ -96,6 +97,15 @@ export class RemoteDisk extends RandomAccessDisk {
throw new Error(`getBlockIndexes must be implemented`)
}
/**
* Abstract
* Returns the parent non inizialized instance
* @returns {RemoteDisk}
*/
instantiateParent() {
throw new Error(`instantiateParent must be implemented`)
}
/**
* Abstract
* Writes a full block.

View File

@@ -202,17 +202,25 @@ describe('tests RemoteVhdDiskChain', { concurrency: 1 }, () => {
test('RemoteVhdDiskChain should read block', async () => {
// Create parent and child VHDs
const chainParent = await generateVhd(`${basePath}/parent.vhd`, { blocks: [0] })
await generateVhd(`${basePath}/child.vhd`, {
const chainChild = await generateVhd(`${basePath}/child.vhd`, {
header: {
parentUnicodeName: 'parent.vhd',
parentUuid: chainParent.footer.uuid,
},
blocks: [1],
})
await generateVhd(`${basePath}/child_2.vhd`, {
header: {
parentUnicodeName: 'child.vhd',
parentUuid: chainChild.footer.uuid,
},
blocks: [1],
})
const parent = new RemoteVhdDisk({ handler, path: `${basePath}/parent.vhd` })
const child = new RemoteVhdDisk({ handler, path: `${basePath}/child.vhd` })
const diskChain = new RemoteVhdDiskChain({ disks: [parent, child] })
const child_2 = new RemoteVhdDisk({ handler, path: `${basePath}/child_2.vhd` })
const diskChain = new RemoteVhdDiskChain({ disks: [parent, child, child_2] })
await diskChain.init({ force: false })
@@ -362,18 +370,18 @@ describe('tests MergeVhdChain', { concurrency: 1 }, () => {
// Create ancestor and children VHDs
await generateVhd(`${basePath}/ancestor.vhd`, { blocks: [0, 1] })
const chainParent = await generateVhd(`${basePath}/child_1.vhd`, { blocks: [2] })
await generateVhd(`${basePath}/child_2.vhd`, {
const chainChild1 = await generateVhd(`${basePath}/child_1.vhd`, { blocks: [2] })
const chainChild2 = await generateVhd(`${basePath}/child_2.vhd`, {
header: {
parentUnicodeName: 'child_1.vhd',
parentUuid: chainParent.footer.uuid,
parentUuid: chainChild1.footer.uuid,
},
blocks: [3],
})
await generateVhd(`${basePath}/child_3.vhd`, {
header: {
parentUnicodeName: 'child_1.vhd',
parentUuid: chainParent.footer.uuid,
parentUnicodeName: 'child_2.vhd',
parentUuid: chainChild2.footer.uuid,
},
blocks: [4],
})

View File

@@ -16,6 +16,7 @@ import { DISK_TYPES } from 'vhd-lib/_constants.js'
import { isVhdAlias, resolveVhdAlias } from 'vhd-lib/aliases.js'
// import { set as setBitmap } from 'vhd-lib/_bitmap.js'
import { stringify } from 'uuid'
import { dirname, join } from 'node:path'
export class RemoteVhdDisk extends RemoteDisk {
/**
@@ -70,18 +71,19 @@ export class RemoteVhdDisk extends RemoteDisk {
* @param {boolean} [options.force=false]
* @returns {Promise<void>}
*/
async init(options = {}) {
if (this.#vhd === undefined) {
try {
if ((await this.isDirectory()) && !isVhdAlias(this.#path)) {
throw Object.assign(new Error("Can't init vhd directory without using alias"), { code: 'NOT_SUPPORTED' })
}
const { value, dispose } = await openVhd(this.#handler, await resolveVhdAlias(this.#handler, this.#path), {
checkSecondFooter: !options.force,
})
this.#vhd = value
if ((await this.isDirectory()) && !isVhdAlias(this.#path)) {
this.#vhd = undefined
throw Object.assign(new Error("Can't init vhd directory without using alias"), { code: 'NOT_SUPPORTED' })
}
this.#dispose = dispose
await this.#vhd.readBlockAllocationTable()
this.#isDifferencing = value.footer.diskType === DISK_TYPES.DIFFERENCING
@@ -204,6 +206,26 @@ export class RemoteVhdDisk extends RemoteDisk {
return indexes
}
/**
* Returns the parent non inizialized instance
* @returns {RemoteDisk}
*/
instantiateParent() {
if (this.#vhd === undefined) {
throw new Error(`can't call instantiateParent of a RemoteVhdDisk before init`)
}
const parentPath = this.#vhd.header.parentUnicodeName
const fullParentPath = join(dirname(this.#path), parentPath)
if (!parentPath) {
throw new Error(`disk ${this.#path} doesn't have parents`)
}
const parent = new RemoteVhdDisk({ handler: this.#handler, path: fullParentPath })
return parent
}
/**
* Writes a full block into this VHD.
* @param {DiskBlock} diskBlock
@@ -428,15 +450,10 @@ export class RemoteVhdDisk extends RemoteDisk {
* @returns {Promise<boolean>}
*/
async isDirectory() {
if (this.#vhd !== undefined) {
return this.#vhd instanceof VhdDirectory
} else {
try {
await this.#handler.readFile(await resolveVhdAlias(this.#handler, this.#path))
return false
} catch (err) {
return true
}
if (this.#vhd === undefined) {
throw new Error(`can't call isDirectory of a RemoteVhdDisk before init`)
}
return this.#vhd instanceof VhdDirectory
}
}

View File

@@ -56,9 +56,7 @@ export class RemoteVhdDiskChain extends RemoteDisk {
await Promise.all(this.#disks.map(disk => disk.init(options)))
let parentUuid = ''
for (const [index, disk] of this.#disks.entries()) {
if (index === 0) {
parentUuid = disk.getUuid()
} else {
if (index !== 0) {
if (!disk.isDifferencing()) {
throw Object.assign(new Error("Can't init vhd directory with non differencing child disks"), {
code: 'NOT_SUPPORTED',
@@ -70,6 +68,8 @@ export class RemoteVhdDiskChain extends RemoteDisk {
})
}
}
parentUuid = disk.getUuid()
}
} catch (error) {
await this.close()
@@ -178,6 +178,14 @@ export class RemoteVhdDiskChain extends RemoteDisk {
return [...indexes]
}
/**
* Returns the parent non inizialized instance
* @returns {RemoteDisk}
*/
instantiateParent() {
return this.#disks[0].instantiateParent()
}
/**
* Writes a full block into this VHD.
* @param {DiskBlock} diskBlock