mharj-diskinfo 0.0.2 → 0.2.0

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,18 +1,19 @@
1
1
  # diskinfo
2
2
 
3
3
  read disk partition and filesystem information with NodeJS
4
+ Requires: NodeJS 10.4 as using Bigint
4
5
 
5
6
  ```bash
6
7
  npm install mharj-diskinfo --save
7
8
  ```
8
9
 
9
10
  ```javascript
10
- const fs = require("fs");
11
- const scan = require("mharj-diskinfo").scan;
12
- const device = "\\\\.\\PHYSICALDRIVE0";
11
+ const fs = require('fs');
12
+ const scan = require('mharj-diskinfo').scan;
13
+ const device = '\\\\.\\PHYSICALDRIVE0';
13
14
  //const device = '/dev/sda';
14
- const fd = fs.openSync(device, "rs+");
15
- let data = scan(fd);
15
+ const fd = fs.openSync(device, 'rs+');
16
+ let data = await scan(fd);
16
17
  console.log(data);
17
18
  ```
18
19
 
package/dist/index.cjs ADDED
@@ -0,0 +1,228 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ //#region \0rolldown/runtime.js
3
+ var __create = Object.create;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
+ var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __getProtoOf = Object.getPrototypeOf;
8
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
9
+ var __copyProps = (to, from, except, desc) => {
10
+ if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
11
+ key = keys[i];
12
+ if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
13
+ get: ((k) => from[k]).bind(null, key),
14
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
15
+ });
16
+ }
17
+ return to;
18
+ };
19
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
20
+ value: mod,
21
+ enumerable: true
22
+ }) : target, mod));
23
+ //#endregion
24
+ let node_fs = require("node:fs");
25
+ node_fs = __toESM(node_fs);
26
+ //#region src/Magic.ts
27
+ var Magic = class {
28
+ constructor(fd) {
29
+ this.fd = fd;
30
+ }
31
+ haveExt(offset) {
32
+ const data = Buffer.allocUnsafe(2048);
33
+ node_fs.default.readSync(this.fd, data, 0, data.length, 512 * offset);
34
+ return data.readInt16BE(1080) === 21487;
35
+ }
36
+ haveNtfs(offset) {
37
+ const data = Buffer.allocUnsafe(512);
38
+ node_fs.default.readSync(this.fd, data, 0, data.length, 512 * offset);
39
+ return data.readInt32BE(3) === 1314145875;
40
+ }
41
+ haveLvm2(offset) {
42
+ const data = Buffer.allocUnsafe(1024);
43
+ node_fs.default.readSync(this.fd, data, 0, data.length, 512 * offset);
44
+ return data.readInt32BE(536) === 1280724274;
45
+ }
46
+ };
47
+ //#endregion
48
+ //#region src/gptPart.ts
49
+ const EFI_PART = Buffer.from([
50
+ 69,
51
+ 70,
52
+ 73,
53
+ 32,
54
+ 80,
55
+ 65,
56
+ 82,
57
+ 84
58
+ ]);
59
+ const gptPartTypes = Object.freeze({
60
+ EMPTY: "00000000-0000-0000-0000-000000000000",
61
+ MBR: "024dee41-33e7-11d3-9d69-0008c781f39f",
62
+ EFI: "c12a7328-f81f-11d2-ba4b-00a0c93ec93b",
63
+ LINUX: "0fc63daf-8483-4772-8e79-3d69d8477de4",
64
+ LINUX_SWAP: "0657fd6d-a4ab-43c4-84e5-0933c84b4f4f",
65
+ LINUX_LVM: "e6d6d379-f507-44c2-a23c-238f2a3df928",
66
+ LINUX_RAID: "a19d880f-05fc-4d3b-a006-743f0f84911e",
67
+ MSR: "e3c9e316-0b5c-4db8-817d-f92df00215ae",
68
+ BASIC_DATA: "ebd0a0a2-b9e5-4433-87c0-68b6b72699c7",
69
+ getName: function(val) {
70
+ return Object.entries(this).reduce((acc, [k, v]) => {
71
+ if (typeof v === "string" && v === val) return k;
72
+ return acc;
73
+ }, "Unknown");
74
+ }
75
+ });
76
+ function readUuidBytes(buf, pos) {
77
+ return Buffer.from([
78
+ buf[pos + 3],
79
+ buf[pos + 2],
80
+ buf[pos + 1],
81
+ buf[pos + 0],
82
+ buf[pos + 5],
83
+ buf[pos + 4],
84
+ buf[pos + 7],
85
+ buf[pos + 6],
86
+ buf[pos + 8],
87
+ buf[pos + 9],
88
+ buf[pos + 10],
89
+ buf[pos + 11],
90
+ buf[pos + 12],
91
+ buf[pos + 13],
92
+ buf[pos + 14],
93
+ buf[pos + 15]
94
+ ]);
95
+ }
96
+ function readUuidString(buf, pos) {
97
+ const uuid = readUuidBytes(buf, pos).toString("hex");
98
+ return `${uuid.slice(0, 8)}-${uuid.slice(8, 12)}-${uuid.slice(12, 16)}-${uuid.slice(16, 20)}-${uuid.slice(20, 32)}`;
99
+ }
100
+ function parseGPTable(buf) {
101
+ const typeId = readUuidString(buf, 0);
102
+ const uuid = readUuidString(buf, 16);
103
+ const startLBA = buf.readBigUInt64LE(32);
104
+ const endLBA = buf.readBigUInt64LE(40);
105
+ return {
106
+ typeId,
107
+ type: gptPartTypes.getName(typeId),
108
+ uuid,
109
+ active: uuid !== gptPartTypes.EMPTY,
110
+ startLBA,
111
+ endLBA,
112
+ partitionSize: endLBA - startLBA + 1n,
113
+ attributes: buf.readBigUInt64BE(48),
114
+ label: buf.subarray(56, 128).toString("utf16le").split("\0", 1)[0]
115
+ };
116
+ }
117
+ function parseGPT(buf) {
118
+ if (buf.indexOf(EFI_PART) !== 0) throw Error("not GTP entry");
119
+ return {
120
+ revision: `${buf[8]}.${buf[9]}.${buf[10]}.${buf[11]}`,
121
+ headerSize: buf.readUInt32LE(12),
122
+ headerCRC32: buf.readUInt32LE(16),
123
+ currentLBA: buf.readBigUInt64LE(24),
124
+ backupLBA: buf.readBigUInt64LE(32),
125
+ firstUsableLBA: buf.readBigUInt64LE(40),
126
+ lastUsableLBA: buf.readBigUInt64LE(48),
127
+ uuid: readUuidString(buf, 56),
128
+ tableLBA: buf.readBigUInt64LE(72),
129
+ partitions: buf.readUInt32LE(80),
130
+ partitionSize: buf.readUInt32LE(84),
131
+ partitionCRC32: buf.readUInt32LE(88)
132
+ };
133
+ }
134
+ //#endregion
135
+ //#region src/mbrPart.ts
136
+ const partTypes = {
137
+ EMPTY: 0,
138
+ EXTENDED: 5,
139
+ NTFS: 7,
140
+ LINUX_SWAP: 130,
141
+ LINUX: 131,
142
+ LINUX_EXTENDED: 133,
143
+ LINUX_LVM: 142,
144
+ GPT: 238,
145
+ EFI: 239,
146
+ LINUX_RAID: 253,
147
+ getName: function(val) {
148
+ return Object.entries(this).reduce((acc, [k, v]) => {
149
+ if (typeof v === "number" && v === val) return k;
150
+ return acc;
151
+ }, "Unknown");
152
+ }
153
+ };
154
+ function parseMBR(mbr) {
155
+ if (mbr.length < 512 || mbr[510] !== 85 || mbr[511] !== 170) throw Error("no MBR signature or buffer is less than 512 bytes");
156
+ const ret = {
157
+ copyProtected: !!(mbr[444] === 90 && mbr[444] === 90),
158
+ uuid: Buffer.from([
159
+ mbr[443],
160
+ mbr[442],
161
+ mbr[441],
162
+ mbr[440]
163
+ ]).toString("hex"),
164
+ partitions: [],
165
+ type: "MBR"
166
+ };
167
+ for (let i = 446; i <= 508; i += 16) ret.partitions.push(parseMBRPartition(mbr.slice(i, i + 16)));
168
+ return ret;
169
+ }
170
+ function parseMBRPartition(part) {
171
+ const startLBA = part.readUInt32LE(8);
172
+ const partitionSize = part.readUInt32LE(12);
173
+ return {
174
+ active: part.readUInt8(0) === 128,
175
+ type: part.readUInt8(4),
176
+ startLBA,
177
+ partitionSize,
178
+ endLBA: startLBA + partitionSize
179
+ };
180
+ }
181
+ function isMbrPartition(part) {
182
+ return typeof part.type === "number";
183
+ }
184
+ //#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
+ //#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
+ });
209
+ }
210
+ if (p.type === partTypes.GPT) {
211
+ 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
+ rootMbr.partitions = partitions;
222
+ }
223
+ });
224
+ return rootMbr;
225
+ }
226
+ //#endregion
227
+ exports.Magic = Magic;
228
+ exports.scan = scan;
@@ -0,0 +1,48 @@
1
+ //#region src/Magic.d.ts
2
+ declare class Magic {
3
+ private fd;
4
+ constructor(fd: number);
5
+ haveExt(offset: number): boolean;
6
+ haveNtfs(offset: number): boolean;
7
+ haveLvm2(offset: number): boolean;
8
+ }
9
+ //#endregion
10
+ //#region src/types.d.ts
11
+ type MBRPartition = {
12
+ active: boolean;
13
+ type: number;
14
+ startLBA: number;
15
+ partitionSize: number;
16
+ endLBA: number;
17
+ };
18
+ type GPTPartition = {
19
+ typeId: string;
20
+ type: string;
21
+ uuid: string;
22
+ active: boolean;
23
+ startLBA: bigint;
24
+ endLBA: bigint;
25
+ partitionSize: bigint;
26
+ attributes: bigint;
27
+ label: string;
28
+ };
29
+ //#endregion
30
+ //#region src/mbrPart.d.ts
31
+ type GptData = {
32
+ copyProtected: boolean;
33
+ uuid: string;
34
+ type: 'GPT';
35
+ partitions: GPTPartition[];
36
+ };
37
+ type MbrData = {
38
+ copyProtected: boolean;
39
+ uuid: string;
40
+ type: 'MBR';
41
+ partitions: MBRPartition[];
42
+ };
43
+ type IMbrData = MbrData | GptData;
44
+ //#endregion
45
+ //#region src/scan.d.ts
46
+ declare function scan(fd: number): Promise<IMbrData>;
47
+ //#endregion
48
+ export { Magic, scan };
@@ -0,0 +1,48 @@
1
+ //#region src/Magic.d.ts
2
+ declare class Magic {
3
+ private fd;
4
+ constructor(fd: number);
5
+ haveExt(offset: number): boolean;
6
+ haveNtfs(offset: number): boolean;
7
+ haveLvm2(offset: number): boolean;
8
+ }
9
+ //#endregion
10
+ //#region src/types.d.ts
11
+ type MBRPartition = {
12
+ active: boolean;
13
+ type: number;
14
+ startLBA: number;
15
+ partitionSize: number;
16
+ endLBA: number;
17
+ };
18
+ type GPTPartition = {
19
+ typeId: string;
20
+ type: string;
21
+ uuid: string;
22
+ active: boolean;
23
+ startLBA: bigint;
24
+ endLBA: bigint;
25
+ partitionSize: bigint;
26
+ attributes: bigint;
27
+ label: string;
28
+ };
29
+ //#endregion
30
+ //#region src/mbrPart.d.ts
31
+ type GptData = {
32
+ copyProtected: boolean;
33
+ uuid: string;
34
+ type: 'GPT';
35
+ partitions: GPTPartition[];
36
+ };
37
+ type MbrData = {
38
+ copyProtected: boolean;
39
+ uuid: string;
40
+ type: 'MBR';
41
+ partitions: MBRPartition[];
42
+ };
43
+ type IMbrData = MbrData | GptData;
44
+ //#endregion
45
+ //#region src/scan.d.ts
46
+ declare function scan(fd: number): Promise<IMbrData>;
47
+ //#endregion
48
+ export { Magic, scan };
package/dist/index.mjs ADDED
@@ -0,0 +1,203 @@
1
+ import fs from "node:fs";
2
+ //#region src/Magic.ts
3
+ var Magic = class {
4
+ constructor(fd) {
5
+ this.fd = fd;
6
+ }
7
+ haveExt(offset) {
8
+ const data = Buffer.allocUnsafe(2048);
9
+ fs.readSync(this.fd, data, 0, data.length, 512 * offset);
10
+ return data.readInt16BE(1080) === 21487;
11
+ }
12
+ haveNtfs(offset) {
13
+ const data = Buffer.allocUnsafe(512);
14
+ fs.readSync(this.fd, data, 0, data.length, 512 * offset);
15
+ return data.readInt32BE(3) === 1314145875;
16
+ }
17
+ haveLvm2(offset) {
18
+ const data = Buffer.allocUnsafe(1024);
19
+ fs.readSync(this.fd, data, 0, data.length, 512 * offset);
20
+ return data.readInt32BE(536) === 1280724274;
21
+ }
22
+ };
23
+ //#endregion
24
+ //#region src/gptPart.ts
25
+ const EFI_PART = Buffer.from([
26
+ 69,
27
+ 70,
28
+ 73,
29
+ 32,
30
+ 80,
31
+ 65,
32
+ 82,
33
+ 84
34
+ ]);
35
+ const gptPartTypes = Object.freeze({
36
+ EMPTY: "00000000-0000-0000-0000-000000000000",
37
+ MBR: "024dee41-33e7-11d3-9d69-0008c781f39f",
38
+ EFI: "c12a7328-f81f-11d2-ba4b-00a0c93ec93b",
39
+ LINUX: "0fc63daf-8483-4772-8e79-3d69d8477de4",
40
+ LINUX_SWAP: "0657fd6d-a4ab-43c4-84e5-0933c84b4f4f",
41
+ LINUX_LVM: "e6d6d379-f507-44c2-a23c-238f2a3df928",
42
+ LINUX_RAID: "a19d880f-05fc-4d3b-a006-743f0f84911e",
43
+ MSR: "e3c9e316-0b5c-4db8-817d-f92df00215ae",
44
+ BASIC_DATA: "ebd0a0a2-b9e5-4433-87c0-68b6b72699c7",
45
+ getName: function(val) {
46
+ return Object.entries(this).reduce((acc, [k, v]) => {
47
+ if (typeof v === "string" && v === val) return k;
48
+ return acc;
49
+ }, "Unknown");
50
+ }
51
+ });
52
+ function readUuidBytes(buf, pos) {
53
+ return Buffer.from([
54
+ buf[pos + 3],
55
+ buf[pos + 2],
56
+ buf[pos + 1],
57
+ buf[pos + 0],
58
+ buf[pos + 5],
59
+ buf[pos + 4],
60
+ buf[pos + 7],
61
+ buf[pos + 6],
62
+ buf[pos + 8],
63
+ buf[pos + 9],
64
+ buf[pos + 10],
65
+ buf[pos + 11],
66
+ buf[pos + 12],
67
+ buf[pos + 13],
68
+ buf[pos + 14],
69
+ buf[pos + 15]
70
+ ]);
71
+ }
72
+ function readUuidString(buf, pos) {
73
+ const uuid = readUuidBytes(buf, pos).toString("hex");
74
+ return `${uuid.slice(0, 8)}-${uuid.slice(8, 12)}-${uuid.slice(12, 16)}-${uuid.slice(16, 20)}-${uuid.slice(20, 32)}`;
75
+ }
76
+ function parseGPTable(buf) {
77
+ const typeId = readUuidString(buf, 0);
78
+ const uuid = readUuidString(buf, 16);
79
+ const startLBA = buf.readBigUInt64LE(32);
80
+ const endLBA = buf.readBigUInt64LE(40);
81
+ return {
82
+ typeId,
83
+ type: gptPartTypes.getName(typeId),
84
+ uuid,
85
+ active: uuid !== gptPartTypes.EMPTY,
86
+ startLBA,
87
+ endLBA,
88
+ partitionSize: endLBA - startLBA + 1n,
89
+ attributes: buf.readBigUInt64BE(48),
90
+ label: buf.subarray(56, 128).toString("utf16le").split("\0", 1)[0]
91
+ };
92
+ }
93
+ function parseGPT(buf) {
94
+ if (buf.indexOf(EFI_PART) !== 0) throw Error("not GTP entry");
95
+ return {
96
+ revision: `${buf[8]}.${buf[9]}.${buf[10]}.${buf[11]}`,
97
+ headerSize: buf.readUInt32LE(12),
98
+ headerCRC32: buf.readUInt32LE(16),
99
+ currentLBA: buf.readBigUInt64LE(24),
100
+ backupLBA: buf.readBigUInt64LE(32),
101
+ firstUsableLBA: buf.readBigUInt64LE(40),
102
+ lastUsableLBA: buf.readBigUInt64LE(48),
103
+ uuid: readUuidString(buf, 56),
104
+ tableLBA: buf.readBigUInt64LE(72),
105
+ partitions: buf.readUInt32LE(80),
106
+ partitionSize: buf.readUInt32LE(84),
107
+ partitionCRC32: buf.readUInt32LE(88)
108
+ };
109
+ }
110
+ //#endregion
111
+ //#region src/mbrPart.ts
112
+ const partTypes = {
113
+ EMPTY: 0,
114
+ EXTENDED: 5,
115
+ NTFS: 7,
116
+ LINUX_SWAP: 130,
117
+ LINUX: 131,
118
+ LINUX_EXTENDED: 133,
119
+ LINUX_LVM: 142,
120
+ GPT: 238,
121
+ EFI: 239,
122
+ LINUX_RAID: 253,
123
+ getName: function(val) {
124
+ return Object.entries(this).reduce((acc, [k, v]) => {
125
+ if (typeof v === "number" && v === val) return k;
126
+ return acc;
127
+ }, "Unknown");
128
+ }
129
+ };
130
+ function parseMBR(mbr) {
131
+ if (mbr.length < 512 || mbr[510] !== 85 || mbr[511] !== 170) throw Error("no MBR signature or buffer is less than 512 bytes");
132
+ const ret = {
133
+ copyProtected: !!(mbr[444] === 90 && mbr[444] === 90),
134
+ uuid: Buffer.from([
135
+ mbr[443],
136
+ mbr[442],
137
+ mbr[441],
138
+ mbr[440]
139
+ ]).toString("hex"),
140
+ partitions: [],
141
+ type: "MBR"
142
+ };
143
+ for (let i = 446; i <= 508; i += 16) ret.partitions.push(parseMBRPartition(mbr.slice(i, i + 16)));
144
+ return ret;
145
+ }
146
+ function parseMBRPartition(part) {
147
+ const startLBA = part.readUInt32LE(8);
148
+ const partitionSize = part.readUInt32LE(12);
149
+ return {
150
+ active: part.readUInt8(0) === 128,
151
+ type: part.readUInt8(4),
152
+ startLBA,
153
+ partitionSize,
154
+ endLBA: startLBA + partitionSize
155
+ };
156
+ }
157
+ function isMbrPartition(part) {
158
+ return typeof part.type === "number";
159
+ }
160
+ //#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
+ //#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
+ });
185
+ }
186
+ if (p.type === partTypes.GPT) {
187
+ 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
+ rootMbr.partitions = partitions;
198
+ }
199
+ });
200
+ return rootMbr;
201
+ }
202
+ //#endregion
203
+ export { Magic, scan };
package/package.json CHANGED
@@ -1,38 +1,57 @@
1
1
  {
2
- "name": "mharj-diskinfo",
3
- "version": "0.0.2",
4
- "description": "",
5
- "main": "diskinfo.js",
6
- "scripts": {
7
- "test": "mocha"
8
- },
9
- "mocha": {
10
- "exit": true,
11
- "recursive": true,
12
- "reporters": [
13
- "spec"
14
- ]
15
- },
16
- "repository": {
17
- "type": "git",
18
- "url": "git+https://github.com/mharj/diskinfo.git"
19
- },
20
- "author": "mharj",
21
- "license": "LGPL",
22
- "bugs": {
23
- "url": "https://github.com/mharj/diskinfo/issues"
24
- },
25
- "homepage": "https://github.com/mharj/diskinfo#readme",
26
- "devDependencies": {
27
- "buffer-crc32": "^0.2.13",
28
- "chai": "^4.0.2",
29
- "chai-things": "^0.2.0",
30
- "eslint": "^7.32.0",
31
- "eslint-config-google": "^0.14.0",
32
- "mocha": "^9.1.0"
33
- },
34
- "dependencies": {
35
- "iconv-lite": "^0.6.3",
36
- "uuid-parse": "^1.0.0"
37
- }
2
+ "name": "mharj-diskinfo",
3
+ "version": "0.2.0",
4
+ "description": "Node.js library to parse MBR and GPT partition information from disk images or devices.",
5
+ "main": "./dist/index.cjs",
6
+ "module": "./dist/index.mjs",
7
+ "types": "./dist/index.d.mts",
8
+ "exports": {
9
+ "import": {
10
+ "types": "./dist/index.d.mts",
11
+ "default": "./dist/index.mjs"
12
+ },
13
+ "require": {
14
+ "types": "./dist/index.d.cts",
15
+ "default": "./dist/index.cjs"
16
+ },
17
+ "default": "./dist/index.mjs"
18
+ },
19
+ "scripts": {
20
+ "prepare": "lefthook install",
21
+ "build": "tsdown src/index.ts --format cjs,esm --dts --clean",
22
+ "prepublishOnly": "npm run build",
23
+ "test": "vitest test --typecheck --run --no-isolate --coverage",
24
+ "coverage": "vitest test --run --no-isolate --reporter=dot --coverage --coverage.reporter=lcov",
25
+ "lint": "biome check",
26
+ "validate": "tsc --noEmit --project tsconfig.test.json"
27
+ },
28
+ "repository": "github:mharj/diskinfo",
29
+ "files": [
30
+ "dist"
31
+ ],
32
+ "engines": {
33
+ "node": ">=10.4.0"
34
+ },
35
+ "author": "mharj",
36
+ "license": "LGPL",
37
+ "bugs": {
38
+ "url": "https://github.com/mharj/diskinfo/issues"
39
+ },
40
+ "homepage": "https://github.com/mharj/diskinfo#readme",
41
+ "devDependencies": {
42
+ "@biomejs/biome": "^2.4.15",
43
+ "@tsconfig/node16": "^16.1.8",
44
+ "@types/buffer-crc32": "^0.2.0",
45
+ "@types/node": "^22.19.1",
46
+ "@vitest/coverage-v8": "^4.1.6",
47
+ "buffer-crc32": "^0.2.13",
48
+ "c8": "^11.0.0",
49
+ "lefthook": "^2.1.6",
50
+ "tsdown": "^0.22.0",
51
+ "tslib": "^2.8.1",
52
+ "typescript": "^6.0.3",
53
+ "vite": "^8.0.12",
54
+ "vitest": "^4.1.6"
55
+ },
56
+ "packageManager": "pnpm@10.33.4+sha512.1c67b3b359b2d408119ba1ed289f34b8fc3c6873412bec6fd264fbdc82489e510fcbecb9ce9d22dae7f3b76269d8441046014bdca53b9979cd7a561ad631b800"
38
57
  }
