node.js fs module rename directory that has subdirectories (EPERM, EXDEV)

Viewed 511

I am trying to write a server in node.js that will work like a simplified google drive / onedrive. I wrote a method for renaming files/directories, but it doesn't work in all cases. Here is the code below:

try {
  if (!fs.existsSync(fullPath)) {
    reject(new Error('The file to be renamed does not exist!'));
  } else if (fs.existsSync(newPath)) {
    reject(new Error('A file already exists with that name!'));
  } else {
    fs.renameSync(fullPath, newPath);
    resolve(newPath);
  }
} catch (err) {
  reject(err);
}

It has no problem renaming files, or renaming directories that contain no subdirectories. But when a directory has one or more subdirectories, the renaming fails.

I am using a windows platform, and I get the following error. I have tried changing file permissions before renaming with fs.chmodSync(fullPath, 0o777), but the error still persists.

"errno": -4048,
"syscall": "rename",
"code": "EPERM",

I thought the problem was with windows and it's filesystem usage, so I tried running the whole thing inside a Docker container (the final product will be deployed on docker), but then I got the following error:

"errno": -18,
"syscall": "rename",
"code": "EXDEV",

The problem is that my paths are normalized and there is nothing like copying from one drive to another, if I console.log my fullPath and newPath, I get something like:

src/test-storage/myFolder/aFolder
src/test-storage/myFolder/xFolder

Thank you in advance for any help. Have a nice day! :)

1 Answers

My first answer had no help, so I deleted it and here is a new one.

I had the same issue except that I used 'fs-extra' module and tried to move a folder that contains another folder. When I checked the 'moveSync' method I found that it's used the same 'renameSync' from 'fs' module.

I haven't found a reason of this error, but here is a workaround:

  1. Copy your folder recursively. I used the same fs-extra module, but ncp also does the trick.

So, first import the module

import * as fs from 'fs-extra';

and then copy your folder:

fs.copySync('/tmp/folderName', '/tmp/newFolderName');
  1. After that just remove the original folder, fs-extra and ncp use the rimraf module under the hood, but I end up using fs.rmdirSync with option recursive: true:

fs.rmdirSync(path, { recursive: true });

Despite that it didn't produce an error when I tried, I'd still recommend to use the original fs.renameSync for renaming files.

That would be great if somebody has an explanation why fs.renameSync doesn't work with folder that contains another folder and can share it.

UPDATE: Here is the method I use for renaming folders and files:

rename(path: string, newPath: string) {
    if (fs.existsSync(newPath)) {
      throw new Error('Already exists');
    }
    
    if (fs.lstatSync(path).isDirectory()) {
      fs.copySync(path, newPath);
      fs.rmdirSync(path, { recursive: true });
    } else if (fs.lstatSync(path).isFile()) {
      fs.renameSync(path, newPath);
    }
  }
Related