mharj-diskinfo 0.2.0 → 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,19 +1,39 @@
1
1
  # diskinfo
2
2
 
3
+ [![TypeScript](https://badges.frapsoft.com/typescript/code/typescript.svg?v=101)](https://github.com/ellerbrock/typescript-badges/)
4
+ [![npm version](https://badge.fury.io/js/mharj-diskinfo.svg)](https://badge.fury.io/js/mharj-diskinfo)
5
+ [![Maintainability](https://qlty.sh/gh/mharj/projects/diskinfo/maintainability.svg)](https://qlty.sh/gh/mharj/projects/diskinfo)
6
+ [![Code Coverage](https://qlty.sh/gh/mharj/projects/diskinfo/coverage.svg)](https://qlty.sh/gh/mharj/projects/diskinfo)
7
+ [![CI/CD](https://github.com/mharj/diskinfo/actions/workflows/main.yml/badge.svg)](https://github.com/mharj/diskinfo/actions/workflows/main.yml)
8
+
3
9
  read disk partition and filesystem information with NodeJS
4
10
  Requires: NodeJS 10.4 as using Bigint
5
11
 
12
+ ### Installation
13
+
6
14
  ```bash
7
15
  npm install mharj-diskinfo --save
8
16
  ```
9
17
 
18
+ ### Magic usage
19
+
20
+ ```typescript
21
+ import {open} from 'node:fs/promises';
22
+ import {Magic} from 'mharj-diskinfo';
23
+ const handle = await open('\\\\.\\PHYSICALDRIVE0', 'rs+');
24
+ const magic = new Magic(handle);
25
+ console.log(magic.haveNtfs(0)); // true if NTFS magic found at offset 0
26
+ ```
27
+
28
+ ### Partition scan usage
29
+
10
30
  ```javascript
11
- const fs = require('fs');
31
+ const fsp = require('fs/promises');
12
32
  const scan = require('mharj-diskinfo').scan;
13
33
  const device = '\\\\.\\PHYSICALDRIVE0';
14
34
  //const device = '/dev/sda';
15
- const fd = fs.openSync(device, 'rs+');
16
- let data = await scan(fd);
35
+ const handle = await fsp.open(device, 'rs+');
36
+ let data = await scan(handle);
17
37
  console.log(data);
18
38
  ```
19
39
 
package/dist/index.cjs CHANGED
@@ -23,24 +23,59 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
23
23
  //#endregion
24
24
  let node_fs = require("node:fs");
25
25
  node_fs = __toESM(node_fs);
26
+ //#region \0@oxc-project+runtime@0.129.0/helpers/checkPrivateRedeclaration.js
27
+ function _checkPrivateRedeclaration(e, t) {
28
+ if (t.has(e)) throw new TypeError("Cannot initialize the same private elements twice on an object");
29
+ }
30
+ //#endregion
31
+ //#region \0@oxc-project+runtime@0.129.0/helpers/classPrivateFieldInitSpec.js
32
+ function _classPrivateFieldInitSpec(e, t, a) {
33
+ _checkPrivateRedeclaration(e, t), t.set(e, a);
34
+ }
35
+ //#endregion
36
+ //#region \0@oxc-project+runtime@0.129.0/helpers/assertClassBrand.js
37
+ function _assertClassBrand(e, t, n) {
38
+ if ("function" == typeof e ? e === t : e.has(t)) return arguments.length < 3 ? t : n;
39
+ throw new TypeError("Private element is not present on this object");
40
+ }
41
+ //#endregion
42
+ //#region \0@oxc-project+runtime@0.129.0/helpers/classPrivateFieldSet2.js
43
+ function _classPrivateFieldSet2(s, a, r) {
44
+ return s.set(_assertClassBrand(s, a), r), r;
45
+ }
46
+ //#endregion
47
+ //#region \0@oxc-project+runtime@0.129.0/helpers/classPrivateFieldGet2.js
48
+ function _classPrivateFieldGet2(s, a) {
49
+ return s.get(_assertClassBrand(s, a));
50
+ }
51
+ //#endregion
26
52
  //#region src/Magic.ts
53
+ var _handle = /* @__PURE__ */ new WeakMap();
54
+ /**
55
+ * Class to check for magic numbers of various filesystems at given offsets.
56
+ * @example
57
+ * const fh = await fsp.open(device, 'rs+');
58
+ * const magic = new Magic(fh);
59
+ * console.log(magic.haveExt(0)); // check for EXT at offset 0
60
+ */
27
61
  var Magic = class {
28
- constructor(fd) {
29
- this.fd = fd;
62
+ constructor(fileHandle) {
63
+ _classPrivateFieldInitSpec(this, _handle, void 0);
64
+ _classPrivateFieldSet2(_handle, this, fileHandle);
30
65
  }
31
66
  haveExt(offset) {
32
67
  const data = Buffer.allocUnsafe(2048);
33
- node_fs.default.readSync(this.fd, data, 0, data.length, 512 * offset);
68
+ node_fs.default.readSync(_classPrivateFieldGet2(_handle, this).fd, data, 0, data.length, 512 * offset);
34
69
  return data.readInt16BE(1080) === 21487;
35
70
  }
36
71
  haveNtfs(offset) {
37
72
  const data = Buffer.allocUnsafe(512);
38
- node_fs.default.readSync(this.fd, data, 0, data.length, 512 * offset);
73
+ node_fs.default.readSync(_classPrivateFieldGet2(_handle, this).fd, data, 0, data.length, 512 * offset);
39
74
  return data.readInt32BE(3) === 1314145875;
40
75
  }
41
76
  haveLvm2(offset) {
42
77
  const data = Buffer.allocUnsafe(1024);
43
- node_fs.default.readSync(this.fd, data, 0, data.length, 512 * offset);
78
+ node_fs.default.readSync(_classPrivateFieldGet2(_handle, this).fd, data, 0, data.length, 512 * offset);
44
79
  return data.readInt32BE(536) === 1280724274;
45
80
  }
46
81
  };
@@ -93,13 +128,13 @@ function readUuidBytes(buf, pos) {
93
128
  buf[pos + 15]
94
129
  ]);
95
130
  }
96
- function readUuidString(buf, pos) {
131
+ function readUuidAsString(buf, pos) {
97
132
  const uuid = readUuidBytes(buf, pos).toString("hex");
98
133
  return `${uuid.slice(0, 8)}-${uuid.slice(8, 12)}-${uuid.slice(12, 16)}-${uuid.slice(16, 20)}-${uuid.slice(20, 32)}`;
99
134
  }
100
135
  function parseGPTable(buf) {
101
- const typeId = readUuidString(buf, 0);
102
- const uuid = readUuidString(buf, 16);
136
+ const typeId = readUuidAsString(buf, 0);
137
+ const uuid = readUuidAsString(buf, 16);
103
138
  const startLBA = buf.readBigUInt64LE(32);
104
139
  const endLBA = buf.readBigUInt64LE(40);
105
140
  return {
@@ -124,7 +159,7 @@ function parseGPT(buf) {
124
159
  backupLBA: buf.readBigUInt64LE(32),
125
160
  firstUsableLBA: buf.readBigUInt64LE(40),
126
161
  lastUsableLBA: buf.readBigUInt64LE(48),
127
- uuid: readUuidString(buf, 56),
162
+ uuid: readUuidAsString(buf, 56),
128
163
  tableLBA: buf.readBigUInt64LE(72),
129
164
  partitions: buf.readUInt32LE(80),
130
165
  partitionSize: buf.readUInt32LE(84),
@@ -133,7 +168,7 @@ function parseGPT(buf) {
133
168
  }
134
169
  //#endregion
135
170
  //#region src/mbrPart.ts
136
- const partTypes = {
171
+ const partTypes = Object.freeze({
137
172
  EMPTY: 0,
138
173
  EXTENDED: 5,
139
174
  NTFS: 7,
@@ -150,7 +185,7 @@ const partTypes = {
150
185
  return acc;
151
186
  }, "Unknown");
152
187
  }
153
- };
188
+ });
154
189
  function parseMBR(mbr) {
155
190
  if (mbr.length < 512 || mbr[510] !== 85 || mbr[511] !== 170) throw Error("no MBR signature or buffer is less than 512 bytes");
156
191
  const ret = {
@@ -164,7 +199,7 @@ function parseMBR(mbr) {
164
199
  partitions: [],
165
200
  type: "MBR"
166
201
  };
167
- for (let i = 446; i <= 508; i += 16) ret.partitions.push(parseMBRPartition(mbr.slice(i, i + 16)));
202
+ for (let i = 446; i <= 508; i += 16) ret.partitions.push(parseMBRPartition(mbr.subarray(i, i + 16)));
168
203
  return ret;
169
204
  }
170
205
  function parseMBRPartition(part) {
@@ -182,45 +217,58 @@ function isMbrPartition(part) {
182
217
  return typeof part.type === "number";
183
218
  }
184
219
  //#endregion
185
- //#region src/util.ts
186
- function readFile(fd, offset, length, position) {
187
- return new Promise((resolve, reject) => {
188
- const buffer = Buffer.allocUnsafe(length);
189
- node_fs.default.read(fd, buffer, offset, buffer.length, position, (err) => {
190
- if (err) reject(err);
191
- else resolve(buffer);
192
- });
193
- });
194
- }
195
- //#endregion
196
220
  //#region src/scan.ts
197
- async function scan(fd) {
198
- const rootMbr = parseMBR(await readFile(fd, 0, 512, 0));
199
- rootMbr.partitions.forEach(async function(p) {
200
- if (p.type === partTypes.EXTENDED) {
201
- if (!isMbrPartition(p)) throw TypeError("we did get GPT partition as extended");
202
- parseMBR(await readFile(fd, 0, 512, 512)).partitions.forEach(function(extpart) {
203
- if (!isMbrPartition(extpart)) throw TypeError("we did get GPT partition as extended");
204
- if (extpart.type !== partTypes.EMPTY) {
205
- extpart.startLBA = extpart.startLBA + p.startLBA;
206
- rootMbr.partitions.push(extpart);
207
- }
208
- });
221
+ async function getMbrPartitions(handle, startLBA) {
222
+ const buffer = Buffer.allocUnsafe(512);
223
+ await handle.read(buffer, 0, 512, startLBA * 512);
224
+ const output = [];
225
+ const extparts = parseMBR(buffer);
226
+ for (const extpart of extparts.partitions) {
227
+ if (!isMbrPartition(extpart)) throw TypeError("we did get GPT partition as extended");
228
+ if (extpart.type !== partTypes.EMPTY) {
229
+ extpart.startLBA = extpart.startLBA + startLBA;
230
+ output.push(extpart);
231
+ }
232
+ }
233
+ return output;
234
+ }
235
+ async function getGptPartitions(handle) {
236
+ const buffer = Buffer.allocUnsafe(512);
237
+ await handle.read(buffer, 0, 512, 512);
238
+ const gpt = parseGPT(buffer);
239
+ const gBuff = Buffer.allocUnsafe(gpt.partitions * gpt.partitionSize);
240
+ const partitions = [];
241
+ for (let i = 0; i < gpt.partitions * gpt.partitionSize; i += gpt.partitionSize) {
242
+ const table = parseGPTable(gBuff.subarray(i, i + gpt.partitionSize));
243
+ if (table.typeId !== gptPartTypes.EMPTY) partitions.push(table);
244
+ }
245
+ return {
246
+ uuid: gpt.uuid,
247
+ partitions
248
+ };
249
+ }
250
+ function isGptPartition(root, part) {
251
+ return part.type === partTypes.GPT;
252
+ }
253
+ function isExtendedPartition(part) {
254
+ return part.type === partTypes.EXTENDED;
255
+ }
256
+ async function scan(handle) {
257
+ const buffer = Buffer.allocUnsafe(512);
258
+ await handle.read(buffer, 0, 512, 0);
259
+ const rootMbr = parseMBR(buffer);
260
+ for (const p of rootMbr.partitions) {
261
+ if (isExtendedPartition(p)) {
262
+ const partitions = await getMbrPartitions(handle, p.startLBA);
263
+ rootMbr.partitions.push(...partitions);
209
264
  }
210
- if (p.type === partTypes.GPT) {
265
+ if (isGptPartition(rootMbr, p)) {
266
+ const { partitions, uuid } = await getGptPartitions(handle);
211
267
  rootMbr.type = "GPT";
212
- const gpt = parseGPT(await readFile(fd, 0, 512, 512));
213
- rootMbr.uuid = gpt.uuid;
214
- const gBuff = Buffer.allocUnsafe(gpt.partitions * gpt.partitionSize);
215
- node_fs.default.readSync(fd, gBuff, 0, gBuff.length, Number(gpt.tableLBA) * 512);
216
- const partitions = [];
217
- for (let i = 0; i < gpt.partitions * gpt.partitionSize; i += gpt.partitionSize) {
218
- const table = parseGPTable(gBuff.slice(i, i + gpt.partitionSize));
219
- if (table.typeId !== gptPartTypes.EMPTY) partitions.push(table);
220
- }
221
268
  rootMbr.partitions = partitions;
269
+ rootMbr.uuid = uuid;
222
270
  }
223
- });
271
+ }
224
272
  return rootMbr;
225
273
  }
226
274
  //#endregion
package/dist/index.d.cts CHANGED
@@ -1,7 +1,16 @@
1
+ import { FileHandle } from "node:fs/promises";
2
+
1
3
  //#region src/Magic.d.ts
4
+ /**
5
+ * Class to check for magic numbers of various filesystems at given offsets.
6
+ * @example
7
+ * const fh = await fsp.open(device, 'rs+');
8
+ * const magic = new Magic(fh);
9
+ * console.log(magic.haveExt(0)); // check for EXT at offset 0
10
+ */
2
11
  declare class Magic {
3
- private fd;
4
- constructor(fd: number);
12
+ #private;
13
+ constructor(fileHandle: FileHandle);
5
14
  haveExt(offset: number): boolean;
6
15
  haveNtfs(offset: number): boolean;
7
16
  haveLvm2(offset: number): boolean;
@@ -31,18 +40,18 @@ type GPTPartition = {
31
40
  type GptData = {
32
41
  copyProtected: boolean;
33
42
  uuid: string;
34
- type: 'GPT';
43
+ type: "GPT";
35
44
  partitions: GPTPartition[];
36
45
  };
37
46
  type MbrData = {
38
47
  copyProtected: boolean;
39
48
  uuid: string;
40
- type: 'MBR';
49
+ type: "MBR";
41
50
  partitions: MBRPartition[];
42
51
  };
43
52
  type IMbrData = MbrData | GptData;
44
53
  //#endregion
45
54
  //#region src/scan.d.ts
46
- declare function scan(fd: number): Promise<IMbrData>;
55
+ declare function scan(handle: FileHandle): Promise<IMbrData>;
47
56
  //#endregion
48
57
  export { Magic, scan };
package/dist/index.d.mts CHANGED
@@ -1,7 +1,16 @@
1
+ import { FileHandle } from "node:fs/promises";
2
+
1
3
  //#region src/Magic.d.ts
4
+ /**
5
+ * Class to check for magic numbers of various filesystems at given offsets.
6
+ * @example
7
+ * const fh = await fsp.open(device, 'rs+');
8
+ * const magic = new Magic(fh);
9
+ * console.log(magic.haveExt(0)); // check for EXT at offset 0
10
+ */
2
11
  declare class Magic {
3
- private fd;
4
- constructor(fd: number);
12
+ #private;
13
+ constructor(fileHandle: FileHandle);
5
14
  haveExt(offset: number): boolean;
6
15
  haveNtfs(offset: number): boolean;
7
16
  haveLvm2(offset: number): boolean;
@@ -31,18 +40,18 @@ type GPTPartition = {
31
40
  type GptData = {
32
41
  copyProtected: boolean;
33
42
  uuid: string;
34
- type: 'GPT';
43
+ type: "GPT";
35
44
  partitions: GPTPartition[];
36
45
  };
37
46
  type MbrData = {
38
47
  copyProtected: boolean;
39
48
  uuid: string;
40
- type: 'MBR';
49
+ type: "MBR";
41
50
  partitions: MBRPartition[];
42
51
  };
43
52
  type IMbrData = MbrData | GptData;
44
53
  //#endregion
45
54
  //#region src/scan.d.ts
46
- declare function scan(fd: number): Promise<IMbrData>;
55
+ declare function scan(handle: FileHandle): Promise<IMbrData>;
47
56
  //#endregion
48
57
  export { Magic, scan };
package/dist/index.mjs CHANGED
@@ -1,22 +1,57 @@
1
1
  import fs from "node:fs";
2
+ //#region \0@oxc-project+runtime@0.129.0/helpers/checkPrivateRedeclaration.js
3
+ function _checkPrivateRedeclaration(e, t) {
4
+ if (t.has(e)) throw new TypeError("Cannot initialize the same private elements twice on an object");
5
+ }
6
+ //#endregion
7
+ //#region \0@oxc-project+runtime@0.129.0/helpers/classPrivateFieldInitSpec.js
8
+ function _classPrivateFieldInitSpec(e, t, a) {
9
+ _checkPrivateRedeclaration(e, t), t.set(e, a);
10
+ }
11
+ //#endregion
12
+ //#region \0@oxc-project+runtime@0.129.0/helpers/assertClassBrand.js
13
+ function _assertClassBrand(e, t, n) {
14
+ if ("function" == typeof e ? e === t : e.has(t)) return arguments.length < 3 ? t : n;
15
+ throw new TypeError("Private element is not present on this object");
16
+ }
17
+ //#endregion
18
+ //#region \0@oxc-project+runtime@0.129.0/helpers/classPrivateFieldSet2.js
19
+ function _classPrivateFieldSet2(s, a, r) {
20
+ return s.set(_assertClassBrand(s, a), r), r;
21
+ }
22
+ //#endregion
23
+ //#region \0@oxc-project+runtime@0.129.0/helpers/classPrivateFieldGet2.js
24
+ function _classPrivateFieldGet2(s, a) {
25
+ return s.get(_assertClassBrand(s, a));
26
+ }
27
+ //#endregion
2
28
  //#region src/Magic.ts
29
+ var _handle = /* @__PURE__ */ new WeakMap();
30
+ /**
31
+ * Class to check for magic numbers of various filesystems at given offsets.
32
+ * @example
33
+ * const fh = await fsp.open(device, 'rs+');
34
+ * const magic = new Magic(fh);
35
+ * console.log(magic.haveExt(0)); // check for EXT at offset 0
36
+ */
3
37
  var Magic = class {
4
- constructor(fd) {
5
- this.fd = fd;
38
+ constructor(fileHandle) {
39
+ _classPrivateFieldInitSpec(this, _handle, void 0);
40
+ _classPrivateFieldSet2(_handle, this, fileHandle);
6
41
  }
7
42
  haveExt(offset) {
8
43
  const data = Buffer.allocUnsafe(2048);
9
- fs.readSync(this.fd, data, 0, data.length, 512 * offset);
44
+ fs.readSync(_classPrivateFieldGet2(_handle, this).fd, data, 0, data.length, 512 * offset);
10
45
  return data.readInt16BE(1080) === 21487;
11
46
  }
12
47
  haveNtfs(offset) {
13
48
  const data = Buffer.allocUnsafe(512);
14
- fs.readSync(this.fd, data, 0, data.length, 512 * offset);
49
+ fs.readSync(_classPrivateFieldGet2(_handle, this).fd, data, 0, data.length, 512 * offset);
15
50
  return data.readInt32BE(3) === 1314145875;
16
51
  }
17
52
  haveLvm2(offset) {
18
53
  const data = Buffer.allocUnsafe(1024);
19
- fs.readSync(this.fd, data, 0, data.length, 512 * offset);
54
+ fs.readSync(_classPrivateFieldGet2(_handle, this).fd, data, 0, data.length, 512 * offset);
20
55
  return data.readInt32BE(536) === 1280724274;
21
56
  }
22
57
  };
@@ -69,13 +104,13 @@ function readUuidBytes(buf, pos) {
69
104
  buf[pos + 15]
70
105
  ]);
71
106
  }
72
- function readUuidString(buf, pos) {
107
+ function readUuidAsString(buf, pos) {
73
108
  const uuid = readUuidBytes(buf, pos).toString("hex");
74
109
  return `${uuid.slice(0, 8)}-${uuid.slice(8, 12)}-${uuid.slice(12, 16)}-${uuid.slice(16, 20)}-${uuid.slice(20, 32)}`;
75
110
  }
76
111
  function parseGPTable(buf) {
77
- const typeId = readUuidString(buf, 0);
78
- const uuid = readUuidString(buf, 16);
112
+ const typeId = readUuidAsString(buf, 0);
113
+ const uuid = readUuidAsString(buf, 16);
79
114
  const startLBA = buf.readBigUInt64LE(32);
80
115
  const endLBA = buf.readBigUInt64LE(40);
81
116
  return {
@@ -100,7 +135,7 @@ function parseGPT(buf) {
100
135
  backupLBA: buf.readBigUInt64LE(32),
101
136
  firstUsableLBA: buf.readBigUInt64LE(40),
102
137
  lastUsableLBA: buf.readBigUInt64LE(48),
103
- uuid: readUuidString(buf, 56),
138
+ uuid: readUuidAsString(buf, 56),
104
139
  tableLBA: buf.readBigUInt64LE(72),
105
140
  partitions: buf.readUInt32LE(80),
106
141
  partitionSize: buf.readUInt32LE(84),
@@ -109,7 +144,7 @@ function parseGPT(buf) {
109
144
  }
110
145
  //#endregion
111
146
  //#region src/mbrPart.ts
112
- const partTypes = {
147
+ const partTypes = Object.freeze({
113
148
  EMPTY: 0,
114
149
  EXTENDED: 5,
115
150
  NTFS: 7,
@@ -126,7 +161,7 @@ const partTypes = {
126
161
  return acc;
127
162
  }, "Unknown");
128
163
  }
129
- };
164
+ });
130
165
  function parseMBR(mbr) {
131
166
  if (mbr.length < 512 || mbr[510] !== 85 || mbr[511] !== 170) throw Error("no MBR signature or buffer is less than 512 bytes");
132
167
  const ret = {
@@ -140,7 +175,7 @@ function parseMBR(mbr) {
140
175
  partitions: [],
141
176
  type: "MBR"
142
177
  };
143
- for (let i = 446; i <= 508; i += 16) ret.partitions.push(parseMBRPartition(mbr.slice(i, i + 16)));
178
+ for (let i = 446; i <= 508; i += 16) ret.partitions.push(parseMBRPartition(mbr.subarray(i, i + 16)));
144
179
  return ret;
145
180
  }
146
181
  function parseMBRPartition(part) {
@@ -158,45 +193,58 @@ function isMbrPartition(part) {
158
193
  return typeof part.type === "number";
159
194
  }
160
195
  //#endregion
161
- //#region src/util.ts
162
- function readFile(fd, offset, length, position) {
163
- return new Promise((resolve, reject) => {
164
- const buffer = Buffer.allocUnsafe(length);
165
- fs.read(fd, buffer, offset, buffer.length, position, (err) => {
166
- if (err) reject(err);
167
- else resolve(buffer);
168
- });
169
- });
170
- }
171
- //#endregion
172
196
  //#region src/scan.ts
173
- async function scan(fd) {
174
- const rootMbr = parseMBR(await readFile(fd, 0, 512, 0));
175
- rootMbr.partitions.forEach(async function(p) {
176
- if (p.type === partTypes.EXTENDED) {
177
- if (!isMbrPartition(p)) throw TypeError("we did get GPT partition as extended");
178
- parseMBR(await readFile(fd, 0, 512, 512)).partitions.forEach(function(extpart) {
179
- if (!isMbrPartition(extpart)) throw TypeError("we did get GPT partition as extended");
180
- if (extpart.type !== partTypes.EMPTY) {
181
- extpart.startLBA = extpart.startLBA + p.startLBA;
182
- rootMbr.partitions.push(extpart);
183
- }
184
- });
197
+ async function getMbrPartitions(handle, startLBA) {
198
+ const buffer = Buffer.allocUnsafe(512);
199
+ await handle.read(buffer, 0, 512, startLBA * 512);
200
+ const output = [];
201
+ const extparts = parseMBR(buffer);
202
+ for (const extpart of extparts.partitions) {
203
+ if (!isMbrPartition(extpart)) throw TypeError("we did get GPT partition as extended");
204
+ if (extpart.type !== partTypes.EMPTY) {
205
+ extpart.startLBA = extpart.startLBA + startLBA;
206
+ output.push(extpart);
207
+ }
208
+ }
209
+ return output;
210
+ }
211
+ async function getGptPartitions(handle) {
212
+ const buffer = Buffer.allocUnsafe(512);
213
+ await handle.read(buffer, 0, 512, 512);
214
+ const gpt = parseGPT(buffer);
215
+ const gBuff = Buffer.allocUnsafe(gpt.partitions * gpt.partitionSize);
216
+ const partitions = [];
217
+ for (let i = 0; i < gpt.partitions * gpt.partitionSize; i += gpt.partitionSize) {
218
+ const table = parseGPTable(gBuff.subarray(i, i + gpt.partitionSize));
219
+ if (table.typeId !== gptPartTypes.EMPTY) partitions.push(table);
220
+ }
221
+ return {
222
+ uuid: gpt.uuid,
223
+ partitions
224
+ };
225
+ }
226
+ function isGptPartition(root, part) {
227
+ return part.type === partTypes.GPT;
228
+ }
229
+ function isExtendedPartition(part) {
230
+ return part.type === partTypes.EXTENDED;
231
+ }
232
+ async function scan(handle) {
233
+ const buffer = Buffer.allocUnsafe(512);
234
+ await handle.read(buffer, 0, 512, 0);
235
+ const rootMbr = parseMBR(buffer);
236
+ for (const p of rootMbr.partitions) {
237
+ if (isExtendedPartition(p)) {
238
+ const partitions = await getMbrPartitions(handle, p.startLBA);
239
+ rootMbr.partitions.push(...partitions);
185
240
  }
186
- if (p.type === partTypes.GPT) {
241
+ if (isGptPartition(rootMbr, p)) {
242
+ const { partitions, uuid } = await getGptPartitions(handle);
187
243
  rootMbr.type = "GPT";
188
- const gpt = parseGPT(await readFile(fd, 0, 512, 512));
189
- rootMbr.uuid = gpt.uuid;
190
- const gBuff = Buffer.allocUnsafe(gpt.partitions * gpt.partitionSize);
191
- fs.readSync(fd, gBuff, 0, gBuff.length, Number(gpt.tableLBA) * 512);
192
- const partitions = [];
193
- for (let i = 0; i < gpt.partitions * gpt.partitionSize; i += gpt.partitionSize) {
194
- const table = parseGPTable(gBuff.slice(i, i + gpt.partitionSize));
195
- if (table.typeId !== gptPartTypes.EMPTY) partitions.push(table);
196
- }
197
244
  rootMbr.partitions = partitions;
245
+ rootMbr.uuid = uuid;
198
246
  }
199
- });
247
+ }
200
248
  return rootMbr;
201
249
  }
202
250
  //#endregion
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mharj-diskinfo",
3
- "version": "0.2.0",
3
+ "version": "0.2.2",
4
4
  "description": "Node.js library to parse MBR and GPT partition information from disk images or devices.",
5
5
  "main": "./dist/index.cjs",
6
6
  "module": "./dist/index.mjs",
@@ -18,12 +18,12 @@
18
18
  },
19
19
  "scripts": {
20
20
  "prepare": "lefthook install",
21
- "build": "tsdown src/index.ts --format cjs,esm --dts --clean",
21
+ "build": "tsdown src/index.ts --format cjs,esm --dts --clean -c tsconfig.build.json",
22
22
  "prepublishOnly": "npm run build",
23
23
  "test": "vitest test --typecheck --run --no-isolate --coverage",
24
24
  "coverage": "vitest test --run --no-isolate --reporter=dot --coverage --coverage.reporter=lcov",
25
25
  "lint": "biome check",
26
- "validate": "tsc --noEmit --project tsconfig.test.json"
26
+ "validate": "tsgo --noEmit"
27
27
  },
28
28
  "repository": "github:mharj/diskinfo",
29
29
  "files": [
@@ -43,6 +43,7 @@
43
43
  "@tsconfig/node16": "^16.1.8",
44
44
  "@types/buffer-crc32": "^0.2.0",
45
45
  "@types/node": "^22.19.1",
46
+ "@typescript/native-preview": "7.0.0-dev.20260421.2",
46
47
  "@vitest/coverage-v8": "^4.1.6",
47
48
  "buffer-crc32": "^0.2.13",
48
49
  "c8": "^11.0.0",