@gjsify/fs 0.1.15 → 0.3.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/lib/esm/callback.js +22 -13
- package/lib/esm/cp.js +253 -0
- package/lib/esm/dir.js +160 -0
- package/lib/esm/fd-ops.js +189 -0
- package/lib/esm/file-handle.js +263 -84
- package/lib/esm/fs-watcher.js +88 -4
- package/lib/esm/glob.js +164 -0
- package/lib/esm/index.js +128 -2
- package/lib/esm/promises.js +90 -27
- package/lib/esm/read-stream.js +53 -43
- package/lib/esm/stat-watcher.js +121 -0
- package/lib/esm/statfs.js +57 -0
- package/lib/esm/sync.js +70 -52
- package/lib/esm/utils.js +7 -0
- package/lib/esm/utimes.js +62 -0
- package/lib/esm/write-stream.js +2 -5
- package/lib/types/cp.d.ts +18 -0
- package/lib/types/cp.spec.d.ts +2 -0
- package/lib/types/dir.d.ts +29 -0
- package/lib/types/dir.spec.d.ts +2 -0
- package/lib/types/fd-ops.d.ts +57 -0
- package/lib/types/fd-ops.spec.d.ts +2 -0
- package/lib/types/file-handle.d.ts +34 -4
- package/lib/types/fs-watcher.d.ts +9 -2
- package/lib/types/glob.d.ts +8 -0
- package/lib/types/glob.spec.d.ts +2 -0
- package/lib/types/index.d.ts +51 -1
- package/lib/types/promises.d.ts +31 -4
- package/lib/types/read-stream.d.ts +3 -1
- package/lib/types/stat-watcher.d.ts +21 -0
- package/lib/types/statfs.d.ts +35 -0
- package/lib/types/statfs.spec.d.ts +2 -0
- package/lib/types/sync.d.ts +4 -7
- package/lib/types/utils.d.ts +2 -0
- package/lib/types/utimes.d.ts +13 -0
- package/lib/types/utimes.spec.d.ts +2 -0
- package/lib/types/watch.spec.d.ts +2 -0
- package/lib/types/watchfile.spec.d.ts +2 -0
- package/lib/types/write-stream.d.ts +1 -2
- package/package.json +12 -12
- package/src/callback.ts +22 -13
- package/src/cp.spec.ts +181 -0
- package/src/cp.ts +328 -0
- package/src/dir.spec.ts +204 -0
- package/src/dir.ts +199 -0
- package/src/fd-ops.spec.ts +234 -0
- package/src/fd-ops.ts +251 -0
- package/src/file-handle.ts +264 -94
- package/src/fs-watcher.ts +101 -6
- package/src/glob.spec.ts +201 -0
- package/src/glob.ts +205 -0
- package/src/index.ts +74 -0
- package/src/promises.ts +94 -29
- package/src/read-stream.ts +49 -43
- package/src/stat-watcher.ts +116 -0
- package/src/statfs.spec.ts +67 -0
- package/src/statfs.ts +92 -0
- package/src/streams.spec.ts +58 -0
- package/src/sync.ts +75 -57
- package/src/test.mts +13 -2
- package/src/utils.ts +10 -0
- package/src/utimes.spec.ts +113 -0
- package/src/utimes.ts +97 -0
- package/src/watch.spec.ts +171 -0
- package/src/watchfile.spec.ts +185 -0
- package/src/write-stream.ts +5 -8
- package/tsconfig.tsbuildinfo +1 -1
package/lib/esm/callback.js
CHANGED
|
@@ -6,17 +6,19 @@ import { Buffer } from "node:buffer";
|
|
|
6
6
|
import { Stats, BigIntStats, STAT_ATTRIBUTES } from "./stats.js";
|
|
7
7
|
import { createNodeError } from "./errors.js";
|
|
8
8
|
import { realpathSync, readdirSync, renameSync, copyFileSync, accessSync, appendFileSync, readlinkSync, truncateSync, chmodSync, chownSync, mkdirSync, rmdirSync, readFileSync, writeFileSync } from "./sync.js";
|
|
9
|
+
import { normalizePath } from "./utils.js";
|
|
9
10
|
function parseOptsCb(optionsOrCallback, maybeCallback) {
|
|
10
11
|
return typeof optionsOrCallback === "function" ? { options: {}, callback: optionsOrCallback } : { options: optionsOrCallback ?? {}, callback: maybeCallback };
|
|
11
12
|
}
|
|
12
13
|
function statImpl(path, flags, syscall, options, callback) {
|
|
13
|
-
const
|
|
14
|
+
const pathStr = normalizePath(path);
|
|
15
|
+
const file = Gio.File.new_for_path(pathStr);
|
|
14
16
|
file.query_info_async(STAT_ATTRIBUTES, flags, GLib.PRIORITY_DEFAULT, null, (_s, res) => {
|
|
15
17
|
try {
|
|
16
18
|
const info = file.query_info_finish(res);
|
|
17
|
-
callback(null, options?.bigint ? new BigIntStats(info,
|
|
19
|
+
callback(null, options?.bigint ? new BigIntStats(info, pathStr) : new Stats(info, pathStr));
|
|
18
20
|
} catch (err) {
|
|
19
|
-
callback(createNodeError(err, syscall,
|
|
21
|
+
callback(createNodeError(err, syscall, pathStr));
|
|
20
22
|
}
|
|
21
23
|
});
|
|
22
24
|
}
|
|
@@ -53,13 +55,15 @@ function symlink(target, path, typeOrCallback, maybeCallback) {
|
|
|
53
55
|
if (typeof callback !== "function") {
|
|
54
56
|
throw new TypeError("Callback must be a function. Received " + typeof callback);
|
|
55
57
|
}
|
|
56
|
-
const
|
|
57
|
-
|
|
58
|
+
const pathStr = normalizePath(path);
|
|
59
|
+
const targetStr = normalizePath(target);
|
|
60
|
+
const file = Gio.File.new_for_path(pathStr);
|
|
61
|
+
file.make_symbolic_link_async(targetStr, GLib.PRIORITY_DEFAULT, null, (_s, res) => {
|
|
58
62
|
try {
|
|
59
63
|
file.make_symbolic_link_finish(res);
|
|
60
64
|
callback(null);
|
|
61
65
|
} catch (err) {
|
|
62
|
-
callback(createNodeError(err, "symlink",
|
|
66
|
+
callback(createNodeError(err, "symlink", targetStr, pathStr));
|
|
63
67
|
}
|
|
64
68
|
});
|
|
65
69
|
}
|
|
@@ -271,10 +275,11 @@ function rmdir(path, optsOrCb, maybeCb) {
|
|
|
271
275
|
function readFile(path, optsOrCb, maybeCb) {
|
|
272
276
|
const callback = typeof optsOrCb === "function" ? optsOrCb : maybeCb;
|
|
273
277
|
const options = typeof optsOrCb === "function" ? void 0 : optsOrCb;
|
|
278
|
+
const pathStr = normalizePath(path);
|
|
274
279
|
Promise.resolve().then(() => {
|
|
275
280
|
try {
|
|
276
281
|
const readOpts = typeof options === "string" ? { encoding: options, flag: "r" } : { encoding: options?.encoding ?? null, flag: options?.flag ?? "r" };
|
|
277
|
-
callback(null, readFileSync(
|
|
282
|
+
callback(null, readFileSync(pathStr, readOpts));
|
|
278
283
|
} catch (err) {
|
|
279
284
|
callback(err, null);
|
|
280
285
|
}
|
|
@@ -282,9 +287,10 @@ function readFile(path, optsOrCb, maybeCb) {
|
|
|
282
287
|
}
|
|
283
288
|
function writeFile(path, data, optsOrCb, maybeCb) {
|
|
284
289
|
const callback = typeof optsOrCb === "function" ? optsOrCb : maybeCb;
|
|
290
|
+
const pathStr = normalizePath(path);
|
|
285
291
|
Promise.resolve().then(() => {
|
|
286
292
|
try {
|
|
287
|
-
writeFileSync(
|
|
293
|
+
writeFileSync(pathStr, data);
|
|
288
294
|
callback(null);
|
|
289
295
|
} catch (err) {
|
|
290
296
|
callback(err);
|
|
@@ -292,16 +298,18 @@ function writeFile(path, data, optsOrCb, maybeCb) {
|
|
|
292
298
|
});
|
|
293
299
|
}
|
|
294
300
|
function link(existingPath, newPath, callback) {
|
|
301
|
+
const existingStr = normalizePath(existingPath);
|
|
302
|
+
const newStr = normalizePath(newPath);
|
|
295
303
|
Promise.resolve().then(() => {
|
|
296
304
|
try {
|
|
297
|
-
const result = GLib.spawn_command_line_sync(`ln ${
|
|
305
|
+
const result = GLib.spawn_command_line_sync(`ln ${existingStr} ${newStr}`);
|
|
298
306
|
if (!result[0]) {
|
|
299
|
-
throw Object.assign(new Error(`EPERM: operation not permitted, link '${
|
|
307
|
+
throw Object.assign(new Error(`EPERM: operation not permitted, link '${existingStr}' -> '${newStr}'`), {
|
|
300
308
|
code: "EPERM",
|
|
301
309
|
errno: -1,
|
|
302
310
|
syscall: "link",
|
|
303
|
-
path:
|
|
304
|
-
dest:
|
|
311
|
+
path: existingStr,
|
|
312
|
+
dest: newStr
|
|
305
313
|
});
|
|
306
314
|
}
|
|
307
315
|
callback(null);
|
|
@@ -311,9 +319,10 @@ function link(existingPath, newPath, callback) {
|
|
|
311
319
|
});
|
|
312
320
|
}
|
|
313
321
|
function unlink(path, callback) {
|
|
322
|
+
const pathStr = normalizePath(path);
|
|
314
323
|
Promise.resolve().then(() => {
|
|
315
324
|
try {
|
|
316
|
-
GLib.unlink(
|
|
325
|
+
GLib.unlink(pathStr);
|
|
317
326
|
callback(null);
|
|
318
327
|
} catch (err) {
|
|
319
328
|
callback(err);
|
package/lib/esm/cp.js
ADDED
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
import Gio from "@girs/gio-2.0";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { normalizePath } from "./utils.js";
|
|
4
|
+
import { createNodeError } from "./errors.js";
|
|
5
|
+
function makeEEXIST(destStr) {
|
|
6
|
+
const e = new Error(`ERR_FS_CP_EEXIST: file already exists, copyfile '${destStr}'`);
|
|
7
|
+
e.code = "ERR_FS_CP_EEXIST";
|
|
8
|
+
e.syscall = "copyfile";
|
|
9
|
+
e.path = destStr;
|
|
10
|
+
return e;
|
|
11
|
+
}
|
|
12
|
+
function makeEISDIR(srcStr) {
|
|
13
|
+
const e = new Error(`ERR_FS_EISDIR: illegal operation on a directory, copyfile '${srcStr}'`);
|
|
14
|
+
e.code = "ERR_FS_EISDIR";
|
|
15
|
+
e.syscall = "copyfile";
|
|
16
|
+
e.path = srcStr;
|
|
17
|
+
return e;
|
|
18
|
+
}
|
|
19
|
+
function makeENOTDIR(srcStr, destStr) {
|
|
20
|
+
const e = new Error(`ENOTDIR: not a directory, copyfile '${srcStr}' -> '${destStr}'`);
|
|
21
|
+
e.code = "ENOTDIR";
|
|
22
|
+
e.syscall = "copyfile";
|
|
23
|
+
e.path = srcStr;
|
|
24
|
+
e.dest = destStr;
|
|
25
|
+
return e;
|
|
26
|
+
}
|
|
27
|
+
function makeSYMLINKLOOP(srcStr, destStr) {
|
|
28
|
+
const e = new Error(`ELOOP: too many levels of symbolic links, copyfile '${srcStr}' -> '${destStr}'`);
|
|
29
|
+
e.code = "ELOOP";
|
|
30
|
+
e.syscall = "copyfile";
|
|
31
|
+
e.path = srcStr;
|
|
32
|
+
e.dest = destStr;
|
|
33
|
+
return e;
|
|
34
|
+
}
|
|
35
|
+
function queryCopyFlags(opts) {
|
|
36
|
+
const force = opts.force ?? true;
|
|
37
|
+
let flags = Gio.FileCopyFlags.NONE;
|
|
38
|
+
if (force) flags |= Gio.FileCopyFlags.OVERWRITE;
|
|
39
|
+
if (opts.preserveTimestamps) flags |= Gio.FileCopyFlags.TARGET_DEFAULT_MODIFIED_TIME;
|
|
40
|
+
if (!opts.dereference) flags |= Gio.FileCopyFlags.NOFOLLOW_SYMLINKS;
|
|
41
|
+
return flags;
|
|
42
|
+
}
|
|
43
|
+
function copyOneSyncFile(srcFile, destFile, srcStr, destStr, opts) {
|
|
44
|
+
const force = opts.force ?? true;
|
|
45
|
+
try {
|
|
46
|
+
const destInfo = destFile.query_info("standard::type", Gio.FileQueryInfoFlags.NONE, null);
|
|
47
|
+
if (destInfo.get_file_type() === Gio.FileType.DIRECTORY) {
|
|
48
|
+
throw makeENOTDIR(srcStr, destStr);
|
|
49
|
+
}
|
|
50
|
+
if (!force) {
|
|
51
|
+
if (opts.errorOnExist) throw makeEEXIST(destStr);
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
} catch (e) {
|
|
55
|
+
if (typeof e.code === "string") throw e;
|
|
56
|
+
}
|
|
57
|
+
const flags = queryCopyFlags(opts);
|
|
58
|
+
try {
|
|
59
|
+
srcFile.copy(destFile, flags, null, null);
|
|
60
|
+
} catch (err) {
|
|
61
|
+
throw createNodeError(err, "copyfile", srcStr, destStr);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
function cpOneDirSync(srcFile, destFile, srcStr, destStr, opts) {
|
|
65
|
+
const sep = srcStr.endsWith("/") ? "" : "/";
|
|
66
|
+
if (destStr.startsWith(srcStr + sep) && destStr !== srcStr) {
|
|
67
|
+
throw makeSYMLINKLOOP(srcStr, destStr);
|
|
68
|
+
}
|
|
69
|
+
if (!destFile.query_exists(null)) {
|
|
70
|
+
try {
|
|
71
|
+
destFile.make_directory_with_parents(null);
|
|
72
|
+
} catch (err) {
|
|
73
|
+
throw createNodeError(err, "mkdir", destStr);
|
|
74
|
+
}
|
|
75
|
+
} else {
|
|
76
|
+
try {
|
|
77
|
+
const destInfo = destFile.query_info("standard::type", Gio.FileQueryInfoFlags.NONE, null);
|
|
78
|
+
if (destInfo.get_file_type() !== Gio.FileType.DIRECTORY) {
|
|
79
|
+
throw makeENOTDIR(destStr, srcStr);
|
|
80
|
+
}
|
|
81
|
+
} catch (e) {
|
|
82
|
+
if (typeof e.code === "string") throw e;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
let enumerator;
|
|
86
|
+
try {
|
|
87
|
+
enumerator = srcFile.enumerate_children(
|
|
88
|
+
"standard::name,standard::type,standard::is-symlink",
|
|
89
|
+
opts.dereference ? Gio.FileQueryInfoFlags.NONE : Gio.FileQueryInfoFlags.NOFOLLOW_SYMLINKS,
|
|
90
|
+
null
|
|
91
|
+
);
|
|
92
|
+
} catch (err) {
|
|
93
|
+
throw createNodeError(err, "scandir", srcStr);
|
|
94
|
+
}
|
|
95
|
+
let childInfo = enumerator.next_file(null);
|
|
96
|
+
while (childInfo !== null) {
|
|
97
|
+
const name = childInfo.get_name();
|
|
98
|
+
const childSrc = join(srcStr, name);
|
|
99
|
+
const childDest = join(destStr, name);
|
|
100
|
+
const filter = opts.filter;
|
|
101
|
+
if (filter && !filter(childSrc, childDest)) {
|
|
102
|
+
childInfo = enumerator.next_file(null);
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
cpSyncInternal(childSrc, childDest, opts);
|
|
106
|
+
childInfo = enumerator.next_file(null);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
function cpSyncInternal(srcStr, destStr, opts) {
|
|
110
|
+
const srcFile = Gio.File.new_for_path(srcStr);
|
|
111
|
+
const destFile = Gio.File.new_for_path(destStr);
|
|
112
|
+
let info;
|
|
113
|
+
try {
|
|
114
|
+
info = srcFile.query_info(
|
|
115
|
+
"standard::type,standard::is-symlink",
|
|
116
|
+
opts.dereference ? Gio.FileQueryInfoFlags.NONE : Gio.FileQueryInfoFlags.NOFOLLOW_SYMLINKS,
|
|
117
|
+
null
|
|
118
|
+
);
|
|
119
|
+
} catch (err) {
|
|
120
|
+
throw createNodeError(err, "stat", srcStr);
|
|
121
|
+
}
|
|
122
|
+
const type = info.get_file_type();
|
|
123
|
+
if (type === Gio.FileType.DIRECTORY) {
|
|
124
|
+
if (!opts.recursive) throw makeEISDIR(srcStr);
|
|
125
|
+
cpOneDirSync(srcFile, destFile, srcStr, destStr, opts);
|
|
126
|
+
} else {
|
|
127
|
+
copyOneSyncFile(srcFile, destFile, srcStr, destStr, opts);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
function cpSync(src, dest, options) {
|
|
131
|
+
const srcStr = normalizePath(src);
|
|
132
|
+
const destStr = normalizePath(dest);
|
|
133
|
+
const opts = options ?? {};
|
|
134
|
+
const srcFile = Gio.File.new_for_path(srcStr);
|
|
135
|
+
const filter = opts.filter;
|
|
136
|
+
if (filter && !filter(srcStr, destStr)) return;
|
|
137
|
+
try {
|
|
138
|
+
const info = srcFile.query_info(
|
|
139
|
+
"standard::type",
|
|
140
|
+
opts.dereference ? Gio.FileQueryInfoFlags.NONE : Gio.FileQueryInfoFlags.NOFOLLOW_SYMLINKS,
|
|
141
|
+
null
|
|
142
|
+
);
|
|
143
|
+
if (info.get_file_type() === Gio.FileType.DIRECTORY && !opts.recursive) {
|
|
144
|
+
throw makeEISDIR(srcStr);
|
|
145
|
+
}
|
|
146
|
+
} catch (e) {
|
|
147
|
+
if (typeof e.code === "string") throw e;
|
|
148
|
+
throw createNodeError(e, "stat", srcStr);
|
|
149
|
+
}
|
|
150
|
+
cpSyncInternal(srcStr, destStr, opts);
|
|
151
|
+
}
|
|
152
|
+
function cp(src, dest, options, callback) {
|
|
153
|
+
let opts;
|
|
154
|
+
let cb;
|
|
155
|
+
if (typeof options === "function") {
|
|
156
|
+
cb = options;
|
|
157
|
+
opts = {};
|
|
158
|
+
} else {
|
|
159
|
+
cb = callback;
|
|
160
|
+
opts = options;
|
|
161
|
+
}
|
|
162
|
+
const asyncFilter = opts.filter;
|
|
163
|
+
if (asyncFilter) {
|
|
164
|
+
Promise.resolve(asyncFilter(normalizePath(src), normalizePath(dest))).then((include) => {
|
|
165
|
+
if (!include) {
|
|
166
|
+
cb(null);
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
try {
|
|
170
|
+
cpPromises(src, dest, opts).then(() => cb(null)).catch(cb);
|
|
171
|
+
} catch (e) {
|
|
172
|
+
cb(e);
|
|
173
|
+
}
|
|
174
|
+
}).catch(cb);
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
Promise.resolve().then(() => {
|
|
178
|
+
try {
|
|
179
|
+
cpSync(src, dest, opts);
|
|
180
|
+
cb(null);
|
|
181
|
+
} catch (e) {
|
|
182
|
+
cb(e);
|
|
183
|
+
}
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
async function cpPromisesDir(srcStr, destStr, opts) {
|
|
187
|
+
const sep = srcStr.endsWith("/") ? "" : "/";
|
|
188
|
+
if (destStr.startsWith(srcStr + sep) && destStr !== srcStr) {
|
|
189
|
+
throw makeSYMLINKLOOP(srcStr, destStr);
|
|
190
|
+
}
|
|
191
|
+
const destFile = Gio.File.new_for_path(destStr);
|
|
192
|
+
if (!destFile.query_exists(null)) {
|
|
193
|
+
try {
|
|
194
|
+
destFile.make_directory_with_parents(null);
|
|
195
|
+
} catch (err) {
|
|
196
|
+
throw createNodeError(err, "mkdir", destStr);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
const srcFile = Gio.File.new_for_path(srcStr);
|
|
200
|
+
let enumerator;
|
|
201
|
+
try {
|
|
202
|
+
enumerator = srcFile.enumerate_children(
|
|
203
|
+
"standard::name,standard::type",
|
|
204
|
+
opts.dereference ? Gio.FileQueryInfoFlags.NONE : Gio.FileQueryInfoFlags.NOFOLLOW_SYMLINKS,
|
|
205
|
+
null
|
|
206
|
+
);
|
|
207
|
+
} catch (err) {
|
|
208
|
+
throw createNodeError(err, "scandir", srcStr);
|
|
209
|
+
}
|
|
210
|
+
let childInfo = enumerator.next_file(null);
|
|
211
|
+
while (childInfo !== null) {
|
|
212
|
+
const name = childInfo.get_name();
|
|
213
|
+
const childSrc = join(srcStr, name);
|
|
214
|
+
const childDest = join(destStr, name);
|
|
215
|
+
const filter = opts.filter;
|
|
216
|
+
if (filter) {
|
|
217
|
+
const include = await Promise.resolve(filter(childSrc, childDest));
|
|
218
|
+
if (!include) {
|
|
219
|
+
childInfo = enumerator.next_file(null);
|
|
220
|
+
continue;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
await cpPromises(childSrc, childDest, opts);
|
|
224
|
+
childInfo = enumerator.next_file(null);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
async function cpPromises(src, dest, opts = {}) {
|
|
228
|
+
const srcStr = normalizePath(src);
|
|
229
|
+
const destStr = normalizePath(dest);
|
|
230
|
+
const srcFile = Gio.File.new_for_path(srcStr);
|
|
231
|
+
let info;
|
|
232
|
+
try {
|
|
233
|
+
info = srcFile.query_info(
|
|
234
|
+
"standard::type",
|
|
235
|
+
opts.dereference ? Gio.FileQueryInfoFlags.NONE : Gio.FileQueryInfoFlags.NOFOLLOW_SYMLINKS,
|
|
236
|
+
null
|
|
237
|
+
);
|
|
238
|
+
} catch (err) {
|
|
239
|
+
throw createNodeError(err, "stat", srcStr);
|
|
240
|
+
}
|
|
241
|
+
if (info.get_file_type() === Gio.FileType.DIRECTORY) {
|
|
242
|
+
if (!opts.recursive) throw makeEISDIR(srcStr);
|
|
243
|
+
await cpPromisesDir(srcStr, destStr, opts);
|
|
244
|
+
} else {
|
|
245
|
+
const destFile = Gio.File.new_for_path(destStr);
|
|
246
|
+
copyOneSyncFile(srcFile, destFile, srcStr, destStr, opts);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
export {
|
|
250
|
+
cp,
|
|
251
|
+
cpPromises as cpAsync,
|
|
252
|
+
cpSync
|
|
253
|
+
};
|
package/lib/esm/dir.js
ADDED
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import Gio from "@girs/gio-2.0";
|
|
2
|
+
import GLib from "@girs/glib-2.0";
|
|
3
|
+
import { normalizePath } from "./utils.js";
|
|
4
|
+
import { Dirent } from "./dirent.js";
|
|
5
|
+
import { createNodeError } from "./errors.js";
|
|
6
|
+
const DIR_ATTRS = "standard::name,standard::type,standard::is-symlink,standard::size,standard::symlink-target,unix::uid,unix::gid,unix::mode,time::modified,time::access,time::created";
|
|
7
|
+
class Dir {
|
|
8
|
+
path;
|
|
9
|
+
_enumerator;
|
|
10
|
+
_closed = false;
|
|
11
|
+
constructor(path, enumerator) {
|
|
12
|
+
this.path = path;
|
|
13
|
+
this._enumerator = enumerator;
|
|
14
|
+
}
|
|
15
|
+
_assertOpen() {
|
|
16
|
+
if (this._closed) {
|
|
17
|
+
const err = new Error("Directory handle was closed");
|
|
18
|
+
err.code = "ERR_DIR_CLOSED";
|
|
19
|
+
throw err;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
readSync() {
|
|
23
|
+
this._assertOpen();
|
|
24
|
+
try {
|
|
25
|
+
const info = this._enumerator.next_file(null);
|
|
26
|
+
if (info === null) return null;
|
|
27
|
+
const name = info.get_name();
|
|
28
|
+
const fileType = info.get_file_type();
|
|
29
|
+
const childPath = this.path.endsWith("/") ? this.path + name : this.path + "/" + name;
|
|
30
|
+
return new Dirent(childPath, name, fileType);
|
|
31
|
+
} catch (err) {
|
|
32
|
+
throw createNodeError(err, "readdir", this.path);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
read(callback) {
|
|
36
|
+
if (callback !== void 0) {
|
|
37
|
+
if (typeof callback !== "function") {
|
|
38
|
+
throw new TypeError('The "callback" argument must be of type function');
|
|
39
|
+
}
|
|
40
|
+
try {
|
|
41
|
+
this._assertOpen();
|
|
42
|
+
const dirent = this.readSync();
|
|
43
|
+
Promise.resolve().then(() => callback(null, dirent));
|
|
44
|
+
} catch (err) {
|
|
45
|
+
Promise.resolve().then(() => callback(err, null));
|
|
46
|
+
}
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
return new Promise((resolve, reject) => {
|
|
50
|
+
try {
|
|
51
|
+
this._assertOpen();
|
|
52
|
+
resolve(this.readSync());
|
|
53
|
+
} catch (err) {
|
|
54
|
+
reject(err);
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
closeSync() {
|
|
59
|
+
this._assertOpen();
|
|
60
|
+
this._closed = true;
|
|
61
|
+
try {
|
|
62
|
+
this._enumerator.close(null);
|
|
63
|
+
} catch {
|
|
64
|
+
}
|
|
65
|
+
this._enumerator = null;
|
|
66
|
+
}
|
|
67
|
+
close(callback) {
|
|
68
|
+
if (callback !== void 0) {
|
|
69
|
+
if (typeof callback !== "function") {
|
|
70
|
+
throw new TypeError('The "callback" argument must be of type function');
|
|
71
|
+
}
|
|
72
|
+
try {
|
|
73
|
+
this.closeSync();
|
|
74
|
+
Promise.resolve().then(() => callback(null));
|
|
75
|
+
} catch (err) {
|
|
76
|
+
Promise.resolve().then(() => callback(err));
|
|
77
|
+
}
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
return new Promise((resolve, reject) => {
|
|
81
|
+
try {
|
|
82
|
+
this.closeSync();
|
|
83
|
+
resolve();
|
|
84
|
+
} catch (err) {
|
|
85
|
+
reject(err);
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
async *[Symbol.asyncIterator]() {
|
|
90
|
+
try {
|
|
91
|
+
while (true) {
|
|
92
|
+
const dirent = await this.read();
|
|
93
|
+
if (dirent === null) break;
|
|
94
|
+
yield dirent;
|
|
95
|
+
}
|
|
96
|
+
} finally {
|
|
97
|
+
if (!this._closed) {
|
|
98
|
+
await this.close();
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
function _openDir(pathStr) {
|
|
104
|
+
const file = Gio.File.new_for_path(pathStr);
|
|
105
|
+
let enumerator;
|
|
106
|
+
try {
|
|
107
|
+
enumerator = file.enumerate_children(DIR_ATTRS, Gio.FileQueryInfoFlags.NOFOLLOW_SYMLINKS, null);
|
|
108
|
+
} catch (err) {
|
|
109
|
+
throw createNodeError(err, "opendir", pathStr);
|
|
110
|
+
}
|
|
111
|
+
return new Dir(pathStr, enumerator);
|
|
112
|
+
}
|
|
113
|
+
function opendirSync(path) {
|
|
114
|
+
return _openDir(normalizePath(path));
|
|
115
|
+
}
|
|
116
|
+
function opendir(path, optionsOrCallback, callback) {
|
|
117
|
+
let cb;
|
|
118
|
+
if (typeof optionsOrCallback === "function") {
|
|
119
|
+
cb = optionsOrCallback;
|
|
120
|
+
} else {
|
|
121
|
+
cb = callback;
|
|
122
|
+
}
|
|
123
|
+
if (typeof cb !== "function") {
|
|
124
|
+
throw new TypeError('The "callback" argument must be of type function');
|
|
125
|
+
}
|
|
126
|
+
Promise.resolve().then(() => {
|
|
127
|
+
try {
|
|
128
|
+
const dir = opendirSync(path);
|
|
129
|
+
cb(null, dir);
|
|
130
|
+
} catch (err) {
|
|
131
|
+
cb(err, null);
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
async function opendirAsync(path, _options) {
|
|
136
|
+
return new Promise((resolve, reject) => {
|
|
137
|
+
const pathStr = normalizePath(path);
|
|
138
|
+
const file = Gio.File.new_for_path(pathStr);
|
|
139
|
+
file.enumerate_children_async(
|
|
140
|
+
DIR_ATTRS,
|
|
141
|
+
Gio.FileQueryInfoFlags.NOFOLLOW_SYMLINKS,
|
|
142
|
+
GLib.PRIORITY_DEFAULT,
|
|
143
|
+
null,
|
|
144
|
+
(_source, result) => {
|
|
145
|
+
try {
|
|
146
|
+
const enumerator = file.enumerate_children_finish(result);
|
|
147
|
+
resolve(new Dir(pathStr, enumerator));
|
|
148
|
+
} catch (err) {
|
|
149
|
+
reject(createNodeError(err, "opendir", pathStr));
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
);
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
export {
|
|
156
|
+
Dir,
|
|
157
|
+
opendir,
|
|
158
|
+
opendirAsync,
|
|
159
|
+
opendirSync
|
|
160
|
+
};
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
import { FileHandle } from "./file-handle.js";
|
|
2
|
+
import { statSync, truncateSync, chmodSync, chownSync, readFileSync } from "./sync.js";
|
|
3
|
+
import { utimesSync } from "./utimes.js";
|
|
4
|
+
import { normalizePath } from "./utils.js";
|
|
5
|
+
function getFH(fd) {
|
|
6
|
+
if (fd instanceof FileHandle) return FileHandle.getInstance(fd.fd);
|
|
7
|
+
return FileHandle.getInstance(fd);
|
|
8
|
+
}
|
|
9
|
+
function fstatSync(fd, options) {
|
|
10
|
+
return statSync(normalizePath(getFH(fd).options.path), options);
|
|
11
|
+
}
|
|
12
|
+
function fstat(fd, optionsOrCb, callback) {
|
|
13
|
+
if (typeof optionsOrCb === "function") {
|
|
14
|
+
callback = optionsOrCb;
|
|
15
|
+
optionsOrCb = {};
|
|
16
|
+
}
|
|
17
|
+
Promise.resolve().then(() => fstatSync(fd, optionsOrCb)).then((s) => callback(null, s), callback);
|
|
18
|
+
}
|
|
19
|
+
async function fstatAsync(fd, options) {
|
|
20
|
+
return fstatSync(fd, options);
|
|
21
|
+
}
|
|
22
|
+
function ftruncateSync(fd, len = 0) {
|
|
23
|
+
truncateSync(normalizePath(getFH(fd).options.path), len);
|
|
24
|
+
}
|
|
25
|
+
function ftruncate(fd, lenOrCb, callback) {
|
|
26
|
+
if (typeof lenOrCb === "function") {
|
|
27
|
+
callback = lenOrCb;
|
|
28
|
+
lenOrCb = 0;
|
|
29
|
+
}
|
|
30
|
+
Promise.resolve().then(() => ftruncateSync(fd, lenOrCb)).then(() => callback(null), callback);
|
|
31
|
+
}
|
|
32
|
+
async function ftruncateAsync(fd, len = 0) {
|
|
33
|
+
ftruncateSync(fd, len);
|
|
34
|
+
}
|
|
35
|
+
function fdatasyncSync(fd) {
|
|
36
|
+
getFH(fd)._flushSync();
|
|
37
|
+
}
|
|
38
|
+
function fdatasync(fd, callback) {
|
|
39
|
+
Promise.resolve().then(() => fdatasyncSync(fd)).then(() => callback(null), callback);
|
|
40
|
+
}
|
|
41
|
+
async function fdatasyncAsync(fd) {
|
|
42
|
+
fdatasyncSync(fd);
|
|
43
|
+
}
|
|
44
|
+
function fsyncSync(fd) {
|
|
45
|
+
getFH(fd)._flushSync();
|
|
46
|
+
}
|
|
47
|
+
function fsync(fd, callback) {
|
|
48
|
+
Promise.resolve().then(() => fsyncSync(fd)).then(() => callback(null), callback);
|
|
49
|
+
}
|
|
50
|
+
async function fsyncAsync(fd) {
|
|
51
|
+
fsyncSync(fd);
|
|
52
|
+
}
|
|
53
|
+
function fchmodSync(fd, mode) {
|
|
54
|
+
chmodSync(normalizePath(getFH(fd).options.path), mode);
|
|
55
|
+
}
|
|
56
|
+
function fchmod(fd, mode, callback) {
|
|
57
|
+
Promise.resolve().then(() => fchmodSync(fd, mode)).then(() => callback(null), callback);
|
|
58
|
+
}
|
|
59
|
+
async function fchmodAsync(fd, mode) {
|
|
60
|
+
fchmodSync(fd, mode);
|
|
61
|
+
}
|
|
62
|
+
function fchownSync(fd, uid, gid) {
|
|
63
|
+
chownSync(normalizePath(getFH(fd).options.path), uid, gid);
|
|
64
|
+
}
|
|
65
|
+
function fchown(fd, uid, gid, callback) {
|
|
66
|
+
Promise.resolve().then(() => fchownSync(fd, uid, gid)).then(() => callback(null), callback);
|
|
67
|
+
}
|
|
68
|
+
async function fchownAsync(fd, uid, gid) {
|
|
69
|
+
fchownSync(fd, uid, gid);
|
|
70
|
+
}
|
|
71
|
+
function futimesSync(fd, atime, mtime) {
|
|
72
|
+
utimesSync(normalizePath(getFH(fd).options.path), atime, mtime);
|
|
73
|
+
}
|
|
74
|
+
function futimes(fd, atime, mtime, callback) {
|
|
75
|
+
Promise.resolve().then(() => futimesSync(fd, atime, mtime)).then(() => callback(null), callback);
|
|
76
|
+
}
|
|
77
|
+
async function futimesAsync(fd, atime, mtime) {
|
|
78
|
+
futimesSync(fd, atime, mtime);
|
|
79
|
+
}
|
|
80
|
+
function closeSync(fd) {
|
|
81
|
+
getFH(fd)._closeSync();
|
|
82
|
+
}
|
|
83
|
+
function readSync(fd, buffer, offsetOrOptions, length, position) {
|
|
84
|
+
let offset = 0;
|
|
85
|
+
if (offsetOrOptions !== null && typeof offsetOrOptions === "object") {
|
|
86
|
+
offset = offsetOrOptions.offset ?? 0;
|
|
87
|
+
length = offsetOrOptions.length ?? buffer.byteLength;
|
|
88
|
+
position = offsetOrOptions.position ?? null;
|
|
89
|
+
} else {
|
|
90
|
+
offset = offsetOrOptions ?? 0;
|
|
91
|
+
length = length ?? buffer.byteLength - offset;
|
|
92
|
+
}
|
|
93
|
+
return getFH(fd)._readSync(buffer, offset, length, position ?? null);
|
|
94
|
+
}
|
|
95
|
+
function writeSync(fd, bufferOrString, offsetOrPosition, lengthOrEncoding, position) {
|
|
96
|
+
let data;
|
|
97
|
+
if (typeof bufferOrString === "string") {
|
|
98
|
+
data = new TextEncoder().encode(bufferOrString);
|
|
99
|
+
if (typeof offsetOrPosition === "number") position = offsetOrPosition;
|
|
100
|
+
} else {
|
|
101
|
+
const offset = typeof offsetOrPosition === "number" ? offsetOrPosition : 0;
|
|
102
|
+
const len = typeof lengthOrEncoding === "number" ? lengthOrEncoding : bufferOrString.byteLength - offset;
|
|
103
|
+
data = new Uint8Array(bufferOrString.buffer, bufferOrString.byteOffset + offset, len);
|
|
104
|
+
}
|
|
105
|
+
return getFH(fd)._writeSync(data, position ?? null);
|
|
106
|
+
}
|
|
107
|
+
function readvSync(fd, buffers, position) {
|
|
108
|
+
let bytesRead = 0;
|
|
109
|
+
for (const buf of buffers) {
|
|
110
|
+
const n = readSync(fd, buf, 0, buf.byteLength, position != null ? position + bytesRead : null);
|
|
111
|
+
bytesRead += n;
|
|
112
|
+
if (n < buf.byteLength) break;
|
|
113
|
+
}
|
|
114
|
+
return bytesRead;
|
|
115
|
+
}
|
|
116
|
+
function readv(fd, buffers, positionOrCb, callback) {
|
|
117
|
+
if (typeof positionOrCb === "function") {
|
|
118
|
+
callback = positionOrCb;
|
|
119
|
+
positionOrCb = null;
|
|
120
|
+
}
|
|
121
|
+
Promise.resolve().then(() => ({ bytesRead: readvSync(fd, buffers, positionOrCb), buffers })).then((r) => callback(null, r.bytesRead, r.buffers), callback);
|
|
122
|
+
}
|
|
123
|
+
async function readvAsync(fd, buffers, position) {
|
|
124
|
+
return { bytesRead: readvSync(fd, buffers, position), buffers };
|
|
125
|
+
}
|
|
126
|
+
function writevSync(fd, buffers, position) {
|
|
127
|
+
let bytesWritten = 0;
|
|
128
|
+
for (const buf of buffers) {
|
|
129
|
+
const n = writeSync(fd, buf, 0, buf.byteLength, position != null ? position + bytesWritten : null);
|
|
130
|
+
bytesWritten += n;
|
|
131
|
+
}
|
|
132
|
+
return bytesWritten;
|
|
133
|
+
}
|
|
134
|
+
function writev(fd, buffers, positionOrCb, callback) {
|
|
135
|
+
if (typeof positionOrCb === "function") {
|
|
136
|
+
callback = positionOrCb;
|
|
137
|
+
positionOrCb = null;
|
|
138
|
+
}
|
|
139
|
+
Promise.resolve().then(() => ({ bytesWritten: writevSync(fd, buffers, positionOrCb), buffers })).then((r) => callback(null, r.bytesWritten, r.buffers), callback);
|
|
140
|
+
}
|
|
141
|
+
async function writevAsync(fd, buffers, position) {
|
|
142
|
+
return { bytesWritten: writevSync(fd, buffers, position), buffers };
|
|
143
|
+
}
|
|
144
|
+
function exists(path, callback) {
|
|
145
|
+
try {
|
|
146
|
+
statSync(normalizePath(path));
|
|
147
|
+
callback(true);
|
|
148
|
+
} catch {
|
|
149
|
+
callback(false);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
async function openAsBlob(path, options) {
|
|
153
|
+
const data = readFileSync(normalizePath(path));
|
|
154
|
+
return new Blob([data], { type: options?.type ?? "" });
|
|
155
|
+
}
|
|
156
|
+
export {
|
|
157
|
+
closeSync,
|
|
158
|
+
exists,
|
|
159
|
+
fchmod,
|
|
160
|
+
fchmodAsync,
|
|
161
|
+
fchmodSync,
|
|
162
|
+
fchown,
|
|
163
|
+
fchownAsync,
|
|
164
|
+
fchownSync,
|
|
165
|
+
fdatasync,
|
|
166
|
+
fdatasyncAsync,
|
|
167
|
+
fdatasyncSync,
|
|
168
|
+
fstat,
|
|
169
|
+
fstatAsync,
|
|
170
|
+
fstatSync,
|
|
171
|
+
fsync,
|
|
172
|
+
fsyncAsync,
|
|
173
|
+
fsyncSync,
|
|
174
|
+
ftruncate,
|
|
175
|
+
ftruncateAsync,
|
|
176
|
+
ftruncateSync,
|
|
177
|
+
futimes,
|
|
178
|
+
futimesAsync,
|
|
179
|
+
futimesSync,
|
|
180
|
+
openAsBlob,
|
|
181
|
+
readSync,
|
|
182
|
+
readv,
|
|
183
|
+
readvAsync,
|
|
184
|
+
readvSync,
|
|
185
|
+
writeSync,
|
|
186
|
+
writev,
|
|
187
|
+
writevAsync,
|
|
188
|
+
writevSync
|
|
189
|
+
};
|