hackpro-sdk
Version:
204 lines • 8.6 kB
JavaScript
"use strict";
/*
* Copyright 2018 balena.io
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
const bluebird_1 = require("bluebird");
const mountutils_1 = require("mountutils");
const os_1 = require("os");
const block_write_stream_1 = require("../block-write-stream");
const diskpart_1 = require("../diskpart");
const sparse_write_stream_1 = require("../sparse-stream/sparse-write-stream");
const file_1 = require("./file");
/**
* @summary Time, in milliseconds, to wait before unmounting on success
*/
const UNMOUNT_ON_SUCCESS_TIMEOUT_MS = 2000;
const DEFAULT_BLOCK_SIZE = 512;
const WIN32_FIRST_BYTES_TO_KEEP = 64 * 1024;
const USE_ALIGNED_IO = os_1.platform() === 'win32' || os_1.platform() === 'darwin';
const unmountDiskAsync = bluebird_1.promisify(mountutils_1.unmountDisk);
class BlockDevice extends file_1.File {
constructor(drive, unmountOnSuccess = false) {
super(drive.raw, file_1.File.OpenFlags.WriteDevice);
this.drive = drive;
this.unmountOnSuccess = unmountOnSuccess;
this.emitsProgress = false;
this.blockSize = drive.blockSize || DEFAULT_BLOCK_SIZE;
}
get isSystem() {
return this.drive.isSystem;
}
get raw() {
return this.drive.raw;
}
get device() {
return this.drive.device;
}
get devicePath() {
return this.drive.devicePath;
}
get description() {
return this.drive.description;
}
get mountpoints() {
return this.drive.mountpoints;
}
get size() {
return this.drive.size;
}
_getMetadata() {
return __awaiter(this, void 0, void 0, function* () {
return {
size: this.drive.size || undefined,
};
});
}
canWrite() {
return __awaiter(this, void 0, void 0, function* () {
return !this.drive.isReadOnly;
});
}
canCreateWriteStream() {
return __awaiter(this, void 0, void 0, function* () {
return !this.drive.isReadOnly;
});
}
canCreateSparseWriteStream() {
return __awaiter(this, void 0, void 0, function* () {
return !this.drive.isReadOnly;
});
}
createWriteStream() {
return __awaiter(this, void 0, void 0, function* () {
const stream = new block_write_stream_1.ProgressBlockWriteStream(this, os_1.platform() === 'win32' ? WIN32_FIRST_BYTES_TO_KEEP : 0);
stream.on('finish', stream.emit.bind(stream, 'done'));
return stream;
});
}
createSparseWriteStream() {
return __awaiter(this, void 0, void 0, function* () {
const stream = new sparse_write_stream_1.ProgressSparseWriteStream(this, os_1.platform() === 'win32' ? WIN32_FIRST_BYTES_TO_KEEP : 0);
stream.on('finish', stream.emit.bind(stream, 'done'));
return stream;
});
}
_open() {
const _super = Object.create(null, {
_open: { get: () => super._open }
});
return __awaiter(this, void 0, void 0, function* () {
if (os_1.platform() !== 'win32') {
yield unmountDiskAsync(this.drive.device);
}
yield diskpart_1.clean(this.drive.device);
yield _super._open.call(this);
});
}
_close() {
const _super = Object.create(null, {
_close: { get: () => super._close }
});
return __awaiter(this, void 0, void 0, function* () {
yield _super._close.call(this);
// Closing a file descriptor on a drive containing mountable
// partitions causes macOS to mount the drive. If we try to
// unmount too quickly, then the drive might get re-mounted
// right afterwards.
if (this.unmountOnSuccess) {
yield bluebird_1.delay(UNMOUNT_ON_SUCCESS_TIMEOUT_MS);
yield unmountDiskAsync(this.drive.device);
}
});
}
offsetIsAligned(offset) {
return offset % this.blockSize === 0;
}
alignOffsetBefore(offset) {
return Math.floor(offset / this.blockSize) * this.blockSize;
}
alignOffsetAfter(offset) {
return Math.ceil(offset / this.blockSize) * this.blockSize;
}
alignedRead(buffer, bufferOffset, length, sourceOffset) {
const _super = Object.create(null, {
read: { get: () => super.read }
});
return __awaiter(this, void 0, void 0, function* () {
const start = this.alignOffsetBefore(sourceOffset);
const end = this.alignOffsetAfter(sourceOffset + length);
const alignedBuffer = Buffer.allocUnsafe(end - start);
const { bytesRead } = yield _super.read.call(this, alignedBuffer, 0, alignedBuffer.length, start);
const offset = sourceOffset - start;
alignedBuffer.copy(buffer, bufferOffset, offset, offset + length);
return { buffer, bytesRead: Math.min(length, bytesRead - offset) };
});
}
read(buffer, bufferOffset, length, sourceOffset) {
const _super = Object.create(null, {
read: { get: () => super.read }
});
return __awaiter(this, void 0, void 0, function* () {
if (USE_ALIGNED_IO &&
!(this.offsetIsAligned(sourceOffset) && this.offsetIsAligned(length))) {
return yield this.alignedRead(buffer, bufferOffset, length, sourceOffset);
}
else {
return yield _super.read.call(this, buffer, bufferOffset, length, sourceOffset);
}
});
}
alignedWrite(buffer, bufferOffset, length, fileOffset) {
const _super = Object.create(null, {
read: { get: () => super.read },
write: { get: () => super.write }
});
return __awaiter(this, void 0, void 0, function* () {
const start = this.alignOffsetBefore(fileOffset);
const end = this.alignOffsetAfter(fileOffset + length);
const alignedBuffer = Buffer.allocUnsafe(end - start);
yield _super.read.call(this, alignedBuffer, 0, alignedBuffer.length, start);
const offset = fileOffset - start;
buffer.copy(alignedBuffer, offset, bufferOffset, length);
yield _super.write.call(this, alignedBuffer, 0, alignedBuffer.length, start);
return { buffer, bytesWritten: length };
});
}
write(buffer, bufferOffset, length, fileOffset) {
const _super = Object.create(null, {
write: { get: () => super.write }
});
return __awaiter(this, void 0, void 0, function* () {
if (USE_ALIGNED_IO &&
!(this.offsetIsAligned(fileOffset) && this.offsetIsAligned(length))) {
return yield this.alignedWrite(buffer, bufferOffset, length, fileOffset);
}
else {
return yield _super.write.call(this, buffer, bufferOffset, length, fileOffset);
}
});
}
}
exports.BlockDevice = BlockDevice;
//# sourceMappingURL=block-device.js.map