TiddlyWiki5 icon indicating copy to clipboard operation
TiddlyWiki5 copied to clipboard

[BUG] Rendering to CON on Windows causes a crash

Open kravlost opened this issue 2 years ago • 2 comments

Describe the bug

The filename "CON" on Windows causes data written to the file to appear in the console. CON is a reserved filename and it cannot be used with a path. If I run:

tiddlywiki "WikiName" --render "." "CON" "text/plain" '$:/core/templates/exporters/JsonFile' "exportFilter" "[!is[system]!tag[image]]"

to get the TW rendered to the console, I get an error:

node:internal/fs/utils:347
    throw err;
    ^

Error: EINVAL: invalid argument, open '.........\output\CON'
    at Object.openSync (node:fs:599:3)
    at Object.writeFileSync (node:fs:2221:35)
    at $:/core/modules/commands/render.js:58:7
    at $tw.utils.each ($:/boot/boot.js:146:12)
    at Command.execute ($:/core/modules/commands/render.js:47:13)
    at Commander.executeNextCommand ($:/core/modules/commander.js:107:14)
    at Commander.execute ($:/core/modules/commander.js:64:7)
    at exports.startup ($:/core/modules/startup/commands.js:34:12)
    at $tw.boot.executeNextStartupTask ($:/boot/boot.js:2542:10)
    at $tw.boot.executeNextStartupTask ($:/boot/boot.js:2540:21) {
  errno: -4071,
  syscall: 'open',
  code: 'EINVAL',
  path: '.........................\\output\\CON'
}

Node.js v18.6.0

It looks like TW is adding the path to the CON filename, which is illegal under Windows. If I add --output "" to set the path to nothing, I get this error:

> tiddlywiki --output "" "WikiName" --render "." "CON" "text/plain" '$:/core/templates/exporters/JsonFile' "exportFilter" "[!is[system]!tag[image]]"
node:internal/fs/utils:347
    throw err;
    ^

Error: EINVAL: invalid argument, open '.......\WikiName\CON'
    at Object.openSync (node:fs:599:3)
    at Object.writeFileSync (node:fs:2221:35)
    at $:/core/modules/commands/render.js:58:7
    at $tw.utils.each ($:/boot/boot.js:146:12)
    at Command.execute ($:/core/modules/commands/render.js:47:13)
    at Commander.executeNextCommand ($:/core/modules/commander.js:107:14)
    at Commander.executeNextCommand ($:/core/modules/commander.js:111:12)
    at Commander.execute ($:/core/modules/commander.js:64:7)
    at exports.startup ($:/core/modules/startup/commands.js:34:12)
    at $tw.boot.executeNextStartupTask ($:/boot/boot.js:2542:10) {
  errno: -4071,
  syscall: 'open',
  code: 'EINVAL',
  path: '......\\WikiName\\CON'
}

Node.js v18.6.0

Admittedly the CON filename is a rare case. Is there another way of rendering to stdout rather than a file?

Expected behavior

The JSON data should be rendered to the console.

To Reproduce

  1. On a NodeJS TW, run
tiddlywiki "WikiName" --render "." "CON" "text/plain" '$:/core/templates/exporters/JsonFile' "exportFilter" "[!is[system]!tag[image]]"

Screenshots

No response

TiddlyWiki Configuration

  • Version v5.2.2
  • Saving mechanism Node.js
  • Plugins installed: extended-button-widgets, Relink, Todolist

Desktop (please complete the following information):

  • OS: Windows 10
  • Browser Edge
  • Version 103

Additional context

No response

kravlost avatar Jul 29 '22 19:07 kravlost

Thank you @kravlost, that's an interesting problem!

My first thought was that I could test it on my Mac using /dev/tty:

tiddlywiki editions/tw5.com --verbose --render '.' '/dev/tty' 'text/plain' '$:/core/templates/exporters/JsonFile' 'exportFilter' 'HelloThere'

But it turns out that that works as expected; it seems that on macOS/Linux the Node.js function path.resolve() has special knowledge of /dev/tty, and discards the other path elements.

I used Google Code search to find quite a few projects that have ended up with a hardcoded list of special filenames in Windows:

https://github.com/tilt-dev/go-get/blob/90f57eece58af5259762820bbe3f091ec8c23bc9/path.go#L169-L191

This comment clarifies that these are actually prefixes:

The following special “files”, which access devices, exist in all directories, case-insensitively, and with all possible endings after a period or colon, except in pathnames that start with \?: "NUL", "CON", "PRN", "AUX", "COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8", "COM9", "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9"

https://cs.github.com/MicahElliott/vrod/blob/d0f598051530005c0dd868dea1900f803c82086b/racket/doc/paths.txt#L762

I found a reasonable looking regexp to match these names:

https://cs.github.com/seiya-npm/sei-helper/blob/fe688d20798546398e3bfcc2d28f2c8f2428eb5c/src/main.js#L140

However, it doesn't seem to account for CLOCK$ which appears in some lists:

https://cs.github.com/seiya-npm/sei-helper/blob/fe688d20798546398e3bfcc2d28f2c8f2428eb5c/src/main.js#L140

Another point to note about the quote above is that "CON" exists in every directory; therefore I'd have expected it not to matter that we've resolved it into the current working directory.

All very frustrating; this feels like something that Node.js should be handling automatically.

Anyhow, I guess one possible fix would be to make our own custom version of path.resolve that when on Windows

One small point is that your example here is incorrect:

tiddlywiki --output "" "WikiName" --render "." "CON" "text/plain" '$:/core/templates/exporters/JsonFile' "exportFilter" "[!is[system]!tag[image]]"

The --output command should go after the path to the wiki:

tiddlywiki "WikiName" --output "" --render "." "CON" "text/plain" '$:/core/templates/exporters/JsonFile' "exportFilter" "[!is[system]!tag[image]]"

Jermolene avatar Jul 30 '22 09:07 Jermolene

Thanks for the analysis, @Jermolene . I've noticed that if I use a forbidden character in a tiddler title, then it is sanitised with replacement underscores before being used as a filename, so something is handling it!

One small point is that your example here is incorrect:

It is indeed, sorry about that.

kravlost avatar Jul 30 '22 19:07 kravlost