FS won't create file - node.js

I want to create a simple console application that would compare two files based on their filename and output the result into a new file.
My problem is that NodeJS refuses to create a new file if it doesn't exist, and acts like it doesn't exist even if I create it manually.
compare = (data) -> # data is being read from process.stdin
fname = "#{data}_compare.txt"
stdout.write "Attempting to compare #{data}" # stdout = process.stdout
fs.writeFileSync fname, 'A test.'
NodeJS returns Error: ENOENT, no such file or directory in both cases (when I want it to create the file, as well as when the file already exists).
I want the file to be created in the same folder from where the application is run, so path shouldn't be an issue at all (and indeed is correct in the error message).
I tried to specify {flags: 'w'} too, but as far as I know, that's the default value anyways, so it changed noting.
I'm running on Windows 10, tried running command prompt under administrator too, still nothing. Any idea what could be causing this?

The data variable is read from stdin and therefore contains a newline at the end. This is probably what's causing the non-descriptive ENOENT error.
You can remove the newline (and any other whitespace that user might have accidentally entered) with data = data.trim()
This would be better than the substring solution since the newline is 2 characters only on Windows and 1 character elsewhere.

Make sure the path exists (not necessarily the file itself, but the folder structure), and that the process user has write permissions.

An ENOENT error tells you that a component of the specified pathname does not exist -- no entity (file or directory) could be found by the given path.
Make sure you are putting the 'dot':
'./path/to/file'

Related

what happens when calling ```touch .``` in linux?

this is a very specific question
I'm mainly interested in the open() system calls the happen when running touch ..
So I ran strace touch . and saw that opennat() is called three times.
but I'm not really understanding whats going on; as touch . does not print anything in the console and does not create a new file named "." since "." is a pointer to the current folder and can be seen by running ls -a so nothing is created since that name is already in use.
this is my assumption:
open() is called to check if the specified file name already exits, if a file descriptor is returned this means that the name is already in use and the operation is canceled.
please correct me if I'm wrong.
GNU touch prefers to use a file descriptor when touching files, since it's possible to write touch - > foo and expect the file foo to be touched. As a result, it always tries to open the specified path as a writable file, and if that's possible, it then uses that file descriptor to update the file timestamp.
In this case, it's not possible to open . for writing, so openat returns EISDIR. touch notices that it's a directory, so its call to its internal fdutimensat function gets an invalid file descriptor and falls back to using utimensat instead of futimens.
It isn't the case that the openat call is used to check that the file exists, but instead that using a file descriptor for many operations means that you don't have to deal with path resolution multiple times or handle symlinks, since all of those are resolved when the file descriptor is opened. This is why many long-lived programs choose to open a file descriptor to their current working directory, then change directories, and then use the file descriptor with fchdir to change back. Any pchanges to permissions after the program starts are not a problem.

How do I get the filename of an open std::fs::File in Rust?

I have an open std::fs::File, and I want to get it's filename, e.g. as a PathBuf. How do I do that?
The simple solution would be to just save the path used in the call to File::open. Unfortunately, this does not work for me. I am trying to write a program that reads log files, and the program that writes the logs keep changing the filenames as part of it's log rotation. So the file may very well have been renamed since it was opened. This is on Linux, so renaming open files is possible.
How do I get around this issue, and get the current filename of an open file?
On a typical Unix filesystem, a file may have multiple filenames at once, or even none at all. The file metadata is stored in an inode, which has a unique inode number, and this inode number can be linked from any number of directory entries. However, there are no reverse links from the inode back to the directory entries.
Given an open File object in Rust, you can get the inode number using the ino() method. If you know the directory the log file is in, you can use std::fs::read_dir() to iterate over all entries in that directory, and each entry will also have an ino() method, so you can find the one(s) matching your open file object. Of course this approach is subject to race conditions – the directory entry may already be gone again once you try to do anything with it.
On linux, files handles held by the current process can be found under /proc/self/fd. These look and act like symlinks to the original files (though I think they may technically be something else - perhaps someone who knows more can chip in).
You can therefore recover the (possibly changed) file name by constructing the correct path in /proc/self/fd using your file descriptor, and then following the symlink back to the filesystem.
This snippet shows the steps:
use std::fs::read_link;
use std::os::unix::io::AsRawFd;
use std::path::PathBuf;
// if f is your std::fs::File
// first construct the path to the symlink under /proc
let path_in_proc = PathBuf::from(format!("/proc/self/fd/{}", f.as_raw_fd()));
// ...and follow it back to the original file
let new_file_name = read_link(path_in_proc).unwrap();

