HelloWorld
HelloWorld

Reputation: 1863

How to open a file with exclusive file access in node?

On Windows, I am looking for a way to open a file with exclusive access. The MSDN documents a function called CreateFile with dwShareMode of 0.

https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea

In specific I am looking for a way the documentation states here:

Prevents other processes from opening a file or device if they request delete, read, or write access.

Does anyone know a built-in or npm package wrapping this functionality?

Upvotes: 1

Views: 1076

Answers (1)

jfriend00
jfriend00

Reputation: 707706

The module add-on fs-ext will work on Windows if you can build it successfully. I had to install Python on my system and put it in the path before it would install and build successfully. Once I did that, then I was able to run this test which verified that a child process was not allowed to read or write to a file that I had an flock on:

// open-exclusive.js
const fs = require('fs');
const fsp = fs.promises;
const child = require('child_process');
const { promisify } = require('util');
const execP = promisify(child.exec);
const flock = promisify(require('fs-ext').flock);

const exclusive = fs.constants.S_IRUSR | fs.constants.S_IWUSR | fs.constants.S_IXUSR;

async function run() {
    const fHandle = await fsp.open("./temp.txt", "r+", exclusive);
    await flock(fHandle.fd, 'ex');
    await fHandle.write("Goodbye", 0);
    console.log('parent finished write');

    const { stdout, stderr } = await execP("node open-exclusive-child.js");
    console.log('stdout:', stdout);
    console.error('stderr:', stderr);
    console.log('parent done exec');
    await fHandle.close();
    return "good";
}

run().then(result => {
    console.log(result);
}).catch(err => {
    console.log(err);
});

And the child process file open-exclusive-child.js

const fs = require('fs');
const fsp = fs.promises;

async function run() {
    const fHandle = await fsp.open("./temp.txt", "r");
    let buf = Buffer.alloc(10);
    await fHandle.read(buf, 0, 10, 0);
    await fHandle.write("Hello", 0);
    console.log('child: finished write');
    await fHandle.close();
    return "child good"
}

run().then(result => {
    console.log(result);
}).catch(err => {
    console.log(err);
});

When I run node open-exclusive.js, the parent will open it, flock it successfully and then the child will not be able to read or write to the file. The child is apparently allowed to "open" the file, but gets an EBUSY error when trying to read or write to it.

In fact, the flock works in the same process too:

const fs = require('fs');
const fsp = fs.promises;
const { promisify } = require('util');
const execP = promisify(child.exec);
const flock = promisify(require('fs-ext').flock);

const exclusive = fs.constants.S_IRUSR | fs.constants.S_IWUSR | fs.constants.S_IXUSR;

async function run() {
    const fHandle = await fsp.open("./temp.txt", "r+", exclusive);
    await flock(fHandle.fd, 'ex');
    await fHandle.write("Goodbye", 0);
    console.log('parent finished write');

    const fHandle2 = await fsp.open("./temp.txt", "r");
    const buf = Buffer.alloc(10);
    console.log("About to read from fHandle2");
    let bytes = await fHandle2.read(buf, 0, 10, 0);
    console.log(bytes);
    await fHandle2.close();
    await fHandle.close();
    return "good";
}

run().then(result => {
    console.log(result);
}).catch(err => {
    console.log(err);
});

When I run this, I get this in the console:

node open-exclusive.js
parent finished write
About to read from fHandle2
[Error: EBUSY: resource busy or locked, read] {
  errno: -4082,
  code: 'EBUSY',
  syscall: 'read'
}

Upvotes: 2

Related Questions