package/diskinfo.js DELETED
@@ -1,179 +0,0 @@
1
- const fs = require('fs');
2
- const iconv = require('iconv-lite');
3
- const uuidParse = require('uuid-parse');
4
- const EFI_PART = Buffer.from([0x45, 0x46, 0x49, 0x20, 0x50, 0x41, 0x52, 0x54]);
5
-
6
- const gptPartTypes = Object.freeze({
7
- EMPTY: '00000000-0000-0000-0000-000000000000',
8
- MBR: '024dee41-33e7-11d3-9d69-0008c781f39f',
9
- EFI: 'c12a7328-f81f-11d2-ba4b-00a0c93ec93b',
10
- LINUX: '0fc63daf-8483-4772-8e79-3d69d8477de4',
11
- LINUX_SWAP: '0657fd6d-a4ab-43c4-84e5-0933c84b4f4f',
12
- LINUX_LVM: 'e6d6d379-f507-44c2-a23c-238f2a3df928',
13
- LINUX_RAID: 'a19d880f-05fc-4d3b-a006-743f0f84911e',
14
- MSR: 'e3c9e316-0b5c-4db8-817d-f92df00215ae',
15
- BASIC_DATA: 'ebd0a0a2-b9e5-4433-87c0-68b6b72699c7',
16
- getName: function(val) { // print names for values
17
- for (let k in gptPartTypes) {
18
- if (gptPartTypes[k] == val) {
19
- return k;
20
- }
21
- }
22
- return 'Unknown';
23
- },
24
- });
25
- module.exports.gptPartTypes = gptPartTypes;
26
-
27
- const partTypes = {
28
- EMPTY: 0x00,
29
- EXTENDED: 0x05,
30
- NTFS: 0x07,
31
- LINUX_SWAP: 0x82,
32
- LINUX: 0x83,
33
- LINUX_EXTENDED: 0x85,
34
- LINUX_LVM: 0x8e,
35
- GPT: 0xee,
36
- EFI: 0xef,
37
- LINUX_RAID: 0xfd,
38
- getName: function(val) { // print names for values
39
- for (let k in partTypes) {
40
- if (partTypes[k] == val) {
41
- return k+' ('+val.toString(16)+')';
42
- }
43
- }
44
- return '('+val.toString(16)+')';
45
- },
46
- };
47
- module.exports.partTypes = partTypes;
48
-
49
- function parseMBRPartition(part) {
50
- let out = {};
51
- out.active = (part.readUInt8(0)==0x80?true:false);
52
- // out.startCHS = Buffer.from([part[1],part[2],part[3]]); // obsolete
53
- out.type = part.readUInt8(4);
54
- // out.endCHS = Buffer.from([part[5],part[6],part[7]]); // obsolete
55
- out.startLBA = part.readUInt32LE(8);
56
- out.partitionSize = part.readUInt32LE(12);
57
- out.endLBA = out.startLBA+out.partitionSize;
58
- return out;
59
- }
60
-
61
- function parseMBR(mbr) {
62
- if ( mbr.length < 512 || mbr[0x1fe] != 85 || mbr[0x1ff] != 170 ) { // MBR signature
63
- throw Error('no MBR signature or buffer is less than 512 bytes');
64
- }
65
- let ret = {partitions: []};
66
- if ( mbr[0x1bc] == 90 && mbr[0x1bc] == 90 ) { // 0x5A5A = copy protected (UEFI)
67
- ret.copyProtected = true;
68
- }
69
- ret.uuid = Buffer.from([mbr[0x1bb], mbr[0x1ba], mbr[0x1b9], mbr[0x1b8]]).toString('hex'); // DiskID: 1B8 (hex) through 1BE (hex) (looks like reverse)
70
- for (let i = 446; i <= 508; i += 16) { // MBR table blocks
71
- ret.partitions.push( parseMBRPartition( mbr.slice(i, i+16) ) );
72
- }
73
- return ret;
74
- }
75
- module.exports.parseMBR = parseMBR;
76
-
77
- function readUuidBytes(buf, pos) {
78
- return [
79
- buf[(pos+3)], buf[(pos+2)], buf[(pos+1)], buf[(pos+0)],
80
- buf[(pos+5)], buf[(pos+4)], buf[(pos+7)], buf[(pos+6)],
81
- buf[(pos+8)], buf[(pos+9)], buf[(pos+10)], buf[(pos+11)],
82
- buf[(pos+12)], buf[(pos+13)], buf[(pos+14)], buf[(pos+15)],
83
- ];
84
- }
85
-
86
- function parseGPT(buf) { // https://en.wikipedia.org/wiki/GUID_Partition_Table
87
- let out = {};
88
- if ( buf.indexOf(EFI_PART) != 0 ) {
89
- throw Error('not GTP entry');
90
- }
91
- out.revision = buf[8]+'.'+buf[9]+'.'+buf[10]+'.'+buf[11];
92
- out.headerSize = buf.readUInt32LE(12);
93
- out.headerCRC32 = buf.readUInt32LE(16);
94
- // buf.readUInt32LE(20); // reserved; must be zero
95
- out.currentLBA = buf.readBigUInt64LE(24); // Warning: 64bit uint, JS uses this as 53bit
96
- out.backupLBA = buf.readBigUInt64LE(32); // Warning: 64bit uint, JS uses this as 53bit
97
- out.firstUsableLBA = buf.readBigUInt64LE(40); // Warning: 64bit uint, JS uses this as 53bit
98
- out.lastUsableLBA = buf.readBigUInt64LE(48); // Warning: 64bit uint, JS uses this as 53bit
99
- out.uuid = uuidParse.unparse(readUuidBytes(buf, 56));
100
- out.tableLBA = buf.readBigUInt64LE(72); // Warning: 64bit uint, JS uses this as 53bit
101
- out.partitions = buf.readUInt32LE(80);
102
- out.partitionSize = buf.readUInt32LE(84);
103
- out.partitionCRC32 = buf.readUInt32LE(88);
104
- return out;
105
- }
106
- module.exports.parseGPT = parseGPT;
107
-
108
- function parseGPTable(buf) {
109
- let out = {};
110
- out.typeId = uuidParse.unparse(readUuidBytes(buf, 0));
111
- out.type = gptPartTypes.getName(out.typeId);
112
- out.uuid = uuidParse.unparse(readUuidBytes(buf, 16));
113
- out.active = (out.uuid==gptPartTypes.EMPTY?false:true);
114
- out.startLBA = buf.readBigUInt64LE(32); // Warning: 64bit uint, JS uses this as 53bit
115
- out.endLBA = buf.readBigUInt64LE(40); // Warning: 64bit uint, JS uses this as 53bit
116
- out.partitionSize = out.endLBA-out.startLBA + 1n; // +1?
117
- out.attributes = buf.readBigUInt64BE(48); // Warning: 64bit uint, JS uses this as 53bit
118
- out.label = iconv.decode(buf.slice(56, 128), 'utf16le').split('\u0000')[0]; // bit hack in here
119
- return out;
120
- }
121
- module.exports.parseGPTable = parseGPTable;
122
-
123
- const buffer = Buffer.allocUnsafe(512);
124
- function scan(fd) {
125
- if ( fs.readSync(fd, buffer, 0, buffer.length, 0) != 512 ) {
126
- throw Error('read only partial data from MBR');
127
- }
128
- let rootMbr = parseMBR(buffer);
129
- rootMbr.type = 'MBR';
130
- rootMbr.partitions.forEach(function(p) {
131
- if ( p.type == partTypes.EXTENDED ) { // Extended partition reading
132
- fs.readSync(fd, buffer, 0, buffer.length, (p.startSector*512));
133
- let extparts = parseMBR(buffer);
134
- extparts.partitions.forEach(function(extpart) {
135
- if ( extpart.type != partTypes.EMPTY ) {
136
- extpart.startLBA = extpart.startLBA + p.startLBA;
137
- rootMbr.partitions.push(extpart);
138
- }
139
- });
140
- }
141
- if ( p.type == partTypes.GPT ) { // GPT partition table reading
142
- fs.readSync(fd, buffer, 0, buffer.length, 512);
143
- let gpt = parseGPT(buffer);
144
- rootMbr.uuid = gpt.uuid;
145
- let gBuff = Buffer.allocUnsafe( (gpt.partitions*gpt.partitionSize) );
146
- fs.readSync(fd, gBuff, 0, gBuff.length, (Number(gpt.tableLBA)*512));
147
- let partitions = [];
148
- for (let i=0; i < (gpt.partitions*gpt.partitionSize); i+=gpt.partitionSize ) {
149
- let table = parseGPTable(gBuff.slice(i, i+gpt.partitionSize));
150
- if ( table.typeId != gptPartTypes.EMPTY ) {
151
- partitions.push(table);
152
- }
153
- }
154
- rootMbr.partitions = partitions;
155
- rootMbr.type = 'GPT';
156
- }
157
- });
158
- return rootMbr;
159
- }
160
- module.exports.scan = scan;
161
-
162
- function magic(fd) {
163
- this.haveExt = function(offset) {
164
- let data = Buffer.allocUnsafe(2048);
165
- fs.readSync(fd, data, 0, data.length, (512*offset) );
166
- return (data.readInt16BE(1080) == 0x53ef);
167
- };
168
- this.haveNtfs = function(offset) {
169
- let data = Buffer.allocUnsafe(512);
170
- fs.readSync(fd, data, 0, data.length, (512*offset) );
171
- return (data.readInt32BE(3) == 0x4e544653);
172
- };
173
- this.haveLvm2 = function(offset) {
174
- let data = Buffer.allocUnsafe(1024);
175
- fs.readSync(fd, data, 0, data.length, (512*offset) );
176
- return (data.readInt32BE(536) == 0x4c564d32);
177
- };
178
- }
179
- module.exports.magic = magic;