Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add attachTimestamp field #421

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ export interface Drive {
raw: string;
size: number | null;
partitionTableType: 'mbr' | 'gpt' | null;
attachTimestamp: number | null;
}

const drivelistBindings = bindings('drivelist');
Expand Down
17 changes: 17 additions & 0 deletions lib/lsblk/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,27 @@ async function getDevicePaths(): Promise<Map<string, string>> {
async function addDevicePaths(devices: Drive[]): Promise<void> {
const devicePaths = await getDevicePaths();
for (const device of devices) {
const path = devicePaths.get(device.device);
device.devicePath = devicePaths.get(device.device) || null;
device.attachTimestamp = await getAttachTimestamp(path);
}
}

async function getAttachTimestamp(path: string | undefined): Promise<number> {
const fsmodule = require('fs');
let time;
try {
const stats = await fsmodule.promises.stat(path);
console.log(stats.mtime);
time = stats.mtime.getTime();
} catch (err) {
time = 0;
console.error(err);
}

return time;
}

async function getOutput(command: string, ...args: string[]) {
const { stdout } = await execFileAsync(command, args);
return stdout;
Expand Down
81 changes: 40 additions & 41 deletions lib/lsblk/json.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,47 +107,46 @@ export function transform(data: LsblkJsonOutput): Drive[] {
!device.name.startsWith('/dev/sr') &&
!device.name.startsWith('/dev/ram'),
)
.map(
(device: LsblkJsonOutputDevice): Drive => {
const isVirtual = device.subsystems
? /^(block)$/i.test(device.subsystems)
: null;
const isSCSI = device.tran
? /^(sata|scsi|ata|ide|pci)$/i.test(device.tran)
: null;
const isUSB = device.tran ? /^(usb)$/i.test(device.tran) : null;
const isReadOnly = Number(device.ro) === 1;
const isRemovable =
Number(device.rm) === 1 ||
Number(device.hotplug) === 1 ||
Boolean(isVirtual);
return {
enumerator: 'lsblk:json',
busType: (device.tran || 'UNKNOWN').toUpperCase(),
busVersion: null,
device: device.name,
devicePath: null,
raw: device.kname || device.name,
description: getDescription(device),
error: null,
size: Number(device.size) || null,
blockSize: Number(device['phy-sec']) || 512,
logicalBlockSize: Number(device['log-sec']) || 512,
mountpoints: device.children
? getMountpoints(device.children)
: getMountpoints([device]),
isReadOnly,
isSystem: !isRemovable && !isVirtual,
isVirtual,
isRemovable,
isCard: null,
isSCSI,
isUSB,
isUAS: null,
partitionTableType: getPartitionTableType(device.pttype),
};
},
);
.map((device: LsblkJsonOutputDevice): Drive => {
const isVirtual = device.subsystems
? /^(block)$/i.test(device.subsystems)
: null;
const isSCSI = device.tran
? /^(sata|scsi|ata|ide|pci)$/i.test(device.tran)
: null;
const isUSB = device.tran ? /^(usb)$/i.test(device.tran) : null;
const isReadOnly = Number(device.ro) === 1;
const isRemovable =
Number(device.rm) === 1 ||
Number(device.hotplug) === 1 ||
Boolean(isVirtual);
return {
enumerator: 'lsblk:json',
busType: (device.tran || 'UNKNOWN').toUpperCase(),
busVersion: null,
device: device.name,
devicePath: null,
raw: device.kname || device.name,
description: getDescription(device),
error: null,
size: Number(device.size) || null,
blockSize: Number(device['phy-sec']) || 512,
logicalBlockSize: Number(device['log-sec']) || 512,
mountpoints: device.children
? getMountpoints(device.children)
: getMountpoints([device]),
isReadOnly,
isSystem: !isRemovable && !isVirtual,
isVirtual,
isRemovable,
isCard: null,
isSCSI,
isUSB,
isUAS: null,
partitionTableType: getPartitionTableType(device.pttype),
attachTimestamp: null,
};
});
}

export function parse(stdout: string): Drive[] {
Expand Down
15 changes: 7 additions & 8 deletions lib/lsblk/pairs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,14 +100,12 @@ function consolidate(
return Object.assign({}, device, {
mountpoints: children
.filter((child) => child.mountpoint)
.map(
(child): Mountpoint => {
return {
path: child.mountpoint,
label: child.label,
};
},
),
.map((child): Mountpoint => {
return {
path: child.mountpoint,
label: child.label,
};
}),
});
});
}
Expand Down Expand Up @@ -182,6 +180,7 @@ export function parse(stdout: string): Drive[] {
partitionTableType: getPartitionTableType(
device.pttype as 'gpt' | 'dos' | undefined,
),
attachTimestamp: null,
};
},
);
Expand Down
10 changes: 4 additions & 6 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,14 +51,14 @@
"node-gyp": "^9.3.1",
"prebuild": "^11.0.4",
"sinon": "^15.0.1",
"ts-node": "^10.9.1",
"typescript": "^4.9.4"
"ts-node": "^10.9.1"
},
"dependencies": {
"bindings": "^1.5.0",
"debug": "^4.3.4",
"node-addon-api": "^5.0.0",
"prebuild-install": "^7.1.1"
"prebuild-install": "^7.1.1",
"typescript": "^4.9.4"
},
"binary": {
"napi_versions": [
Expand Down
7 changes: 6 additions & 1 deletion src/darwin/list.mm
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,11 @@ DeviceDescriptor CreateDeviceDescriptorFromDiskDescription(std::string diskBsdNa
device.isUAS = false;
device.isUASNull = true;

NSFileManager *fileManager = [NSFileManager defaultManager];
NSString *path = [NSString stringWithUTF8String:("/dev/"+diskBsdName).c_str()];
NSDate *dates = [[fileManager attributesOfItemAtPath:path error:NULL] fileModificationDate];
device.attachTimestamp = ((dates != nil) ? [dates timeIntervalSince1970] : 0);

return device;
}

Expand Down Expand Up @@ -146,7 +151,7 @@ DeviceDescriptor CreateDeviceDescriptorFromDiskDescription(std::string diskBsdNa
mountedVolumeURLsIncludingResourceValuesForKeys:volumeKeys
options:0
];

for (NSURL *path in volumePaths) {
DADiskRef disk = DADiskCreateFromVolumePath(kCFAllocatorDefault, session, (__bridge CFURLRef)path);
if (disk == nil) {
Expand Down
2 changes: 2 additions & 0 deletions src/device-descriptor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,8 @@ Napi::Object PackDriveDescriptor(Napi::Env env,
: (Napi::Value)Boolean::New(env, instance->isUAS);

object.Set(String::New(env, "isUAS"), isUAS);
object.Set(String::New(env, "attachTimestamp"),
Number::New(env, static_cast<double>(instance->attachTimestamp)));

return object;
}
Expand Down
1 change: 1 addition & 0 deletions src/drivelist.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ struct DeviceDescriptor {
std::string error;
std::string partitionTableType;
uint64_t size;
uint64_t attachTimestamp;
uint32_t blockSize = 512;
uint32_t logicalBlockSize = 512;
std::vector<std::string> mountpoints;
Expand Down
47 changes: 47 additions & 0 deletions src/windows/list.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,21 @@
#include "../drivelist.hpp"
#include "list.hpp"


#define INITGUID
#ifdef DEFINE_DEVPROPKEY
#undef DEFINE_DEVPROPKEY
#endif
#ifdef INITGUID
#define DEFINE_DEVPROPKEY(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8, pid) EXTERN_C const DEVPROPKEY DECLSPEC_SELECTANY name = { { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } }, pid }
#else
#define DEFINE_DEVPROPKEY(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8, pid) EXTERN_C const DEVPROPKEY name
#endif

#ifndef DEVPKEY_Device_LastArrivalDate
DEFINE_DEVPROPKEY(DEVPKEY_Device_LastArrivalDate, 0x83da6326, 0x97a6, 0x4088, 0x94, 0x53, 0xa1, 0x92, 0x3f, 0x57, 0x3b, 0x29, 102);
#endif

namespace Drivelist {

std::string WCharToUtf8String(const wchar_t* wstr) {
Expand Down Expand Up @@ -657,6 +672,37 @@ bool GetDetailData(DeviceDescriptor* device,
NULL, 0, &size, NULL);

device->isReadOnly = !isWritable;

device->attachTimestamp = NULL;
const int64_t UNIX_TIME_START= 0x019DB1DED53E8000;
const int64_t TICKS_PER_SECOND = 10000000;
DWORD requiredSize;
DEVPROPTYPE type;
SetupDiGetDevicePropertyW(hDeviceInfo, &deviceInfoData, &DEVPKEY_Device_LastArrivalDate,
&type, NULL, 0, &requiredSize, 0);
std::vector<unsigned char> buffer(requiredSize*8);
BOOL hasArrivalDate = SetupDiGetDevicePropertyW(hDeviceInfo, &deviceInfoData, &DEVPKEY_Device_LastArrivalDate, &type, buffer.data(), buffer.capacity(), nullptr, 0);
if (!hasArrivalDate) {
errorCode = GetLastError();
device->error = "Couldn't SetupDiGetDeviceInterfaceDetailW: Error " +
std::to_string(errorCode);
//result = false;
//TOOD is it right to break here?
//break;
}
FILETIME filetime;
LARGE_INTEGER li;
//TODO is this safe?
memmove(&filetime, buffer.data(), buffer.capacity());
li.LowPart=filetime.dwLowDateTime;
li.HighPart=filetime.dwHighDateTime;
//is this even necessary?
FILETIME localFileTime;
FileTimeToLocalFileTime(&filetime, &localFileTime);
SYSTEMTIME systemTime;
FileTimeToSystemTime(&localFileTime, &systemTime);

device->attachTimestamp = (li.QuadPart-UNIX_TIME_START) / TICKS_PER_SECOND;
} // end for (index = 0; ; index++)

if (hDevice != INVALID_HANDLE_VALUE) {
Expand Down Expand Up @@ -726,6 +772,7 @@ std::vector<DeviceDescriptor> ListStorageDevices() {
device.isVirtual = device.isVirtual ||
device.busType == "VIRTUAL" ||
device.busType == "FILEBACKEDVIRTUAL";
device.attachTimestamp = device.attachTimestamp;
} else if (device.error == "") {
device.error = "Couldn't get detail data";
}
Expand Down
1 change: 1 addition & 0 deletions target/npmlist.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"version":"11.1.0","name":"drivelist","dependencies":{"bindings":{"version":"1.5.0"},"debug":{"version":"4.3.4"},"node-addon-api":{"version":"5.0.0"},"prebuild-install":{"version":"7.1.1"},"typescript":{"version":"4.9.4"}}}
4 changes: 4 additions & 0 deletions tests/drivelist.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,10 @@ describe('Drivelist', () => {
device.isUAS === null || typeof device.isUAS === 'boolean',
`Invalid isUAS flag: ${device.isUAS}`,
);
ok(
device.attachTimestamp === null || Number.isFinite(device.attachTimestamp),
`Invalid attachTimestamp: ${device.attachTimestamp}`,
);
});
});

Expand Down
Loading
Loading