-
Notifications
You must be signed in to change notification settings - Fork 376
[php-wasm] Add support for rm command in sandboxed spawn handler
#3010
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: trunk
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -4,6 +4,10 @@ import type { PHPWorker } from './php-worker'; | |
| import type { Remote } from './comlink-sync'; | ||
| import { logger } from '@php-wasm/logger'; | ||
|
|
||
| function wait(ms: number): Promise<void> { | ||
| return new Promise((resolve) => setTimeout(resolve, ms)); | ||
| } | ||
|
|
||
| /** | ||
| * An isomorphic proc_open() handler that implements typical shell in TypeScript | ||
| * without relying on a server runtime. It can be used in the browser and Node.js | ||
|
|
@@ -81,7 +85,7 @@ export function sandboxedSpawnHandlerFactory( | |
| return; | ||
| } | ||
|
|
||
| if (!['php', 'ls', 'pwd'].includes(binaryName ?? '')) { | ||
| if (!['php', 'ls', 'pwd', 'rm'].includes(binaryName ?? '')) { | ||
| // 127 is the exit code "for command not found". | ||
| processApi.exit(127); | ||
| return; | ||
|
|
@@ -142,7 +146,7 @@ export function sandboxedSpawnHandlerFactory( | |
| // Technical limitation of subprocesses – we need to | ||
| // wait before exiting to give consumer a chance to read | ||
| // the output. | ||
| await new Promise((resolve) => setTimeout(resolve, 10)); | ||
| await wait(10); | ||
| processApi.exit(0); | ||
| break; | ||
| } | ||
|
|
@@ -151,10 +155,54 @@ export function sandboxedSpawnHandlerFactory( | |
| // Technical limitation of subprocesses – we need to | ||
| // wait before exiting to give consumer a chance to read | ||
| // the output. | ||
| await new Promise((resolve) => setTimeout(resolve, 10)); | ||
| await wait(10); | ||
| processApi.exit(0); | ||
| break; | ||
| } | ||
| case 'rm': { | ||
| const target = args[args.length - 1]; | ||
| const flags = args.slice(1, -1).join(' '); | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It may be more involved than that. Here's a few examples that would be really useful to cover with a unit test to make sure this command can handle them without failing: rm file1 file2 file3
rm -r -f directory
rm file1 -f file2 -r
# This one means "remove a file called "-rf"
rm -- -rf
# This one means "recursively remove a file or a directory called "-rf"
rm -rf -- -rf
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @adamziel @zaerl What do you think about using the yargs-parser npm package to parse the args instead of writing a custom parser from scratch?
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @Utsav-Ladani potentially! Let's give it a try and see what would this code look like with yargs-parser in place. It seems to be larger than we need, but still fairly small so perhaps? Note this package ( |
||
|
|
||
| if (args.length < 2 || target.startsWith('-')) { | ||
| processApi.stderr('usage: rm [-rf] file\n'); | ||
| // Technical limitation of subprocesses – we need to | ||
| // wait before exiting to give consumer a chance to read | ||
| // the output. | ||
| await wait(10); | ||
| processApi.exit(1); | ||
| break; | ||
| } | ||
|
|
||
| const isRecursive = flags.includes('r'); | ||
| const isForce = flags.includes('f'); | ||
|
|
||
| let errorMessage = ''; | ||
|
|
||
| if (await php.isDir(target)) { | ||
| if (isRecursive) { | ||
| await php.rmdir(target, { recursive: true }); | ||
| } else { | ||
| errorMessage = `rm: cannot remove '${target}': Is a directory\n`; | ||
| } | ||
| } else if (await php.isFile(target)) { | ||
| await php.unlink(target); | ||
| } | ||
| // Target doesn't exist and -f flag is not set | ||
| else if (!isForce) { | ||
| errorMessage = `rm: cannot remove '${target}': No such file or directory\n`; | ||
| } | ||
|
|
||
| if (errorMessage) { | ||
| processApi.stderr(errorMessage); | ||
| // Technical limitation of subprocesses – we need to | ||
| // wait before exiting to give consumer a chance to read | ||
| // the output. | ||
| await wait(10); | ||
| } | ||
|
|
||
| processApi.exit(errorMessage ? 1 : 0); | ||
| break; | ||
| } | ||
| } | ||
| } catch (e) { | ||
| // An exception here means the PHP runtime has crashed. | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.