Skip to content

Instantly share code, notes, and snippets.

@jorangreef
Created November 28, 2018 13:39
Show Gist options
  • Save jorangreef/3695c546367512f8d5bb4cb45b531c39 to your computer and use it in GitHub Desktop.
Save jorangreef/3695c546367512f8d5bb4cb45b531c39 to your computer and use it in GitHub Desktop.
DirectIO cross-platform open()
const DirectIO = require('@ronomon/direct-io');
const Node = {
fs: require('fs'),
path: require('path'),
process: require('process')
};
const PATH = '\\\\.\\PhysicalDrive1';
// 4096 is better than 512 because it works with new Advanced Format devices:
// It's also backwards-compatible with 512 byte sector devices.
const SECTOR = 4096;
function openDevice(path, callback) {
var fd = null;
var flags = 0;
function close(error, end) {
if (!error) throw new Error('must be called only in the event of an error');
if (fd === null) return end(error);
console.log('closing fd because of an error...');
Node.fs.close(fd,
function(errorClose) {
end(error); // Ignoring any `errorClose` in favor of original `error`.
}
);
}
function end(error) {
if (error) return close(error, callback);
callback(undefined, fd);
}
function open(end) {
console.log('opening ' + path + ' flags=' + flags + '...');
Node.fs.open(path, flags,
function(error, result) {
if (error) return end(error);
console.log('opened fd=' + result);
fd = result;
end();
}
);
}
function setFSCTL_LOCK_VOLUME(end) {
if (Node.process.platform !== 'win32') return end();
console.log('setting FSCTL_LOCK_VOLUME=1...');
DirectIO.setFSCTL_LOCK_VOLUME(fd, 1, end);
}
function setF_NOCACHE(end) {
if (Node.process.platform !== 'darwin') return end();
console.log('setting F_NOCACHE=1 (O_DIRECT for macOS)...');
DirectIO.setF_NOCACHE(fd, 1, end);
}
if (Node.fs.constants.O_RDWR) {
console.log('flags |= O_RDWR');
flags |= Node.fs.constants.O_RDWR;
} else {
return end(new Error('O_RDWR not supported on this platform'));
}
if (Node.process.platform !== 'win32') {
// libuv has an issue setting FILE_FLAG_NO_BUFFERING on Windows.
// Skip Windows while this is being resolved.
if (DirectIO.O_DIRECT) {
console.log('flags |= O_DIRECT');
flags |= DirectIO.O_DIRECT;
} else if (Node.process.platform !== 'darwin') {
return end(new Error('O_DIRECT not supported on this platform'));
}
}
if (DirectIO.O_SYNC) {
console.log('flags |= O_SYNC');
flags |= DirectIO.O_SYNC;
} else {
return end(new Error('O_SYNC not supported on this platform'));
}
if (Node.process.platform === 'darwin' || Node.process.platform === 'win32') {
console.log('flags |= O_EXLOCK');
flags |= DirectIO.O_EXLOCK;
} else {
console.log('flags |= O_EXCL');
flags |= DirectIO.O_EXCL;
}
open(
function(error) {
if (error) return end(error);
setF_NOCACHE(end);
}
);
}
function readDevice(fd, offset, buffer, end) {
console.log(
'reading ' + buffer.length + ' bytes at offset ' + offset + '...'
);
Node.fs.read(fd, buffer, 0, buffer.length, offset, end);
}
function writeDevice(fd, offset, buffer, end) {
console.log(
'writing ' + buffer.length + ' bytes at offset ' + offset + '...'
);
Node.fs.write(fd, buffer, 0, buffer.length, offset, end);
}
openDevice(PATH,
function(error, fd) {
if (error) throw error;
var buffer = DirectIO.getAlignedBuffer(65536, SECTOR);
// Go beyond the MBR to make sure we really have write access on Windows:
var offset = 16 * 1024 * 1024;
readDevice(fd, offset, buffer,
function(error) {
if (error) throw error;
writeDevice(fd, offset, buffer,
function(error) {
if (error) throw error;
console.log('100% OK');
}
);
}
);
}
);
{
"dependencies": {
"@ronomon/direct-io": "^2.4.3"
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment