@zenfs/core 1.2.9 → 1.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.
Files changed (57) hide show
  1. package/dist/backends/fetch.js +1 -1
  2. package/dist/backends/memory.d.ts +1 -2
  3. package/dist/backends/overlay.js +2 -3
  4. package/dist/backends/port/fs.d.ts +2 -15
  5. package/dist/backends/store/fs.d.ts +17 -28
  6. package/dist/backends/store/fs.js +169 -191
  7. package/dist/backends/store/simple.d.ts +20 -21
  8. package/dist/backends/store/simple.js +24 -24
  9. package/dist/backends/store/store.d.ts +22 -23
  10. package/dist/backends/store/store.js +6 -6
  11. package/dist/config.d.ts +8 -0
  12. package/dist/config.js +2 -1
  13. package/dist/devices.d.ts +2 -3
  14. package/dist/emulation/cache.d.ts +40 -31
  15. package/dist/emulation/cache.js +62 -53
  16. package/dist/emulation/index.d.ts +1 -1
  17. package/dist/emulation/index.js +1 -1
  18. package/dist/emulation/promises.js +18 -17
  19. package/dist/emulation/shared.d.ts +6 -0
  20. package/dist/emulation/shared.js +13 -1
  21. package/dist/emulation/sync.d.ts +1 -1
  22. package/dist/emulation/sync.js +16 -15
  23. package/dist/file.d.ts +3 -15
  24. package/dist/file.js +7 -19
  25. package/dist/inode.d.ts +4 -13
  26. package/dist/inode.js +22 -29
  27. package/dist/mixins/async.d.ts +15 -10
  28. package/dist/mixins/async.js +3 -1
  29. package/dist/stats.js +30 -5
  30. package/dist/utils.d.ts +5 -7
  31. package/dist/utils.js +11 -20
  32. package/package.json +1 -1
  33. package/src/backends/fetch.ts +1 -1
  34. package/src/backends/memory.ts +1 -2
  35. package/src/backends/overlay.ts +2 -2
  36. package/src/backends/store/fs.ts +187 -220
  37. package/src/backends/store/simple.ts +36 -37
  38. package/src/backends/store/store.ts +25 -26
  39. package/src/config.ts +11 -1
  40. package/src/devices.ts +2 -3
  41. package/src/emulation/cache.ts +68 -60
  42. package/src/emulation/index.ts +1 -1
  43. package/src/emulation/promises.ts +20 -19
  44. package/src/emulation/shared.ts +13 -1
  45. package/src/emulation/sync.ts +16 -15
  46. package/src/file.ts +9 -21
  47. package/src/inode.ts +10 -31
  48. package/src/mixins/async.ts +27 -24
  49. package/src/stats.ts +47 -5
  50. package/src/utils.ts +11 -23
  51. package/tests/fs/dir.test.ts +21 -31
  52. package/tests/fs/directory.test.ts +6 -4
  53. package/tests/fs/links.test.ts +9 -2
  54. package/tests/fs/permissions.test.ts +2 -2
  55. package/tests/fs/stat.test.ts +42 -0
  56. package/tests/fs/times.test.ts +28 -28
  57. package/tests/setup/cow+fetch.ts +4 -2
@@ -1,5 +1,6 @@
1
1
  import assert from 'node:assert';
2
2
  import { suite, test } from 'node:test';
3
+ import { credentials } from '../../dist/credentials.js';
3
4
  import { Stats } from '../../dist/stats.js';
4
5
  import { fs } from '../common.js';
5
6
 
@@ -34,6 +35,47 @@ suite('Stats', () => {
34
35
  fs.close(fd);
35
36
  });
36
37
 
