1

I need to check if a file is open before I copy it to another location.The code below tells if its open with an error code = EBUSY. But if the file is not open it erases the content of the file. Is there a better way of achieving this information.

    fs.open('my-file.dwg','w', function(err,data) {

    });
James Morris
  • 353
  • 5
  • 20

2 Answers2

4

It looks to me like you can use r+:

fs.open('my-file.dwg','r+', function(err,data) {

});

From the fs module docs:

'r+' - Open file for reading and writing. An exception occurs if the file does not exist.

If the file is already open by someone else, then it should not grant you permission for reading and writing and should return an error. This will not create the file it if does not exist.

The r+ option will not truncate or create the file like the w+ option will.

jfriend00
  • 683,504
  • 96
  • 985
  • 979
4

Caveat: I am posting this as the accepted answer doesn't work. However I am no expert on Windows file locking but this is what I have been able to cobble together:

On Windows there seem to be 3 types of lock which cause the EBUSY in Node.

  1. Files locked with an 'exclusive lock'
  2. Executable files locked by the OS which are currently running
    • e.g. when you run a setup.exe
  3. System protected files
    • e.g. C:\hiberfil.sys

Option A:

Node fs is built on libuv which allows passing advanced options to request an exclusive lock. This seems to be the safest technique as there is no chance of changing/corrupting the file.

Open the file with UV_FS_O_RDONLY and UV_FS_O_EXLOCK

EBUSY returned for 1, 2 and 3.

try {
   const fileHandle = await fs.promises.open(filePath, fs.constants.O_RDONLY | 0x10000000);

  fileHandle.close();
} catch (error) {
  if (error.code === 'EBUSY'){
    console.log('file is busy');
  } else {
    throw error;
  }
}

Note: this requires libuv >= 1.17.0, which is satisfied by NodeJS >= 8.10.0

Option B:

Performing an fs.rename() also reliably fails on a locked file, doesn't require any OS specific flags, but is more dangerous as you could introduce race condition bugs as the file is actually moved temporarily.

EBUSY returned for 1, 2 and 3.

try {
  await fs.promises.rename(filePath, filePathNew);

  await fs.promises.rename(filePathNew, filePath);
} catch (error) {
  if (error.code === 'EBUSY'){
    console.log('file is busy');
  } else {
    throw error;
  }
}

Option C (do not use):

Perform an fs.open(..., 'r+'). This DOES NOT WORK for files with an exclusive lock 1, no error is returned.

EBUSY returned for 2 and 3.

try {
  await fs.promises.open(filePath, 'r+');
} catch (error) {
  if (error.code === 'EBUSY'){
    console.log('file is busy');
  } else {
    throw error;
  }
}
chris
  • 3,019
  • 23
  • 21