Skip to content

Commit b428d85

Browse files
committed
Fix symlink mounting and copying
1 parent 652563a commit b428d85

File tree

4 files changed

+74
-31
lines changed

4 files changed

+74
-31
lines changed

packages/php-wasm/node/src/lib/node-fs-mount.ts

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
1-
import type { ErrnoError, MountHandler } from '@php-wasm/universal';
1+
import {
2+
FSHelpers,
3+
type ErrnoError,
4+
type MountHandler,
5+
} from '@php-wasm/universal';
26
import { statSync } from 'fs';
3-
import { dirname } from 'path';
7+
import { basename } from 'path';
48

59
export function createNodeFsMountHandler(localPath: string): MountHandler {
610
return async function (php, FS, vfsMountPoint) {
@@ -27,9 +31,16 @@ export function createNodeFsMountHandler(localPath: string): MountHandler {
2731
if (err.errno !== 44) {
2832
throw e;
2933
}
30-
if (statSync(localPath).isFile()) {
31-
unlinkPath = vfsMountPoint;
34+
if (statSync(localPath).isSymbolicLink()) {
35+
(FS as any).createNode(
36+
FS.lookupPath(vfsMountPoint, { parent: true }).node,
37+
basename(localPath),
38+
110000
39+
);
40+
lookup = FS.lookupPath(vfsMountPoint);
41+
} else if (statSync(localPath).isFile()) {
3242
FS.writeFile(vfsMountPoint, '');
43+
unlinkPath = vfsMountPoint;
3344
} else if (statSync(localPath).isDirectory()) {
3445
FS.mkdirTree(vfsMountPoint);
3546
unlinkPath = vfsMountPoint;

packages/php-wasm/node/src/test/mounting.spec.ts

Lines changed: 0 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -79,31 +79,6 @@ describe('Mounting', () => {
7979
}
8080
});
8181

82-
it('Should mount a symlink', async () => {
83-
const symlinkPath = path.join(__dirname, 'test-data', 'symlink.txt');
84-
const symlinkTarget = path.join(
85-
__dirname,
86-
'test-data',
87-
'long-post-body.txt'
88-
);
89-
const vfsMountPoint = '/symlink.txt';
90-
try {
91-
fs.symlinkSync(symlinkTarget, symlinkPath, 'file');
92-
93-
await php.mount(
94-
vfsMountPoint,
95-
createNodeFsMountHandler(symlinkPath)
96-
);
97-
98-
expect(php.isFile(vfsMountPoint)).toBe(true);
99-
expect(php.readFileAsText(vfsMountPoint)).toEqual(
100-
fs.readFileSync(symlinkTarget, 'utf8')
101-
);
102-
} finally {
103-
fs.unlinkSync(symlinkPath);
104-
}
105-
});
106-
10782
it('Should unmount a file and remove created node from VFS', async () => {
10883
const testFilePath = path.join(
10984
__dirname,

packages/php-wasm/node/src/test/symlinks.spec.ts

Lines changed: 57 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
import { loadNodeRuntime } from '..';
2-
import { PHP, setPhpIniEntries } from '@php-wasm/universal';
2+
import {
3+
__private__dont__use,
4+
FSHelpers,
5+
PHP,
6+
setPhpIniEntries,
7+
} from '@php-wasm/universal';
38
import fs from 'fs';
49
import path from 'path';
510
import { createNodeFsMountHandler } from '../lib/node-fs-mount';
@@ -60,7 +65,6 @@ testSymlinks.forEach(({ name, sourcePath, symlinkPath }) => {
6065
);
6166
}
6267

63-
await php.mkdir('/folder-with-symlinks');
6468
await php.mount(
6569
'/folder-with-symlinks',
6670
createNodeFsMountHandler(
@@ -350,5 +354,56 @@ testSymlinks.forEach(({ name, sourcePath, symlinkPath }) => {
350354
}
351355
});
352356
});
357+
358+
describe('Test symlink file system operations', () => {
359+
const symlinkPath = path.join(
360+
__dirname,
361+
'test-data',
362+
'symlink.txt'
363+
);
364+
const symlinkTarget = path.join(
365+
__dirname,
366+
'test-data',
367+
'long-post-body.txt'
368+
);
369+
const vfsMountPoint = '/symlink.txt';
370+
beforeEach(async () => {
371+
fs.symlinkSync(symlinkTarget, symlinkPath, 'file');
372+
373+
await php.mount(
374+
vfsMountPoint,
375+
createNodeFsMountHandler(symlinkPath)
376+
);
377+
});
378+
afterEach(async () => {
379+
fs.unlinkSync(symlinkPath);
380+
});
381+
382+
it('Should mount a symlink', async () => {
383+
expect(php.isFile(vfsMountPoint)).toBe(true);
384+
expect(php.readFileAsText(vfsMountPoint)).toEqual(
385+
fs.readFileSync(symlinkTarget, 'utf8')
386+
);
387+
});
388+
it('Should be recognized as a symlink', async () => {
389+
expect(php.fileExists(vfsMountPoint)).toBe(true);
390+
expect(php.isSymlink(vfsMountPoint)).toBe(true);
391+
});
392+
it('Should copy a symlink', async () => {
393+
const newVfsMountPoint = '/symlink-copy.txt';
394+
FSHelpers.copyRecursive(
395+
php[__private__dont__use].FS,
396+
vfsMountPoint,
397+
newVfsMountPoint
398+
);
399+
expect(php.fileExists(vfsMountPoint)).toBe(true);
400+
expect(php.isSymlink(vfsMountPoint)).toBe(true);
401+
expect(php.fileExists(newVfsMountPoint)).toBe(true);
402+
expect(php.isSymlink(newVfsMountPoint)).toBe(true);
403+
expect(php.readlink(newVfsMountPoint)).toBe(
404+
php.readlink(vfsMountPoint)
405+
);
406+
});
407+
});
353408
});
354409
});

packages/php-wasm/universal/src/lib/fs-helpers.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,8 @@ export class FSHelpers {
301301
joinPaths(toPath, filename)
302302
);
303303
}
304+
} else if (FS.isLink(fromNode.mode)) {
305+
FS.symlink(FS.readlink(fromPath), toPath);
304306
} else {
305307
FS.writeFile(toPath, FS.readFile(fromPath));
306308
}

0 commit comments

Comments
 (0)