@photostructure/fs-metadata 0.4.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/C++_REVIEW_TODO.md +291 -0
- package/CHANGELOG.md +29 -1
- package/CLAUDE.md +169 -0
- package/CONTRIBUTING.md +25 -0
- package/coverage/base.css +224 -0
- package/coverage/block-navigation.js +87 -0
- package/coverage/favicon.png +0 -0
- package/coverage/index.html +131 -0
- package/coverage/lcov-report/base.css +224 -0
- package/coverage/lcov-report/block-navigation.js +87 -0
- package/coverage/lcov-report/favicon.png +0 -0
- package/coverage/lcov-report/index.html +131 -0
- package/coverage/lcov-report/prettify.css +1 -0
- package/coverage/lcov-report/prettify.js +2 -0
- package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
- package/coverage/lcov-report/sorter.js +196 -0
- package/coverage/lcov-report/src/array.ts.html +217 -0
- package/coverage/lcov-report/src/async.ts.html +547 -0
- package/coverage/lcov-report/src/debuglog.ts.html +187 -0
- package/coverage/lcov-report/src/defer.ts.html +175 -0
- package/coverage/lcov-report/src/dirname.ts.html +124 -0
- package/coverage/lcov-report/src/error.ts.html +322 -0
- package/coverage/lcov-report/src/fs.ts.html +316 -0
- package/coverage/lcov-report/src/glob.ts.html +472 -0
- package/coverage/lcov-report/src/hidden.ts.html +724 -0
- package/coverage/lcov-report/src/index.html +521 -0
- package/coverage/lcov-report/src/index.ts.html +676 -0
- package/coverage/lcov-report/src/linux/dev_disk.ts.html +316 -0
- package/coverage/lcov-report/src/linux/index.html +146 -0
- package/coverage/lcov-report/src/linux/mount_points.ts.html +364 -0
- package/coverage/lcov-report/src/linux/mtab.ts.html +493 -0
- package/coverage/lcov-report/src/mount_point.ts.html +106 -0
- package/coverage/lcov-report/src/number.ts.html +148 -0
- package/coverage/lcov-report/src/object.ts.html +265 -0
- package/coverage/lcov-report/src/options.ts.html +475 -0
- package/coverage/lcov-report/src/path.ts.html +268 -0
- package/coverage/lcov-report/src/platform.ts.html +112 -0
- package/coverage/lcov-report/src/random.ts.html +205 -0
- package/coverage/lcov-report/src/remote_info.ts.html +553 -0
- package/coverage/lcov-report/src/stack_path.ts.html +298 -0
- package/coverage/lcov-report/src/string.ts.html +382 -0
- package/coverage/lcov-report/src/string_enum.ts.html +208 -0
- package/coverage/lcov-report/src/system_volume.ts.html +301 -0
- package/coverage/lcov-report/src/unc.ts.html +274 -0
- package/coverage/lcov-report/src/units.ts.html +274 -0
- package/coverage/lcov-report/src/uuid.ts.html +157 -0
- package/coverage/lcov-report/src/volume_health_status.ts.html +259 -0
- package/coverage/lcov-report/src/volume_metadata.ts.html +787 -0
- package/coverage/lcov-report/src/volume_mount_points.ts.html +388 -0
- package/coverage/lcov.info +3581 -0
- package/coverage/prettify.css +1 -0
- package/coverage/prettify.js +2 -0
- package/coverage/sort-arrow-sprite.png +0 -0
- package/coverage/sorter.js +196 -0
- package/coverage/src/array.ts.html +217 -0
- package/coverage/src/async.ts.html +547 -0
- package/coverage/src/debuglog.ts.html +187 -0
- package/coverage/src/defer.ts.html +175 -0
- package/coverage/src/dirname.ts.html +124 -0
- package/coverage/src/error.ts.html +322 -0
- package/coverage/src/fs.ts.html +316 -0
- package/coverage/src/glob.ts.html +472 -0
- package/coverage/src/hidden.ts.html +724 -0
- package/coverage/src/index.html +521 -0
- package/coverage/src/index.ts.html +676 -0
- package/coverage/src/linux/dev_disk.ts.html +316 -0
- package/coverage/src/linux/index.html +146 -0
- package/coverage/src/linux/mount_points.ts.html +364 -0
- package/coverage/src/linux/mtab.ts.html +493 -0
- package/coverage/src/mount_point.ts.html +106 -0
- package/coverage/src/number.ts.html +148 -0
- package/coverage/src/object.ts.html +265 -0
- package/coverage/src/options.ts.html +475 -0
- package/coverage/src/path.ts.html +268 -0
- package/coverage/src/platform.ts.html +112 -0
- package/coverage/src/random.ts.html +205 -0
- package/coverage/src/remote_info.ts.html +553 -0
- package/coverage/src/stack_path.ts.html +298 -0
- package/coverage/src/string.ts.html +382 -0
- package/coverage/src/string_enum.ts.html +208 -0
- package/coverage/src/system_volume.ts.html +301 -0
- package/coverage/src/unc.ts.html +274 -0
- package/coverage/src/units.ts.html +274 -0
- package/coverage/src/uuid.ts.html +157 -0
- package/coverage/src/volume_health_status.ts.html +259 -0
- package/coverage/src/volume_metadata.ts.html +787 -0
- package/coverage/src/volume_mount_points.ts.html +388 -0
- package/jest.config.cjs +67 -6
- package/package.json +51 -41
- package/prebuilds/linux-x64/@photostructure+fs-metadata.glibc.node +0 -0
- package/scripts/check-memory.mjs +243 -0
- package/scripts/clang-tidy.mjs +73 -0
- package/scripts/is-platform.mjs +12 -0
- package/scripts/post-build.mjs +21 -0
- package/scripts/run-asan.sh +92 -0
- package/scripts/valgrind-test.mjs +83 -0
- package/scripts/valgrind.sh +70 -0
- package/src/async.ts +3 -3
- package/src/binding.cpp +3 -3
- package/src/error.ts +3 -3
- package/src/fs.ts +1 -1
- package/src/glob.ts +2 -2
- package/src/hidden.ts +6 -6
- package/src/index.ts +19 -23
- package/src/linux/blkid_cache.cpp +15 -12
- package/src/linux/dev_disk.ts +2 -2
- package/src/linux/gio_mount_points.cpp +7 -7
- package/src/linux/gio_utils.cpp +19 -8
- package/src/linux/gio_volume_metadata.cpp +15 -15
- package/src/linux/mount_points.ts +9 -9
- package/src/linux/mtab.ts +7 -7
- package/src/linux/volume_metadata.cpp +6 -1
- package/src/object.ts +1 -1
- package/src/options.ts +3 -3
- package/src/path.ts +2 -2
- package/src/remote_info.ts +5 -5
- package/src/system_volume.ts +8 -8
- package/src/test-utils/assert.ts +2 -2
- package/src/test-utils/debuglog-child.ts +1 -3
- package/src/test-utils/debuglog-enabled-child.ts +10 -0
- package/src/test-utils/hidden-tests.ts +1 -1
- package/src/test-utils/platform.ts +3 -3
- package/src/types/native_bindings.ts +3 -3
- package/src/types/volume_metadata.ts +2 -2
- package/src/unc.ts +2 -2
- package/src/uuid.ts +1 -1
- package/src/volume_health_status.ts +6 -6
- package/src/volume_metadata.ts +20 -23
- package/src/volume_mount_points.ts +12 -17
- package/src/windows/drive_status.h +30 -13
- package/src/windows/hidden.cpp +12 -0
- package/src/windows/volume_metadata.cpp +17 -7
- package/tsup.config.ts +8 -2
- package/dist/index.cjs +0 -1439
- package/dist/index.cjs.map +0 -1
- package/dist/index.mjs +0 -1396
- package/dist/index.mjs.map +0 -1
- package/dist/types/array.d.ts +0 -25
- package/dist/types/async.d.ts +0 -42
- package/dist/types/debuglog.d.ts +0 -3
- package/dist/types/defer.d.ts +0 -10
- package/dist/types/dirname.d.ts +0 -1
- package/dist/types/error.d.ts +0 -17
- package/dist/types/fs.d.ts +0 -22
- package/dist/types/glob.d.ts +0 -17
- package/dist/types/hidden.d.ts +0 -29
- package/dist/types/index.d.ts +0 -91
- package/dist/types/linux/dev_disk.d.ts +0 -13
- package/dist/types/linux/mount_points.d.ts +0 -6
- package/dist/types/linux/mtab.d.ts +0 -47
- package/dist/types/mount_point.d.ts +0 -2
- package/dist/types/number.d.ts +0 -3
- package/dist/types/object.d.ts +0 -18
- package/dist/types/options.d.ts +0 -33
- package/dist/types/path.d.ts +0 -17
- package/dist/types/platform.d.ts +0 -4
- package/dist/types/random.d.ts +0 -12
- package/dist/types/remote_info.d.ts +0 -6
- package/dist/types/stack_path.d.ts +0 -2
- package/dist/types/string.d.ts +0 -37
- package/dist/types/string_enum.d.ts +0 -19
- package/dist/types/system_volume.d.ts +0 -14
- package/dist/types/types/hidden_metadata.d.ts +0 -32
- package/dist/types/types/mount_point.d.ts +0 -46
- package/dist/types/types/native_bindings.d.ts +0 -51
- package/dist/types/types/options.d.ts +0 -47
- package/dist/types/types/remote_info.d.ts +0 -33
- package/dist/types/types/volume_metadata.d.ts +0 -46
- package/dist/types/unc.d.ts +0 -11
- package/dist/types/units.d.ts +0 -38
- package/dist/types/uuid.d.ts +0 -16
- package/dist/types/volume_health_status.d.ts +0 -24
- package/dist/types/volume_metadata.d.ts +0 -8
- package/dist/types/volume_mount_points.d.ts +0 -6
- package/jest.config.base.cjs +0 -63
- package/prebuilds/darwin-arm64/@photostructure+fs-metadata.glibc.node +0 -0
- package/prebuilds/linux-arm64/@photostructure+fs-metadata.musl.node +0 -0
- package/prebuilds/linux-x64/@photostructure+fs-metadata.musl.node +0 -0
- package/prebuilds/win32-x64/@photostructure+fs-metadata.glibc.node +0 -0
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
#pragma once
|
|
4
4
|
#include "../common/debug_log.h"
|
|
5
|
+
#include <atomic>
|
|
5
6
|
#include <memory>
|
|
6
7
|
#include <string>
|
|
7
8
|
#include <vector>
|
|
@@ -35,15 +36,15 @@ inline std::string DriveStatusToString(DriveStatus status) {
|
|
|
35
36
|
class IOOperation {
|
|
36
37
|
private:
|
|
37
38
|
HANDLE completionEvent;
|
|
38
|
-
DriveStatus result;
|
|
39
|
+
std::atomic<DriveStatus> result;
|
|
39
40
|
std::string path;
|
|
40
41
|
DWORD threadId;
|
|
41
|
-
|
|
42
|
+
std::atomic<bool> shouldTerminate;
|
|
42
43
|
HANDLE threadHandle; // Store thread handle as member
|
|
43
44
|
|
|
44
45
|
public:
|
|
45
46
|
IOOperation()
|
|
46
|
-
: result
|
|
47
|
+
: result{DriveStatus::Unknown}, threadId(0), shouldTerminate{false},
|
|
47
48
|
threadHandle(NULL) {
|
|
48
49
|
completionEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
|
49
50
|
}
|
|
@@ -59,12 +60,20 @@ public:
|
|
|
59
60
|
if (threadHandle) {
|
|
60
61
|
DEBUG_LOG("[IOOperation] Cleaning up thread %lu", threadId);
|
|
61
62
|
// Signal termination
|
|
62
|
-
shouldTerminate
|
|
63
|
-
|
|
64
|
-
//
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
63
|
+
shouldTerminate.store(true, std::memory_order_release);
|
|
64
|
+
|
|
65
|
+
// Wake up thread if it's waiting on something
|
|
66
|
+
SetEvent(completionEvent);
|
|
67
|
+
|
|
68
|
+
// Give thread chance to exit gracefully (increased timeout)
|
|
69
|
+
DWORD waitResult = WaitForSingleObject(threadHandle, 1000);
|
|
70
|
+
if (waitResult != WAIT_OBJECT_0) {
|
|
71
|
+
DEBUG_LOG("[IOOperation] WARNING: Thread %lu did not exit gracefully "
|
|
72
|
+
"after 1000ms",
|
|
73
|
+
threadId);
|
|
74
|
+
// NEVER use TerminateThread - it's extremely dangerous
|
|
75
|
+
// Instead, log the issue and abandon the thread
|
|
76
|
+
// The thread will eventually exit when the process terminates
|
|
68
77
|
}
|
|
69
78
|
|
|
70
79
|
CloseHandle(threadHandle);
|
|
@@ -81,15 +90,23 @@ public:
|
|
|
81
90
|
|
|
82
91
|
DEBUG_LOG("[WorkerThread] Starting search on path: %s", searchPath.c_str());
|
|
83
92
|
|
|
93
|
+
// Check if we should terminate before starting work
|
|
94
|
+
if (self->shouldTerminate.load(std::memory_order_acquire)) {
|
|
95
|
+
DEBUG_LOG("[WorkerThread] Thread %lu terminating before work",
|
|
96
|
+
self->threadId);
|
|
97
|
+
return 0;
|
|
98
|
+
}
|
|
99
|
+
|
|
84
100
|
findHandle = FindFirstFileExA(
|
|
85
101
|
searchPath.c_str(), FindExInfoBasic, &findData, FindExSearchNameMatch,
|
|
86
102
|
NULL, FIND_FIRST_EX_LARGE_FETCH | FIND_FIRST_EX_ON_DISK_ENTRIES_ONLY);
|
|
87
103
|
|
|
88
104
|
if (findHandle == INVALID_HANDLE_VALUE) {
|
|
89
|
-
self->result
|
|
105
|
+
self->result.store(self->MapErrorToDriveStatus(GetLastError()),
|
|
106
|
+
std::memory_order_release);
|
|
90
107
|
DEBUG_LOG("[WorkerThread] Search failed with error: %lu", GetLastError());
|
|
91
108
|
} else {
|
|
92
|
-
self->result
|
|
109
|
+
self->result.store(DriveStatus::Healthy, std::memory_order_release);
|
|
93
110
|
FindClose(findHandle);
|
|
94
111
|
DEBUG_LOG("[WorkerThread] Search completed successfully");
|
|
95
112
|
}
|
|
@@ -109,7 +126,7 @@ public:
|
|
|
109
126
|
|
|
110
127
|
path = checkPath;
|
|
111
128
|
ResetEvent(completionEvent);
|
|
112
|
-
shouldTerminate
|
|
129
|
+
shouldTerminate.store(false, std::memory_order_release);
|
|
113
130
|
|
|
114
131
|
threadHandle = CreateThread(NULL, 0, WorkerThread, this, 0, &threadId);
|
|
115
132
|
if (!threadHandle) {
|
|
@@ -131,7 +148,7 @@ public:
|
|
|
131
148
|
CloseHandle(threadHandle);
|
|
132
149
|
DEBUG_LOG("[CheckDriveStatus] CloseHandle %lu completed", threadId);
|
|
133
150
|
threadHandle = NULL;
|
|
134
|
-
return result;
|
|
151
|
+
return result.load(std::memory_order_acquire);
|
|
135
152
|
}
|
|
136
153
|
|
|
137
154
|
private:
|
package/src/windows/hidden.cpp
CHANGED
|
@@ -70,6 +70,12 @@ public:
|
|
|
70
70
|
|
|
71
71
|
void Execute() override {
|
|
72
72
|
try {
|
|
73
|
+
// Add path validation to prevent directory traversal
|
|
74
|
+
if (path.find("..") != std::string::npos) {
|
|
75
|
+
throw FSException("Invalid path containing '..'",
|
|
76
|
+
ERROR_INVALID_PARAMETER);
|
|
77
|
+
}
|
|
78
|
+
|
|
73
79
|
auto wpath = PathConverter::ToWString(path);
|
|
74
80
|
FileAttributeHandler handler(wpath);
|
|
75
81
|
result = handler.isHidden();
|
|
@@ -98,6 +104,12 @@ public:
|
|
|
98
104
|
|
|
99
105
|
void Execute() override {
|
|
100
106
|
try {
|
|
107
|
+
// Add path validation to prevent directory traversal
|
|
108
|
+
if (path.find("..") != std::string::npos) {
|
|
109
|
+
throw FSException("Invalid path containing '..'",
|
|
110
|
+
ERROR_INVALID_PARAMETER);
|
|
111
|
+
}
|
|
112
|
+
|
|
101
113
|
auto wpath = PathConverter::ToWString(path);
|
|
102
114
|
FileAttributeHandler handler(wpath);
|
|
103
115
|
handler.setHidden(value);
|
|
@@ -24,11 +24,20 @@ class WNetConnection {
|
|
|
24
24
|
|
|
25
25
|
public:
|
|
26
26
|
explicit WNetConnection(const std::string &path)
|
|
27
|
-
: drivePath(path.substr(0, 2)), bufferSize(
|
|
28
|
-
|
|
27
|
+
: drivePath(path.substr(0, 2)), bufferSize(MAX_PATH) {
|
|
28
|
+
|
|
29
|
+
// Allocate initial buffer
|
|
30
|
+
buffer = std::make_unique<char[]>(bufferSize);
|
|
29
31
|
|
|
30
32
|
DWORD result =
|
|
31
33
|
WNetGetConnectionA(drivePath.c_str(), buffer.get(), &bufferSize);
|
|
34
|
+
|
|
35
|
+
if (result == ERROR_MORE_DATA) {
|
|
36
|
+
// bufferSize now contains the required size
|
|
37
|
+
buffer = std::make_unique<char[]>(bufferSize);
|
|
38
|
+
result = WNetGetConnectionA(drivePath.c_str(), buffer.get(), &bufferSize);
|
|
39
|
+
}
|
|
40
|
+
|
|
32
41
|
isValid = (result == NO_ERROR);
|
|
33
42
|
}
|
|
34
43
|
|
|
@@ -70,8 +79,9 @@ inline std::string GetVolumeGUID(const std::string &mountPoint) {
|
|
|
70
79
|
|
|
71
80
|
// RAII wrapper for volume information
|
|
72
81
|
class VolumeInfo {
|
|
73
|
-
|
|
74
|
-
char
|
|
82
|
+
static constexpr DWORD VOLUME_NAME_SIZE = MAX_PATH + 1; // 261 characters
|
|
83
|
+
char volumeName[VOLUME_NAME_SIZE];
|
|
84
|
+
char fstype[VOLUME_NAME_SIZE];
|
|
75
85
|
DWORD serialNumber;
|
|
76
86
|
DWORD maxComponentLen;
|
|
77
87
|
DWORD fsFlags;
|
|
@@ -79,9 +89,9 @@ class VolumeInfo {
|
|
|
79
89
|
|
|
80
90
|
public:
|
|
81
91
|
explicit VolumeInfo(const std::string &mountPoint) {
|
|
82
|
-
valid = GetVolumeInformationA(
|
|
83
|
-
|
|
84
|
-
|
|
92
|
+
valid = GetVolumeInformationA(
|
|
93
|
+
mountPoint.c_str(), volumeName, VOLUME_NAME_SIZE, &serialNumber,
|
|
94
|
+
&maxComponentLen, &fsFlags, fstype, VOLUME_NAME_SIZE);
|
|
85
95
|
|
|
86
96
|
if (!valid && GetLastError() != ERROR_NOT_READY) {
|
|
87
97
|
throw FSException("GetVolumeInformation", GetLastError());
|
package/tsup.config.ts
CHANGED
|
@@ -1,9 +1,15 @@
|
|
|
1
1
|
import { defineConfig } from "tsup";
|
|
2
2
|
|
|
3
3
|
export default defineConfig({
|
|
4
|
+
entry: ["src/index.ts"],
|
|
5
|
+
format: ["cjs", "esm"],
|
|
6
|
+
dts: true, // Generate .d.ts files automatically
|
|
7
|
+
clean: true, // Clean dist before each build
|
|
8
|
+
sourcemap: true,
|
|
4
9
|
outExtension: ({ format }) => ({
|
|
5
10
|
js: format === "cjs" ? ".cjs" : ".mjs", // Use .cjs for CommonJS and .mjs for ESM
|
|
6
11
|
}),
|
|
7
|
-
shims: true,
|
|
8
|
-
|
|
12
|
+
shims: true, // Inject CJS shims (__dirname, __filename) in ESM output
|
|
13
|
+
target: "es2022", // Align with TypeScript target
|
|
14
|
+
tsconfig: "tsconfig.build.json", // Use a single tsconfig for building
|
|
9
15
|
});
|