5

I have the following code which tries to delete a file on a windows 7 machine:

    // check if this item has an uploaded image file
    var imageFullPathName = __dirname + "/../public/images/" + req.params.itemId;
    logger.log("imageFullPathName = " + imageFullPathName);
    var normalizedPathName = path.normalize(imageFullPathName);
    logger.log("normalizedPathName = " + normalizedPathName);

    // delete the image if it exists
    fs.exists(normalizedPathName, function(exists) {
        console.log("Found the file: " + normalizedPathName);
        normalizedPathName = normalizedPathName.replace(/\\/g,"\\\\");
        console.log("New path name = " + normalizedPathName);
        fs.unlink(normalizedPathName, function(err){
            if (err){
                console.error("Error in call to fs.unlink");
            }
        });
    });

I get the following output:

imageFullPathName = C:\IronKey\hes\cscie-71\project\medical-interchange\routes/../public/images/5658e5612103cb2c41000006

normalizedPathName = C:\IronKey\hes\cscie-71\project\medical-interchange\public\images\5658e5612103cb2c41000006

New path name = C:\\IronKey\\hes\\cscie-71\\project\\medical-interchange\\public\\images\\5658e5612103cb2c41000006

Error in call to fs.unlink

The file in question does indeed exist when I look for it using a DOS shell. It also doesn't matter what I do to the new path name, I can never delete the file. If I leave the path with single back slashes by commenting out the call to normalizedPathName.replace(), it still fails. However, if I manually create a string like this it works:

fs.unlink("c:\\IronKey\\hes\\cscie-71\\project\\medical-interchange\\public\\images\\5658e5612103cb2c41000006", function(err){ ...

What do I have to do to delete this file? I'm totally stumped.

I modified the code as recommended by josh3736 as follows but I get a ENOENT error. The file clearly does exist because I opened it in my editor using the EXACT full path name reported in the error message:

        // check if this item has an uploaded image file
        var imageFullPathName = path.join(__dirname, "../public/images",
                                          sanitize(req.params.itemId));
        logger.log("imageFullPathName = " + imageFullPathName);

        fs.unlink(imageFullPathName, function(err){
            //if (err.code != 'ENOENT'){
            if (err){
                logger.log("Error in call to fs.unlink", err);
            }
            else{
                logger.log("No file found");
            }
            logger.log("Delete Success");
        });

And the error message follows: Error in call to fs.unlink { [Error: ENOENT: no such file or directory, unlink 'C:\\IronKey\\hes\\cscie-71\\project\\medical-interchange\\public\\images\\5658fd27fca1b3bc3d00000e']

5
  • Why do you do fs.exists() with one version of normalizedPathName and then you try to change it before deleting? Also, fs.exists() is an anti-pattern. Just attempt the delete and deal with an error if it doesn't exist. Commented Nov 28, 2015 at 0:06
  • I'm really new to javascript and node. Could you please explain what "anti-pattern means"? Commented Nov 28, 2015 at 0:36
  • Now to answer your question: The fs.exists() call works with the path that pass it. The call to fs.unlink() fails and I was trying to find a way to make it work. There is literally no other reason. Commented Nov 28, 2015 at 0:38
  • Anti-pattern means "a bad way to do things". You need to stop changing the path and just call fs.unlink() on the desired path with no fs.exists() call. If it doesn't work, then look at exactly what error is returned and diagnose using that. fs.exists() is deprecated because of concurrency issues. In a multi-tasking OS, the file can be removed between the call to fs.exists() and then call to fs.unlink() by some other process. And, you can just call fs.unlink() and handle an error if the file did not exist. There is no reason for the fs.exists() call. Commented Nov 28, 2015 at 0:49
  • Thanks for the explanation! Commented Nov 28, 2015 at 1:18

2 Answers 2

2

There are several problems here.

  1. You are blindly trusting user input. An attacker need only request a URL with the itemId set to something like %2E%2E%2F%2E%2E%2F%2E%2E%2FWindows. Express would unescape this in req.params to ../../../Windows, and there goes your server.

    In general, remember to be extremely careful when dealing with untrusted input (and anything that comes in over HTTP is untrusted). In this case, use something like sanitize-filename to make sure nothing naughty is in the input.

  2. fs.exists is an anti-pattern. Some other process might add or remove the file in question between your call to exists and whatever you do next. Instead, call unlink unconditionally -- if you get an error with err.code == 'ENOENT', the file didn't exist; just ignore the error.

  3. Why normalizedPathName = normalizedPathName.replace(/\\/g,"\\\\");? You have a valid path that you're making invalid (C:\foo\barC:\\foo\\bar), so of course it doesn't work.

  4. When assembling a path, use path.join, not string concatenation. It will deal with slashes (\ vs /), making your code portable.

Taking this all together,

var imageFullPathName = path.join(
                                    __dirname,
                                    "../public/images",
                                    sanitizeFilename(req.params.itemId)
                                );

fs.unlink(imageFullPathName, function(err){
    if (err) {
        if (err.code != 'ENOENT') {
            // handle actual errors here
            console.error("Error in call to fs.unlink", err);
        }
        // else there was no file, handle that if you need to
    }
    // else delete success, handle that if you need to
});

Since you mentioned that your code fails even when commenting out the backslash replace line:

Your code should work that way. What is the actual error? My first guess would be a permissions problem.

Sign up to request clarification or add additional context in comments.

7 Comments

The file most definitely does exist as I opened the file in my editor using the EXACT path name reported in the error message above.
I included the modified code and the full error message in the original question above as I did not have enough characters to do it in a comment.
Here is the error: Error in call to fs.unlink { [Error: ENOENT: no such file or directory, unlink 'C:\\IronKey\\hes\\cscie-71\\project\\medical-interchange\\public\\images\\5658fd27fca1b‌​3bc3d00000e']
It's weird that the error code has double back slashes while the actual file name does not. Here is the output from logging the imageFullPathName: imageFullPathName = C:\IronKey\hes\cscie-71\project\medical-interchange\public\images\5658fd27fca1b3bc3d00000e
One other comment, I did modify the code slightly in order to determine the error by removing "!= ENOENT".
|
0

You can use Windows Command Line to delete file permanently instead of fs.unlink:

exec(`del ${imageFullPathName}`, (error, stdout, stderr) => {
  if (error) {
    console.error(`exec error: ${error}`);
    return;
  }
});

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.