Flag to Create Missing Directories During fs.promises.writeFile

As I review these file system flags, I'm I correct in concluding that there is no flag you can pass to fs.promises.writeFile that will automatically create all missing directories leading up to a filename? If not, which flag does this?
I don't like solutions that check for the existence of the folders first before attempting writeFile, because after the folders are created that check happens every time you write to a file in that folder.
In my program, after the folders are created once, it should always be there, so it seems more efficient to only create the folders if there is an exception. However, I'm hoping there is a flag that avoids all this micro-management.
If a flag for auto-creating the folders doesn't exist for writeFile, then I'd like to attempt writeFile first, and then (only if there is an exception) create the folders recursively.
fs.promises.writeFile() does not automatically create the directory structure for you. That must exist first.
If you want to automatically create the path because you received an error indicative of a path problem, you can use fs.promises.mkdir() and pass the recursive flag.
And you could, of course, create your own wrapper function that calls fs.promises.writeFile() and if it gets whatever error you get when the path doesn't exist (you'd have to test to see exactly what that error is), then call fs.promises.mkdir() and then repeat the fs.promises.writeFile(). It could all be wrapped in your own utility function.

ENOENT no such file on Express Endpoint for readFileSync

I've been going slightly crazy trying to figure this out. I have some certs that I need to pass through to an authentication client from my api; however, the application continues to throw ENOENT exceptions even though the file clearly exists within the same directory (I've fiddled with this to make sure). I'm using readFileSync, effectively doing the following:
key: fs.readFileSync('./privateKey.pem'),
Strangely, if I run this on a standalone Node server not as a part of an api, the file is able to be found without a problem. Is there some consideration I'm not aware of when trying to use readFileSync in such a scenario?
Thanks!
In node you need to be very careful with relative file paths. The only place where I'd ever really use them is in require('./_____') statements, where ./ to mean "relative to this file". However, require is kind of a special case because it is a function that node automatically creates per-file, so it knows the path of the current file.
In general, standard functions have no way of knowing the directory containing the script that happened to call a function, so in almost all cases, ./ means relative to the current working directory (the directory you were in when you ran node <scriptname>.js). The only time that is not the case is if your script or a module you use explicitly calls process.chdir to set the working directory to something else. The correct way to reference files relative to the current script file is to explicitly use an absolute path by using __dirname + '/file.js'.

Escape spaces in File Path

I am wondering how I can programmatically add \ in front of spaces that appear in file paths. I am using fs.readdir to get the contents of directories and if I don't escape the spaces out of the path then I get an ENOENT error because unescaped paths are invalid in UNIX. I'd like get below result :
/path/with\ spaces/in/them/
However, I am running into a problem with a REGEX in the NODE REPL. When I do :
var path = '/path/with spaces/in/them/';
var escapedPath = path.replace(/(\s)/, "\\ ");
I get as result :
'/path/with\\ spaces/in/them/'
When I try to run this same code inside of the Chrome console I get :
"/path/with\ spaces/in/them/"
Which is the desired effect.
I am not sure if I am missing something or if this is a bug. I am confused because Node runs on the same Javascript engine as Chrome so I would think that these expressions would be interpreted the same.
Please let me know if anyone knows a way to do get around this. Maybe I am missing something. I just need to be able to escape the paths before passing them into fs.readdir so that I can avoid these errors.
Thanks!
try either this
var path = "'file:///Users/kevin/folder with space'";
or this
var path = "\"file:///Users/kevin/folder with space\"";
fs.readdir doesn't require you to escape paths. I was able to recursively pass fs.readdir output directories back into fs.readdir without any issues.
The issue above with the REGEX was only occuring in the Node REPL. Once I tested the above code inside of a file I was able to run it through Node and get the same output I saw in the Chrome console.
I ended up finding a bug in my code that was a little hard to track down. I first thought that it came from not escaping the path I was sending into fs.readdir but it was actually an issue where I was fs.stat the output of fs.readdir and then checking if the output was a file or a directory and treating it accordingly.
It turns out that a few results from the stat were neither Files or Directories and my function didn't have any way to deal with this so it just returned. Since I had no handlers for this my node program just stopped abrubtly. All I had to do was add an extra else condition to catch the non-file/directories cases (which I don't care about anyway).
Now its working fine!

Resources