Err. ENOENT when renaming a file in node.js - node.js

I'm trying to upload a file in my node/express app, but everytime I've got the ENOENT error when renaming the file. My code is that:
var tmp_path = req.files.file.path;
fs.rename(tmp_path, target_path, function (err) {
if(err) throw err;
...
});
where target_path will be the destination path. If I do:
console.log('exists ' + fs.existsSync(tmp_path));
then my server logs:
exists true
Also, listing the contents of tmp directory shows that the file is there. What's the problem?

FS methods like fs.rename which create, move or rename files expect that any directories in the path already exist. When they do not, you'll get an ENOENT. Since very often what you mean is "make this file -- and any directories in the path I specify for it" you may want to consider using an NPM library that abstracts access to fs with methods that take care of such things.
There are quite a few options. For example fs-extra is one of the better-tested libraries. Using fs-extra you can use ensureDir in that operation to make the directory structure first if it does not yet exist.

Related

error when moving a file uploaded with multer: resource busy or locked

I have a node+express app that receives files and uploads them to a folder, for which I use multer.
In it's current form, my server.js has:
var multer = require('multer');
app.use(multer({ dest: './uploads/' }).single('files'));
which sends all files to the /uploads directory, with a randomly generated name to avoid conflicts.
That all works fine, however, I need to modify it so that it creates a folder with the randomly generated name and places the file inside (so if a file is randomly named "asdf", then it should end up as uploads/asdf/asdf.
Since the node way of moving files is using fs.rename, I included the following code in my upload route:
fs.rename('uploads/' + newFile.uploadname, 'uploads/' + newFile.uploadname + '/' + newFile.uploadname, function(err) {
if (err) throw err
console.log('Successfully renamed - AKA moved!')
})
(newFile.uploadname should be, and actually is, the name generated by multer).
When that code executes, I get this output:
D:\NodeApp\app\routes\private\upload.js:35
if (err) throw err
^
Error: EBUSY: resource busy or locked, rename 'D:\NodeApp\uploads\b9998bcbb10326c05f305a6a5a0adb9a' -> 'D:\NodeApp\up
loads\b9998bcbb10326c05f305a6a5a0adb9a\b9998bcbb10326c05f305a6a5a0adb9a'
at Error (native)
The file is uploaded properly but not moved, nor the directory created.
What is happening?
The problem was that I was trying to move a file named 'asdf' to a folder called also 'asdf'... Obviously (in restrospect) that folder can't be created because the name is already being used by the file that will be copied. Moving the file to a temporal folder first and then creating the folder solved the issue.

Access Root directory using Node

Is there any way to access the Linux root ('/') directory through node? Right now, I have something like this:
multipart = require('connect-multiparty')
app.use(multipart({
uploadDir: config.tmp
}));
...
var file = req.files.file;
fs.renameSync(file.path, ".", function(err) {
if(err) console.error(err.stack);
})
but the problem is that file.path is refering to a folder inside the Linux root rather than the project's root.
The most literal answer to your question
Is there any way to access the Linux root ('/') directory through node?
Is yes, by using /. Node.js shouldn't be giving any special treatment to it. Root is a directory just like any other.
On to your code...
fs.renameSync takes a source first and destination second.
You are renaming a file to ., which represents the current working directory. I'm not even sure if you can rename something to .. I would extract the filename from the path, then set the destination to the root directory plus that file name.
How to access the root directory, which as you said, is /, well, use /.
By the way, why are you using renameSync with a callback and nothing after it? According to the documentation, this is not valid. It's either async with a callback, or sync without a callback. So your callback is probably not firing.
var file = req.files.file;
fs.rename(file.path, '/' + path.basename(file.path), function(err) {
if(err) console.error(err.stack);
});
By the way, I have to advocate strongly against an application writing files to the Linux root directory, for a number of reasons:
Requires root privileges, which opens a can of worms.
Nobody would ever think to look there
The slightest bug could cause irrevocable damage. What if the desired file name is "etc" or "boot"?
There are a million better locations for storing files uploaded from a web server.

nodeJS, moving a file to a new folder

I'm trying to move an existing file into a new folder that doesn't exist. I tried:
var source = fs.createReadStream(file.thumbnail.path);
var dest = fs.createWriteStream('./public/uploads/'+ user._id + '/' + file.myfail.name);
source.pipe(dest);
However, I keep getting this error Error: ENOENT, open './public/uploads/553283d3216c3895055612dd/18f1b232024ac9d7a5d398dc9291e160.jpg'
I also tried using __dirname but it doesn't seem to help.
I'm pretty sure it's a non-existant folder issue, but I'm not sure how to fix it.
PS: after checking if the folder doesn't exist, how do I create it?
thanks
The ENOENT error is because the file or folder does not exist.
The only way to get around this problem is to open a file that does exist. Perhaps the user's folder does not exist before you try this operation? Check to see if the folder exists.
Another thing to note is that Node.js has a path module that provides a lot of useful filepath tools.
var path = require( 'path' )
var destination = path.join( __dirname, 'public/uploads', user._id, file.myfile.name )
You'll want to check if the sub-directory "./public/uploads/" + user._id exists.
If it doesn't exist create the directory before attempting to write out to a directory that doesn't exist.

ENOENT error when using fs.writeFile

Trying to write to a file using fs.writeFile into a sibling directory. This works fine when using Sitemap.xml into the same directory, but not with the relative path. The public directory exists and it gives the same error whether or not Sitemap.xml exists.
Relevant dir structure:
/public
Sitemap.xml
app files
/create-sitemap
index.js - file containing code below
app.js
fs.write('../public/Sitemap.xml', data.toString(), function(err) {
if (err) throw err;
console.log("Wrote sitemap to XML");
});
Toms-MacBook-Pro:moviehunter tomchambers$ node create-sitemap/index.js
/Users/tomchambers/projects/project/create-sitemap/index.js:88
if (err) throw err;
^
Error: ENOENT, open '../public/Sitemap.xml'
When you use relative paths in node, they're related to the node process. So, if you run your script like node create-sitemap/index.js from the /Users/tomchambers/projects/project/ directory, it'll look for the /Users/tomchambers/projects/public/Sitemap.xml file, which doesn't exist.
In your case, you could use the __dirname global variable, that returns, as the docs say:
The name of the directory that the currently executing script resides in.
So your code should looks like this:
var path = require('path');
fs.write(path.join(__dirname, '../public/Sitemap.xml'), data.toString(), function(err) {
if (err) throw err;
console.log("Wrote sitemap to XML");
});
For me the problem was that the given filename contained unallowed characters on Windows.
Specifically, I tried adding a timestamp to the name e.g. 10:23:11 and the : were not allowed which caused this error.

Node.js: Check if file is an symbolic link when iterating over directory with 'fs'

Supervisor is a package for Node.js that monitors files in your app directory for modifications and reloads the app when a modification occurs.
This script interprets symbolic links as regular files and logs out a warning. I would like to fork Supervisor so that either this can be fixed entirely or that a more descriptive warning is produced.
How can I use the File System module of Node.js to determine if a given file is really an symbolic link?
You can use fs.lstat and then call statis.isSymbolicLink() on the fs.Stats object that's passed into your lstat callback.
fs.lstat('myfilename', function(err, stats) {
console.log(stats.isSymbolicLink());
});
Seems like you can use isSymbolicLink()
const files = fs.readdirSync(dir, {encoding: 'utf8', withFileTypes: true});
files.forEach((file) => {
if (file.isSymbolicLink()) {
console.log('found symlink!');
}
}

Resources