@gjsify/fs 0.1.13 → 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/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/read-stream.js
CHANGED
|
@@ -2,7 +2,7 @@ import Gio from "@girs/gio-2.0";
|
|
|
2
2
|
import GLib from "@girs/glib-2.0";
|
|
3
3
|
import { Buffer } from "node:buffer";
|
|
4
4
|
import { Readable } from "node:stream";
|
|
5
|
-
import {
|
|
5
|
+
import { normalizePath } from "./utils.js";
|
|
6
6
|
class ReadStream extends Readable {
|
|
7
7
|
bytesRead = 0;
|
|
8
8
|
path;
|
|
@@ -10,56 +10,62 @@ class ReadStream extends Readable {
|
|
|
10
10
|
fd = null;
|
|
11
11
|
_gioFile;
|
|
12
12
|
_inputStream = null;
|
|
13
|
+
_cancellable = new Gio.Cancellable();
|
|
13
14
|
_start;
|
|
14
15
|
_end;
|
|
15
16
|
_pos;
|
|
16
17
|
close(callback) {
|
|
18
|
+
this._cancellable.cancel();
|
|
17
19
|
if (this._inputStream) {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
} catch {
|
|
21
|
-
}
|
|
20
|
+
this._inputStream.close_async(GLib.PRIORITY_DEFAULT, null, () => {
|
|
21
|
+
});
|
|
22
22
|
this._inputStream = null;
|
|
23
23
|
}
|
|
24
24
|
this.destroy();
|
|
25
25
|
if (callback) callback(null);
|
|
26
26
|
}
|
|
27
27
|
constructor(path, opts) {
|
|
28
|
-
|
|
29
|
-
path = fileURLToPath(path);
|
|
30
|
-
}
|
|
28
|
+
const pathStr = normalizePath(path);
|
|
31
29
|
super({
|
|
32
30
|
highWaterMark: opts?.highWaterMark ?? 64 * 1024,
|
|
33
31
|
encoding: opts?.encoding,
|
|
34
32
|
objectMode: false
|
|
35
33
|
});
|
|
36
|
-
this.path =
|
|
37
|
-
this._gioFile = Gio.File.new_for_path(
|
|
34
|
+
this.path = pathStr;
|
|
35
|
+
this._gioFile = Gio.File.new_for_path(pathStr);
|
|
38
36
|
this._start = opts?.start ?? 0;
|
|
39
37
|
this._end = opts?.end ?? Infinity;
|
|
40
38
|
this._pos = this._start;
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
39
|
+
}
|
|
40
|
+
// Use _construct() for async file opening so the stream machinery defers
|
|
41
|
+
// _read() until the file is open. This avoids the fragile _pendingReadSize
|
|
42
|
+
// pattern and correctly handles backpressure via the constructed flag.
|
|
43
|
+
_construct(callback) {
|
|
44
|
+
this._gioFile.read_async(GLib.PRIORITY_DEFAULT, this._cancellable, (_source, asyncResult) => {
|
|
45
|
+
if (this.destroyed) {
|
|
46
|
+
callback();
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
try {
|
|
50
|
+
this._inputStream = this._gioFile.read_finish(asyncResult);
|
|
51
|
+
this.pending = false;
|
|
52
|
+
this.emit("open", 0);
|
|
53
|
+
this.emit("ready");
|
|
54
|
+
if (this._start > 0 && this._inputStream.can_seek()) {
|
|
55
|
+
this._inputStream.seek(this._start, GLib.SeekType.SET, null);
|
|
56
|
+
}
|
|
57
|
+
callback();
|
|
58
|
+
} catch (err) {
|
|
59
|
+
if (!this._cancellable.is_cancelled()) {
|
|
60
|
+
callback(err);
|
|
53
61
|
}
|
|
54
62
|
}
|
|
55
63
|
});
|
|
56
64
|
}
|
|
57
65
|
_read(size) {
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
return;
|
|
62
|
-
}
|
|
66
|
+
this._doRead(size);
|
|
67
|
+
}
|
|
68
|
+
_doRead(size) {
|
|
63
69
|
let toRead = size;
|
|
64
70
|
if (this._end !== Infinity) {
|
|
65
71
|
const remaining = this._end - this._pos + 1;
|
|
@@ -69,26 +75,30 @@ class ReadStream extends Readable {
|
|
|
69
75
|
}
|
|
70
76
|
toRead = Math.min(size, remaining);
|
|
71
77
|
}
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
+
const stream = this._inputStream;
|
|
79
|
+
stream.read_bytes_async(toRead, GLib.PRIORITY_DEFAULT, this._cancellable, (_source, asyncResult) => {
|
|
80
|
+
try {
|
|
81
|
+
const gbytes = stream.read_bytes_finish(asyncResult);
|
|
82
|
+
const data = gbytes.get_data();
|
|
83
|
+
if (!data || data.length === 0) {
|
|
84
|
+
this.push(null);
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
this.bytesRead += data.length;
|
|
88
|
+
this._pos += data.length;
|
|
89
|
+
this.push(Buffer.from(data));
|
|
90
|
+
} catch (err) {
|
|
91
|
+
if (!this._cancellable.is_cancelled()) {
|
|
92
|
+
this.destroy(err);
|
|
93
|
+
}
|
|
78
94
|
}
|
|
79
|
-
|
|
80
|
-
this._pos += data.length;
|
|
81
|
-
this.push(Buffer.from(data));
|
|
82
|
-
} catch (err) {
|
|
83
|
-
this.destroy(err);
|
|
84
|
-
}
|
|
95
|
+
});
|
|
85
96
|
}
|
|
86
97
|
_destroy(error, callback) {
|
|
98
|
+
this._cancellable.cancel();
|
|
87
99
|
if (this._inputStream) {
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
} catch {
|
|
91
|
-
}
|
|
100
|
+
this._inputStream.close_async(GLib.PRIORITY_DEFAULT, null, () => {
|
|
101
|
+
});
|
|
92
102
|
this._inputStream = null;
|
|
93
103
|
}
|
|
94
104
|
callback(error);
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { EventEmitter } from "node:events";
|
|
2
|
+
import { statSync } from "./sync.js";
|
|
3
|
+
function zeroedStat() {
|
|
4
|
+
return {
|
|
5
|
+
dev: 0,
|
|
6
|
+
ino: 0,
|
|
7
|
+
mode: 0,
|
|
8
|
+
nlink: 0,
|
|
9
|
+
uid: 0,
|
|
10
|
+
gid: 0,
|
|
11
|
+
rdev: 0,
|
|
12
|
+
size: 0,
|
|
13
|
+
blksize: 0,
|
|
14
|
+
blocks: 0,
|
|
15
|
+
atimeMs: 0,
|
|
16
|
+
mtimeMs: 0,
|
|
17
|
+
ctimeMs: 0,
|
|
18
|
+
birthtimeMs: 0,
|
|
19
|
+
atime: /* @__PURE__ */ new Date(0),
|
|
20
|
+
mtime: /* @__PURE__ */ new Date(0),
|
|
21
|
+
ctime: /* @__PURE__ */ new Date(0),
|
|
22
|
+
birthtime: /* @__PURE__ */ new Date(0),
|
|
23
|
+
isFile: () => false,
|
|
24
|
+
isDirectory: () => false,
|
|
25
|
+
isBlockDevice: () => false,
|
|
26
|
+
isCharacterDevice: () => false,
|
|
27
|
+
isSymbolicLink: () => false,
|
|
28
|
+
isFIFO: () => false,
|
|
29
|
+
isSocket: () => false
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
class StatWatcher extends EventEmitter {
|
|
33
|
+
_path;
|
|
34
|
+
_interval;
|
|
35
|
+
_timerId = null;
|
|
36
|
+
_prev;
|
|
37
|
+
_changeCount = 0;
|
|
38
|
+
constructor(path, interval) {
|
|
39
|
+
super();
|
|
40
|
+
this._path = path;
|
|
41
|
+
this._interval = interval;
|
|
42
|
+
this._prev = zeroedStat();
|
|
43
|
+
}
|
|
44
|
+
start() {
|
|
45
|
+
try {
|
|
46
|
+
this._prev = statSync(this._path);
|
|
47
|
+
} catch {
|
|
48
|
+
}
|
|
49
|
+
this._timerId = setInterval(() => {
|
|
50
|
+
let curr;
|
|
51
|
+
try {
|
|
52
|
+
curr = statSync(this._path);
|
|
53
|
+
} catch {
|
|
54
|
+
curr = zeroedStat();
|
|
55
|
+
}
|
|
56
|
+
const prev = this._prev;
|
|
57
|
+
if (curr.mtimeMs !== prev.mtimeMs || curr.size !== prev.size || curr.ino !== prev.ino) {
|
|
58
|
+
this._prev = curr;
|
|
59
|
+
this.emit("change", curr, prev);
|
|
60
|
+
}
|
|
61
|
+
}, this._interval);
|
|
62
|
+
}
|
|
63
|
+
stop() {
|
|
64
|
+
if (this._timerId !== null) {
|
|
65
|
+
clearInterval(this._timerId);
|
|
66
|
+
this._timerId = null;
|
|
67
|
+
}
|
|
68
|
+
this.emit("stop");
|
|
69
|
+
}
|
|
70
|
+
addChangeListener(listener) {
|
|
71
|
+
this._changeCount++;
|
|
72
|
+
this.on("change", listener);
|
|
73
|
+
}
|
|
74
|
+
removeChangeListener(listener) {
|
|
75
|
+
this._changeCount--;
|
|
76
|
+
this.removeListener("change", listener);
|
|
77
|
+
}
|
|
78
|
+
removeAllChangeListeners() {
|
|
79
|
+
this._changeCount = 0;
|
|
80
|
+
this.removeAllListeners("change");
|
|
81
|
+
}
|
|
82
|
+
get changeListenerCount() {
|
|
83
|
+
return this._changeCount;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
const statWatchers = /* @__PURE__ */ new Map();
|
|
87
|
+
function watchFile(filename, options, listener) {
|
|
88
|
+
if (typeof options === "function") {
|
|
89
|
+
listener = options;
|
|
90
|
+
options = {};
|
|
91
|
+
}
|
|
92
|
+
const interval = options.interval ?? 5007;
|
|
93
|
+
const resolved = filename.toString();
|
|
94
|
+
let watcher = statWatchers.get(resolved);
|
|
95
|
+
if (!watcher) {
|
|
96
|
+
watcher = new StatWatcher(resolved, interval);
|
|
97
|
+
watcher.start();
|
|
98
|
+
statWatchers.set(resolved, watcher);
|
|
99
|
+
}
|
|
100
|
+
if (listener) watcher.addChangeListener(listener);
|
|
101
|
+
return watcher;
|
|
102
|
+
}
|
|
103
|
+
function unwatchFile(filename, listener) {
|
|
104
|
+
const resolved = filename.toString();
|
|
105
|
+
const watcher = statWatchers.get(resolved);
|
|
106
|
+
if (!watcher) return;
|
|
107
|
+
if (listener) {
|
|
108
|
+
watcher.removeChangeListener(listener);
|
|
109
|
+
} else {
|
|
110
|
+
watcher.removeAllChangeListeners();
|
|
111
|
+
}
|
|
112
|
+
if (watcher.changeListenerCount === 0) {
|
|
113
|
+
watcher.stop();
|
|
114
|
+
statWatchers.delete(resolved);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
export {
|
|
118
|
+
StatWatcher,
|
|
119
|
+
unwatchFile,
|
|
120
|
+
watchFile
|
|
121
|
+
};
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import Gio from "@girs/gio-2.0";
|
|
2
|
+
import GLib from "@girs/glib-2.0";
|
|
3
|
+
import { normalizePath } from "./utils.js";
|
|
4
|
+
const FS_INFO_ATTRS = [
|
|
5
|
+
"filesystem::size",
|
|
6
|
+
"filesystem::free"
|
|
7
|
+
].join(",");
|
|
8
|
+
const BSIZE = 4096;
|
|
9
|
+
function buildStatFs(info) {
|
|
10
|
+
const totalBytes = Number(info.get_attribute_uint64("filesystem::size") ?? 0);
|
|
11
|
+
const freeBytes = Number(info.get_attribute_uint64("filesystem::free") ?? 0);
|
|
12
|
+
const blocks = Math.floor(totalBytes / BSIZE);
|
|
13
|
+
const bfree = Math.floor(freeBytes / BSIZE);
|
|
14
|
+
return { type: 0, bsize: BSIZE, blocks, bfree, bavail: bfree, files: 0, ffree: 0 };
|
|
15
|
+
}
|
|
16
|
+
function buildBigIntStatFs(info) {
|
|
17
|
+
const totalBytes = BigInt(info.get_attribute_uint64("filesystem::size") ?? 0);
|
|
18
|
+
const freeBytes = BigInt(info.get_attribute_uint64("filesystem::free") ?? 0);
|
|
19
|
+
const bsize = BigInt(BSIZE);
|
|
20
|
+
const blocks = totalBytes / bsize;
|
|
21
|
+
const bfree = freeBytes / bsize;
|
|
22
|
+
return { type: 0n, bsize, blocks, bfree, bavail: bfree, files: 0n, ffree: 0n };
|
|
23
|
+
}
|
|
24
|
+
function statfsSync(path, options) {
|
|
25
|
+
const file = Gio.File.new_for_path(normalizePath(path));
|
|
26
|
+
const info = file.query_filesystem_info(FS_INFO_ATTRS, null);
|
|
27
|
+
return options?.bigint === true ? buildBigIntStatFs(info) : buildStatFs(info);
|
|
28
|
+
}
|
|
29
|
+
function queryFsInfoAsync(path, useBigInt) {
|
|
30
|
+
return new Promise((resolve, reject) => {
|
|
31
|
+
const file = Gio.File.new_for_path(normalizePath(path));
|
|
32
|
+
file.query_filesystem_info_async(FS_INFO_ATTRS, GLib.PRIORITY_DEFAULT, null, (_s, res) => {
|
|
33
|
+
try {
|
|
34
|
+
const info = file.query_filesystem_info_finish(res);
|
|
35
|
+
resolve(useBigInt ? buildBigIntStatFs(info) : buildStatFs(info));
|
|
36
|
+
} catch (err) {
|
|
37
|
+
reject(err);
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
function statfs(path, optionsOrCb, callback) {
|
|
43
|
+
if (typeof optionsOrCb === "function") {
|
|
44
|
+
callback = optionsOrCb;
|
|
45
|
+
optionsOrCb = {};
|
|
46
|
+
}
|
|
47
|
+
const useBigInt = optionsOrCb?.bigint === true;
|
|
48
|
+
queryFsInfoAsync(path, useBigInt).then((result) => callback(null, result), (err) => callback(err, null));
|
|
49
|
+
}
|
|
50
|
+
async function statfsAsync(path, options) {
|
|
51
|
+
return queryFsInfoAsync(path, options?.bigint === true);
|
|
52
|
+
}
|
|
53
|
+
export {
|
|
54
|
+
statfs,
|
|
55
|
+
statfsAsync,
|
|
56
|
+
statfsSync
|
|
57
|
+
};
|
package/lib/esm/sync.js
CHANGED
|
@@ -9,29 +9,31 @@ import { FileHandle } from "./file-handle.js";
|
|
|
9
9
|
import { Dirent } from "./dirent.js";
|
|
10
10
|
import { Stats, BigIntStats, STAT_ATTRIBUTES } from "./stats.js";
|
|
11
11
|
import { createNodeError, isNotFoundError } from "./errors.js";
|
|
12
|
-
import { tempDirPath } from "./utils.js";
|
|
12
|
+
import { tempDirPath, normalizePath } from "./utils.js";
|
|
13
13
|
function statSync(path, options) {
|
|
14
|
+
const pathStr = normalizePath(path);
|
|
14
15
|
try {
|
|
15
|
-
const file = Gio.File.new_for_path(
|
|
16
|
+
const file = Gio.File.new_for_path(pathStr);
|
|
16
17
|
const info = file.query_info(STAT_ATTRIBUTES, Gio.FileQueryInfoFlags.NONE, null);
|
|
17
|
-
return options?.bigint ? new BigIntStats(info,
|
|
18
|
+
return options?.bigint ? new BigIntStats(info, pathStr) : new Stats(info, pathStr);
|
|
18
19
|
} catch (err) {
|
|
19
20
|
if (options?.throwIfNoEntry === false && isNotFoundError(err)) return void 0;
|
|
20
|
-
throw createNodeError(err, "stat",
|
|
21
|
+
throw createNodeError(err, "stat", pathStr);
|
|
21
22
|
}
|
|
22
23
|
}
|
|
23
24
|
function lstatSync(path, options) {
|
|
25
|
+
const pathStr = normalizePath(path);
|
|
24
26
|
try {
|
|
25
|
-
const file = Gio.File.new_for_path(
|
|
27
|
+
const file = Gio.File.new_for_path(pathStr);
|
|
26
28
|
const info = file.query_info(STAT_ATTRIBUTES, Gio.FileQueryInfoFlags.NOFOLLOW_SYMLINKS, null);
|
|
27
|
-
return options?.bigint ? new BigIntStats(info,
|
|
29
|
+
return options?.bigint ? new BigIntStats(info, pathStr) : new Stats(info, pathStr);
|
|
28
30
|
} catch (err) {
|
|
29
31
|
if (options?.throwIfNoEntry === false && isNotFoundError(err)) return void 0;
|
|
30
|
-
throw createNodeError(err, "lstat",
|
|
32
|
+
throw createNodeError(err, "lstat", pathStr);
|
|
31
33
|
}
|
|
32
34
|
}
|
|
33
35
|
function readdirSync(path, options) {
|
|
34
|
-
const pathStr = path
|
|
36
|
+
const pathStr = normalizePath(path);
|
|
35
37
|
const file = Gio.File.new_for_path(pathStr);
|
|
36
38
|
const enumerator = file.enumerate_children(
|
|
37
39
|
"standard::name,standard::type",
|
|
@@ -64,7 +66,8 @@ function readdirSync(path, options) {
|
|
|
64
66
|
}
|
|
65
67
|
const MAX_SYMLINK_DEPTH = 40;
|
|
66
68
|
function realpathSync(path) {
|
|
67
|
-
|
|
69
|
+
const pathStr = normalizePath(path);
|
|
70
|
+
let current = Gio.File.new_for_path(pathStr);
|
|
68
71
|
let depth = 0;
|
|
69
72
|
while (true) {
|
|
70
73
|
const info = current.query_info(
|
|
@@ -79,26 +82,29 @@ function realpathSync(path) {
|
|
|
79
82
|
const parent = current.get_parent();
|
|
80
83
|
current = parent ? parent.resolve_relative_path(target) : Gio.File.new_for_path(target);
|
|
81
84
|
if (++depth > MAX_SYMLINK_DEPTH) {
|
|
82
|
-
throw new Error(`ELOOP: too many levels of symbolic links, realpath '${
|
|
85
|
+
throw new Error(`ELOOP: too many levels of symbolic links, realpath '${pathStr}'`);
|
|
83
86
|
}
|
|
84
87
|
}
|
|
85
88
|
}
|
|
86
89
|
realpathSync.native = realpathSync;
|
|
87
90
|
function symlinkSync(target, path, _type) {
|
|
88
|
-
const
|
|
89
|
-
|
|
91
|
+
const pathStr = normalizePath(path);
|
|
92
|
+
const targetStr = normalizePath(target);
|
|
93
|
+
const file = Gio.File.new_for_path(pathStr);
|
|
94
|
+
file.make_symbolic_link(targetStr, null);
|
|
90
95
|
}
|
|
91
96
|
function readFileSync(path, options = { encoding: null, flag: "r" }) {
|
|
92
|
-
const
|
|
97
|
+
const pathStr = normalizePath(path);
|
|
98
|
+
const file = Gio.File.new_for_path(pathStr);
|
|
93
99
|
try {
|
|
94
100
|
const [ok, data] = file.load_contents(null);
|
|
95
101
|
if (!ok) {
|
|
96
|
-
throw createNodeError(new Error("failed to read file"), "read",
|
|
102
|
+
throw createNodeError(new Error("failed to read file"), "read", pathStr);
|
|
97
103
|
}
|
|
98
104
|
return encodeUint8Array(getEncodingFromOptions(options, "buffer"), data);
|
|
99
105
|
} catch (err) {
|
|
100
106
|
if (err.code && typeof err.code === "string") throw err;
|
|
101
|
-
throw createNodeError(err, "read",
|
|
107
|
+
throw createNodeError(err, "read", pathStr);
|
|
102
108
|
}
|
|
103
109
|
}
|
|
104
110
|
function mkdirSync(path, options) {
|
|
@@ -110,9 +116,7 @@ function mkdirSync(path, options) {
|
|
|
110
116
|
} else {
|
|
111
117
|
mode = options || 511;
|
|
112
118
|
}
|
|
113
|
-
|
|
114
|
-
path = path.toString();
|
|
115
|
-
}
|
|
119
|
+
path = normalizePath(path);
|
|
116
120
|
if (typeof mode === "string") {
|
|
117
121
|
throw new TypeError("mode as string is currently not supported!");
|
|
118
122
|
}
|
|
@@ -156,47 +160,53 @@ function mkdirSyncRecursive(pathStr, mode) {
|
|
|
156
160
|
}
|
|
157
161
|
}
|
|
158
162
|
function rmdirSync(path, _options) {
|
|
159
|
-
const
|
|
163
|
+
const pathStr = normalizePath(path);
|
|
164
|
+
const file = Gio.File.new_for_path(pathStr);
|
|
160
165
|
try {
|
|
161
166
|
const info = file.query_info("standard::type", Gio.FileQueryInfoFlags.NONE, null);
|
|
162
167
|
if (info.get_file_type() !== Gio.FileType.DIRECTORY) {
|
|
163
168
|
const err = Object.assign(new Error(), { code: 4 });
|
|
164
|
-
throw createNodeError(err, "rmdir",
|
|
169
|
+
throw createNodeError(err, "rmdir", pathStr);
|
|
165
170
|
}
|
|
166
171
|
const enumerator = file.enumerate_children("standard::name", Gio.FileQueryInfoFlags.NONE, null);
|
|
167
172
|
if (enumerator.next_file(null) !== null) {
|
|
168
173
|
const err = Object.assign(new Error(), { code: 5 });
|
|
169
|
-
throw createNodeError(err, "rmdir",
|
|
174
|
+
throw createNodeError(err, "rmdir", pathStr);
|
|
170
175
|
}
|
|
171
176
|
file.delete(null);
|
|
172
177
|
} catch (err) {
|
|
173
178
|
if (err.code && typeof err.code === "string") throw err;
|
|
174
|
-
throw createNodeError(err, "rmdir",
|
|
179
|
+
throw createNodeError(err, "rmdir", pathStr);
|
|
175
180
|
}
|
|
176
181
|
}
|
|
177
182
|
function unlinkSync(path) {
|
|
178
|
-
const
|
|
183
|
+
const pathStr = normalizePath(path);
|
|
184
|
+
const file = Gio.File.new_for_path(pathStr);
|
|
179
185
|
try {
|
|
180
186
|
file.delete(null);
|
|
181
187
|
} catch (err) {
|
|
182
|
-
throw createNodeError(err, "unlink",
|
|
188
|
+
throw createNodeError(err, "unlink", pathStr);
|
|
183
189
|
}
|
|
184
190
|
}
|
|
185
191
|
function writeFileSync(path, data) {
|
|
186
|
-
GLib.file_set_contents(path, data);
|
|
192
|
+
GLib.file_set_contents(normalizePath(path), data);
|
|
187
193
|
}
|
|
188
194
|
function renameSync(oldPath, newPath) {
|
|
189
|
-
const
|
|
190
|
-
const
|
|
195
|
+
const oldStr = normalizePath(oldPath);
|
|
196
|
+
const newStr = normalizePath(newPath);
|
|
197
|
+
const src = Gio.File.new_for_path(oldStr);
|
|
198
|
+
const dest = Gio.File.new_for_path(newStr);
|
|
191
199
|
try {
|
|
192
200
|
src.move(dest, Gio.FileCopyFlags.OVERWRITE, null, null);
|
|
193
201
|
} catch (err) {
|
|
194
|
-
throw createNodeError(err, "rename",
|
|
202
|
+
throw createNodeError(err, "rename", oldStr, newStr);
|
|
195
203
|
}
|
|
196
204
|
}
|
|
197
205
|
function copyFileSync(src, dest, mode) {
|
|
198
|
-
const
|
|
199
|
-
const
|
|
206
|
+
const srcStr = normalizePath(src);
|
|
207
|
+
const destStr = normalizePath(dest);
|
|
208
|
+
const srcFile = Gio.File.new_for_path(srcStr);
|
|
209
|
+
const destFile = Gio.File.new_for_path(destStr);
|
|
200
210
|
let flags = Gio.FileCopyFlags.NONE;
|
|
201
211
|
if (mode && (mode & 1) === 0) {
|
|
202
212
|
flags = Gio.FileCopyFlags.OVERWRITE;
|
|
@@ -206,32 +216,34 @@ function copyFileSync(src, dest, mode) {
|
|
|
206
216
|
try {
|
|
207
217
|
srcFile.copy(destFile, flags, null, null);
|
|
208
218
|
} catch (err) {
|
|
209
|
-
throw createNodeError(err, "copyfile",
|
|
219
|
+
throw createNodeError(err, "copyfile", srcStr, destStr);
|
|
210
220
|
}
|
|
211
221
|
}
|
|
212
222
|
function accessSync(path, mode) {
|
|
213
|
-
const
|
|
223
|
+
const pathStr = normalizePath(path);
|
|
224
|
+
const file = Gio.File.new_for_path(pathStr);
|
|
214
225
|
try {
|
|
215
226
|
const info = file.query_info("access::*", Gio.FileQueryInfoFlags.NONE, null);
|
|
216
227
|
if (mode !== void 0 && mode !== 0) {
|
|
217
|
-
const permErr = { code: 14, message: `permission denied, access '${
|
|
228
|
+
const permErr = { code: 14, message: `permission denied, access '${pathStr}'` };
|
|
218
229
|
if (mode & 4 && !info.get_attribute_boolean("access::can-read")) {
|
|
219
|
-
throw createNodeError(permErr, "access",
|
|
230
|
+
throw createNodeError(permErr, "access", pathStr);
|
|
220
231
|
}
|
|
221
232
|
if (mode & 2 && !info.get_attribute_boolean("access::can-write")) {
|
|
222
|
-
throw createNodeError(permErr, "access",
|
|
233
|
+
throw createNodeError(permErr, "access", pathStr);
|
|
223
234
|
}
|
|
224
235
|
if (mode & 1 && !info.get_attribute_boolean("access::can-execute")) {
|
|
225
|
-
throw createNodeError(permErr, "access",
|
|
236
|
+
throw createNodeError(permErr, "access", pathStr);
|
|
226
237
|
}
|
|
227
238
|
}
|
|
228
239
|
} catch (err) {
|
|
229
240
|
if (err.code && typeof err.code === "string") throw err;
|
|
230
|
-
throw createNodeError(err, "access",
|
|
241
|
+
throw createNodeError(err, "access", pathStr);
|
|
231
242
|
}
|
|
232
243
|
}
|
|
233
244
|
function appendFileSync(path, data, options) {
|
|
234
|
-
const
|
|
245
|
+
const pathStr = normalizePath(path);
|
|
246
|
+
const file = Gio.File.new_for_path(pathStr);
|
|
235
247
|
let bytes;
|
|
236
248
|
if (typeof data === "string") {
|
|
237
249
|
bytes = new TextEncoder().encode(data);
|
|
@@ -245,16 +257,17 @@ function appendFileSync(path, data, options) {
|
|
|
245
257
|
}
|
|
246
258
|
stream.close(null);
|
|
247
259
|
} catch (err) {
|
|
248
|
-
throw createNodeError(err, "appendfile",
|
|
260
|
+
throw createNodeError(err, "appendfile", pathStr);
|
|
249
261
|
}
|
|
250
262
|
}
|
|
251
263
|
function readlinkSync(path, options) {
|
|
252
|
-
const
|
|
264
|
+
const pathStr = normalizePath(path);
|
|
265
|
+
const file = Gio.File.new_for_path(pathStr);
|
|
253
266
|
try {
|
|
254
267
|
const info = file.query_info("standard::symlink-target", Gio.FileQueryInfoFlags.NOFOLLOW_SYMLINKS, null);
|
|
255
268
|
const target = info.get_symlink_target();
|
|
256
269
|
if (!target) {
|
|
257
|
-
throw Object.assign(new Error(`EINVAL: invalid argument, readlink '${
|
|
270
|
+
throw Object.assign(new Error(`EINVAL: invalid argument, readlink '${pathStr}'`), { code: "EINVAL", errno: -22, syscall: "readlink", path: pathStr });
|
|
258
271
|
}
|
|
259
272
|
const encoding = typeof options === "string" ? options : options?.encoding;
|
|
260
273
|
if (encoding === "buffer") {
|
|
@@ -263,17 +276,20 @@ function readlinkSync(path, options) {
|
|
|
263
276
|
return target;
|
|
264
277
|
} catch (err) {
|
|
265
278
|
if (typeof err.code === "string") throw err;
|
|
266
|
-
throw createNodeError(err, "readlink",
|
|
279
|
+
throw createNodeError(err, "readlink", pathStr);
|
|
267
280
|
}
|
|
268
281
|
}
|
|
269
282
|
function linkSync(existingPath, newPath) {
|
|
270
|
-
const
|
|
283
|
+
const existingStr = normalizePath(existingPath);
|
|
284
|
+
const newStr = normalizePath(newPath);
|
|
285
|
+
const result = GLib.spawn_command_line_sync(`ln ${existingStr} ${newStr}`);
|
|
271
286
|
if (!result[0]) {
|
|
272
|
-
throw Object.assign(new Error(`EPERM: operation not permitted, link '${
|
|
287
|
+
throw Object.assign(new Error(`EPERM: operation not permitted, link '${existingStr}' -> '${newStr}'`), { code: "EPERM", errno: -1, syscall: "link", path: existingStr, dest: newStr });
|
|
273
288
|
}
|
|
274
289
|
}
|
|
275
290
|
function truncateSync(path, len) {
|
|
276
|
-
const
|
|
291
|
+
const pathStr = normalizePath(path);
|
|
292
|
+
const file = Gio.File.new_for_path(pathStr);
|
|
277
293
|
try {
|
|
278
294
|
const stream = file.replace(null, false, Gio.FileCreateFlags.NONE, null);
|
|
279
295
|
if (len && len > 0) {
|
|
@@ -285,24 +301,26 @@ function truncateSync(path, len) {
|
|
|
285
301
|
}
|
|
286
302
|
stream.close(null);
|
|
287
303
|
} catch (err) {
|
|
288
|
-
throw createNodeError(err, "truncate",
|
|
304
|
+
throw createNodeError(err, "truncate", pathStr);
|
|
289
305
|
}
|
|
290
306
|
}
|
|
291
307
|
function chmodSync(path, mode) {
|
|
308
|
+
const pathStr = normalizePath(path);
|
|
292
309
|
const modeNum = typeof mode === "string" ? parseInt(mode, 8) : mode;
|
|
293
|
-
const result = GLib.spawn_command_line_sync(`chmod ${modeNum.toString(8)} ${
|
|
310
|
+
const result = GLib.spawn_command_line_sync(`chmod ${modeNum.toString(8)} ${pathStr}`);
|
|
294
311
|
if (!result[0]) {
|
|
295
|
-
throw Object.assign(new Error(`EPERM: operation not permitted, chmod '${
|
|
312
|
+
throw Object.assign(new Error(`EPERM: operation not permitted, chmod '${pathStr}'`), { code: "EPERM", errno: -1, syscall: "chmod", path: pathStr });
|
|
296
313
|
}
|
|
297
314
|
}
|
|
298
315
|
function chownSync(path, uid, gid) {
|
|
299
|
-
const
|
|
316
|
+
const pathStr = normalizePath(path);
|
|
317
|
+
const result = GLib.spawn_command_line_sync(`chown ${uid}:${gid} ${pathStr}`);
|
|
300
318
|
if (!result[0]) {
|
|
301
|
-
throw Object.assign(new Error(`EPERM: operation not permitted, chown '${
|
|
319
|
+
throw Object.assign(new Error(`EPERM: operation not permitted, chown '${pathStr}'`), { code: "EPERM", errno: -1, syscall: "chown", path: pathStr });
|
|
302
320
|
}
|
|
303
321
|
}
|
|
304
322
|
function watch(filename, options, listener) {
|
|
305
|
-
return new FSWatcher(filename, options, listener);
|
|
323
|
+
return new FSWatcher(normalizePath(filename), options, listener);
|
|
306
324
|
}
|
|
307
325
|
function openSync(path, flags, mode) {
|
|
308
326
|
return new FileHandle({ path, flags, mode });
|
|
@@ -317,7 +335,7 @@ function mkdtempSync(prefix, options) {
|
|
|
317
335
|
return decode(path, encoding);
|
|
318
336
|
}
|
|
319
337
|
function rmSync(path, options) {
|
|
320
|
-
const pathStr = path
|
|
338
|
+
const pathStr = normalizePath(path);
|
|
321
339
|
const file = Gio.File.new_for_path(pathStr);
|
|
322
340
|
const recursive = options?.recursive || false;
|
|
323
341
|
const force = options?.force || false;
|
package/lib/esm/utils.js
CHANGED
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
import { existsSync } from "./sync.js";
|
|
2
|
+
import { fileURLToPath, URL as NodeURL } from "node:url";
|
|
3
|
+
function normalizePath(path) {
|
|
4
|
+
if (path instanceof URL || path instanceof NodeURL) return fileURLToPath(path);
|
|
5
|
+
if (typeof path === "string") return path;
|
|
6
|
+
return path.toString();
|
|
7
|
+
}
|
|
2
8
|
const CHARS = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
|
3
9
|
function randomName() {
|
|
4
10
|
return [...Array(6)].map(
|
|
@@ -13,6 +19,7 @@ function tempDirPath(prefix) {
|
|
|
13
19
|
return path;
|
|
14
20
|
}
|
|
15
21
|
export {
|
|
22
|
+
normalizePath,
|
|
16
23
|
randomName,
|
|
17
24
|
tempDirPath
|
|
18
25
|
};
|