38
+ test('hasAccess for non-root access', () => {
39
+ const newFile = 'new.txt';
40
+
41
+ fs.writeFileSync(newFile, 'hello', {
42
+ mode: 0o640, // allow group access
43
+ });
44
+
45
+ const prevCredentials = {
46
+ ...credentials,
47
+ };
48
+ const uid = 33;
49
+ const nonRootCredentials = {
50
+ uid,
51
+ gid: uid,
52
+ euid: uid,
53
+ egid: uid,
54
+ suid: uid,
55
+ sgid: uid,
56
+ };
57
+
58
+ fs.chownSync(newFile, 0, nonRootCredentials.gid); // creating with root-user so that non-root user can access
59
+
60
+ Object.assign(credentials, nonRootCredentials);
61
+ const stat = fs.statSync(newFile);
62
+
63
+ assert.equal(stat.gid, nonRootCredentials.gid);
64
+ assert.equal(stat.uid, 0);
65
+ assert.equal(stat.hasAccess(fs.constants.R_OK), true);
66
+ assert.equal(stat.hasAccess(fs.constants.W_OK), false);
67
+ assert.equal(stat.hasAccess(fs.constants.X_OK), false);
68
+ // changing group
69
+
70
+ Object.assign(credentials, { ...nonRootCredentials, gid: 44 });
71
+
72
+ assert.equal(stat.hasAccess(fs.constants.R_OK), false);
73
+ assert.equal(stat.hasAccess(fs.constants.W_OK), false);
74
+ assert.equal(stat.hasAccess(fs.constants.X_OK), false);
75
+
76
+ Object.assign(credentials, prevCredentials);
77
+ });
78
+
37
79
  test('stat file', async () => {
38
80
  const stats = await fs.promises.stat(existing_file);
39
81
  assert(!stats.isDirectory());
@@ -2,46 +2,46 @@ import assert from 'node:assert';
2
2
  import { suite, test } from 'node:test';
3
3
  import { wait } from 'utilium';
4
4
  import { ErrnoError } from '../../dist/error.js';
5
- import { _toUnixTimestamp } from '../../dist/utils.js';
5
+ import type { StatsLike } from '../../dist/stats.js';
6
6
  import { fs } from '../common.js';
7
7
 
8
- suite('times', () => {
9
- const path = 'x.txt';
8
+ const path = 'x.txt';
10
9
 
11
- function expect_assert(resource: string | number, atime: Date | number, mtime: Date | number) {
12
- const stats = typeof resource == 'string' ? fs.statSync(resource) : fs.fstatSync(resource);
13
- // check up to single-second precision since sub-second precision is OS and fs dependent
14
- assert(_toUnixTimestamp(atime) == _toUnixTimestamp(stats.atime));
15
- assert(_toUnixTimestamp(mtime) == _toUnixTimestamp(stats.mtime));
16
- }
10
+ /**
11
+ * Gets unix timestamps from stats
12
+ *
13
+ * @internal
14
+ */
15
+ export function unixTimestamps(stats: StatsLike<number>): Record<'atime' | 'mtime', number> {
16
+ return {
17
+ atime: Math.floor(stats.atimeMs),
18
+ mtime: Math.floor(stats.mtimeMs),
19
+ };
20
+ }
17
21
 
22
+ suite('times', () => {
18
23
  async function runTest(atime: Date | number, mtime: Date | number): Promise<void> {
24
+ const times = {
25
+ atime: typeof atime == 'number' ? Math.floor(atime) : atime.getTime(),
26
+ mtime: typeof mtime == 'number' ? Math.floor(mtime) : mtime.getTime(),
27
+ };
28
+
19
29
  await fs.promises.utimes(path, atime, mtime);
20
- expect_assert(path, atime, mtime);
30
+
31
+ assert.deepStrictEqual(unixTimestamps(await fs.promises.stat(path)), times);
21
32
 
22
33
  await fs.promises.utimes('foobarbaz', atime, mtime).catch((error: ErrnoError) => {
23
34
  assert(error instanceof ErrnoError);
24
35
  assert.strictEqual(error.code, 'ENOENT');
25
36
  });
26
37
 
27
- // don't close this fd
28
- const handle = await fs.promises.open(path, 'r');
38
+ await using handle = await fs.promises.open(path, 'r');
29
39
 
30
40
  await handle.utimes(atime, mtime);
31
- expect_assert(handle.fd, atime, mtime);
41
+ assert.deepStrictEqual(unixTimestamps(await handle.stat()), times);
32
42
 
33
43
  fs.utimesSync(path, atime, mtime);
34
- expect_assert(path, atime, mtime);
35
-
36
- // some systems don't have futimes
37
- // if there's an error, it be ENOSYS
38
- try {
39
- fs.futimesSync(handle.fd, atime, mtime);
40
- expect_assert(handle.fd, atime, mtime);
41
- } catch (error: any) {
42
- assert(error instanceof ErrnoError);
43
- assert.strictEqual(error.code, 'ENOSYS');
44
- }
44
+ assert.deepStrictEqual(unixTimestamps(fs.statSync(path)), times);
45
45
 
46
46
  try {
47
47
  fs.utimesSync('foobarbaz', atime, mtime);
@@ -59,11 +59,11 @@ suite('times', () => {
59
59
  }
60
60
 
61
61
  test('utimes works', async () => {
62
- await runTest(new Date('1982/09/10 13:37:00'), new Date('1982/09/10 13:37:00'));
63
- await runTest(new Date(), new Date());
64
- await runTest(123456.789, 123456.789);
62
+ await test('new Date(...)', () => runTest(new Date('1982/09/10 13:37:00'), new Date('1982/09/10 13:37:00')));
63
+ await test('new Date()', () => runTest(new Date(), new Date()));
64
+ await test('number', () => runTest(123456.789, 123456.789));
65
65
  const stats = fs.statSync(path);
66
- await runTest(stats.atime, stats.mtime);
66
+ await test('from stats', () => runTest(stats.atime, stats.mtime));
67
67
  });
68
68
 
69
69
  test('read changes atime', async () => {
@@ -33,11 +33,13 @@ server
33
33
  .listen(port)
34
34
  .unref();
35
35
 
36
+ const baseUrl = 'http://localhost:' + port;
37
+
36
38
  await configureSingle({
37
39
  backend: Overlay,
38
40
  readable: Fetch.create({
39
- baseUrl: `http://localhost:${port}/`,
40
- index: '.index.json',
41
+ baseUrl,
42
+ index: baseUrl + '/.index.json',
41
43
  }),
42
44
  writable: InMemory.create({ name: 'cow' }),
43
45
  });