thesidedoor-flock 0.2.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/LICENSE +18 -0
- package/README.md +17 -0
- package/binding.gyp +11 -0
- package/fs-ext.cc +596 -0
- package/index.cjs +4 -0
- package/index.d.ts +2 -0
- package/package.json +42 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
2
|
+
a copy of this software and associated documentation files (the
|
|
3
|
+
"Software"), to deal in the Software without restriction, including
|
|
4
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
|
5
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
|
6
|
+
permit persons to whom the Software is furnished to do so, subject to
|
|
7
|
+
the following conditions:
|
|
8
|
+
|
|
9
|
+
The above copyright notice and this permission notice shall be
|
|
10
|
+
included in all copies or substantial portions of the Software.
|
|
11
|
+
|
|
12
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
13
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
14
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
15
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
16
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
17
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
18
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# Sidedoor native file locking
|
|
2
|
+
|
|
3
|
+
This package builds the native source from fs-ext 2.1.1 by Matt Sergeant and
|
|
4
|
+
contributors under its original MIT license. It retains the OS flock behavior.
|
|
5
|
+
Sidedoor uses only the synchronous flock entry point.
|
|
6
|
+
|
|
7
|
+
The source removes nine process-global V8 persistent string handles used by
|
|
8
|
+
statvfs. Their property names are created in the current isolate instead.
|
|
9
|
+
This prevents concurrent Node worker initialization from resetting another
|
|
10
|
+
isolate's handles. No locking or filesystem operation has been replaced.
|
|
11
|
+
|
|
12
|
+
Installation requires the same native compiler toolchain as fs-ext. Build output
|
|
13
|
+
is produced locally by node-gyp and is not included in the package archive.
|
|
14
|
+
|
|
15
|
+
Next.js applications must list `thesidedoor-flock` in
|
|
16
|
+
`serverExternalPackages` so the server loads the installed native binary instead
|
|
17
|
+
of adding it to the application bundle.
|
package/binding.gyp
ADDED
package/fs-ext.cc
ADDED
|
@@ -0,0 +1,596 @@
|
|
|
1
|
+
// Permission is hereby granted, free of charge, to any person obtaining a
|
|
2
|
+
// copy of this software and associated documentation files (the
|
|
3
|
+
// "Software"), to deal in the Software without restriction, including
|
|
4
|
+
// without limitation the rights to use, copy, modify, merge, publish,
|
|
5
|
+
// distribute, sublicense, and/or sell copies of the Software, and to permit
|
|
6
|
+
// persons to whom the Software is furnished to do so, subject to the
|
|
7
|
+
// following conditions:
|
|
8
|
+
//
|
|
9
|
+
// The above copyright notice and this permission notice shall be included
|
|
10
|
+
// in all copies or substantial portions of the Software.
|
|
11
|
+
//
|
|
12
|
+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
|
13
|
+
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
14
|
+
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
|
|
15
|
+
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
|
16
|
+
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
|
17
|
+
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
|
18
|
+
// USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
19
|
+
|
|
20
|
+
#include <node.h>
|
|
21
|
+
#ifndef _WIN32
|
|
22
|
+
#include <fcntl.h>
|
|
23
|
+
#endif
|
|
24
|
+
#include <errno.h>
|
|
25
|
+
#include <stdio.h>
|
|
26
|
+
#include <sys/types.h>
|
|
27
|
+
#include <stdlib.h>
|
|
28
|
+
#include <string.h>
|
|
29
|
+
#include <nan.h>
|
|
30
|
+
|
|
31
|
+
#ifndef _WIN32
|
|
32
|
+
#include <sys/file.h>
|
|
33
|
+
#include <unistd.h>
|
|
34
|
+
#include <sys/statvfs.h>
|
|
35
|
+
#endif
|
|
36
|
+
|
|
37
|
+
#ifdef _WIN32
|
|
38
|
+
#include <io.h>
|
|
39
|
+
#include <windows.h>
|
|
40
|
+
#define off_t LONGLONG
|
|
41
|
+
#define _LARGEFILE_SOURCE
|
|
42
|
+
#endif
|
|
43
|
+
|
|
44
|
+
using namespace v8;
|
|
45
|
+
using namespace node;
|
|
46
|
+
|
|
47
|
+
#define THROW_BAD_ARGS Nan::ThrowTypeError("Bad argument")
|
|
48
|
+
|
|
49
|
+
struct store_data_t {
|
|
50
|
+
Nan::Callback *cb;
|
|
51
|
+
int fs_op; // operation type within this module
|
|
52
|
+
int fd;
|
|
53
|
+
int oper;
|
|
54
|
+
int arg;
|
|
55
|
+
off_t offset;
|
|
56
|
+
#ifndef _WIN32
|
|
57
|
+
struct statvfs statvfs_buf;
|
|
58
|
+
#endif
|
|
59
|
+
char *path;
|
|
60
|
+
int error;
|
|
61
|
+
int result;
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
#ifdef _WIN32
|
|
66
|
+
#define LOCK_SH 1
|
|
67
|
+
#define LOCK_EX 2
|
|
68
|
+
#define LOCK_NB 4
|
|
69
|
+
#define LOCK_UN 8
|
|
70
|
+
#endif
|
|
71
|
+
|
|
72
|
+
enum
|
|
73
|
+
{
|
|
74
|
+
FS_OP_FLOCK,
|
|
75
|
+
FS_OP_SEEK,
|
|
76
|
+
FS_OP_STATVFS,
|
|
77
|
+
#ifndef _WIN32
|
|
78
|
+
FS_OP_FCNTL,
|
|
79
|
+
#endif
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
static void EIO_After(uv_work_t *req) {
|
|
83
|
+
Nan::HandleScope scope;
|
|
84
|
+
|
|
85
|
+
store_data_t *store_data = static_cast<store_data_t *>(req->data);
|
|
86
|
+
|
|
87
|
+
// there is always at least one argument. "error"
|
|
88
|
+
int argc = 1;
|
|
89
|
+
|
|
90
|
+
// Allocate space for two args: error plus possible additional result
|
|
91
|
+
Local<Value> argv[2];
|
|
92
|
+
Local<Object> statvfs_result;
|
|
93
|
+
// NOTE: This may need to be changed if something returns a -1
|
|
94
|
+
// for a success, which is possible.
|
|
95
|
+
if (store_data->result == -1) {
|
|
96
|
+
// If the request doesn't have a path parameter set.
|
|
97
|
+
argv[0] = Nan::ErrnoException(store_data->error, "EIO_After", "");
|
|
98
|
+
} else {
|
|
99
|
+
// error value is empty or null for non-error.
|
|
100
|
+
argv[0] = Nan::Null();
|
|
101
|
+
|
|
102
|
+
switch (store_data->fs_op) {
|
|
103
|
+
// These operations have no data to pass other than "error".
|
|
104
|
+
case FS_OP_FLOCK:
|
|
105
|
+
argc = 1;
|
|
106
|
+
break;
|
|
107
|
+
|
|
108
|
+
case FS_OP_SEEK:
|
|
109
|
+
argc = 2;
|
|
110
|
+
argv[1] = Nan::New<Number>(static_cast<double>(store_data->offset));
|
|
111
|
+
break;
|
|
112
|
+
case FS_OP_STATVFS:
|
|
113
|
+
#ifndef _WIN32
|
|
114
|
+
argc = 2;
|
|
115
|
+
statvfs_result = Nan::New<Object>();
|
|
116
|
+
argv[1] = statvfs_result;
|
|
117
|
+
Nan::Set(statvfs_result, Nan::New<String>("f_namemax").ToLocalChecked(), Nan::New<Integer>(static_cast<uint32_t>(store_data->statvfs_buf.f_namemax)));
|
|
118
|
+
Nan::Set(statvfs_result, Nan::New<String>("f_bsize").ToLocalChecked(), Nan::New<Integer>(static_cast<uint32_t>(store_data->statvfs_buf.f_bsize)));
|
|
119
|
+
Nan::Set(statvfs_result, Nan::New<String>("f_frsize").ToLocalChecked(), Nan::New<Integer>(static_cast<uint32_t>(store_data->statvfs_buf.f_frsize)));
|
|
120
|
+
Nan::Set(statvfs_result, Nan::New<String>("f_blocks").ToLocalChecked(), Nan::New<Number>(store_data->statvfs_buf.f_blocks));
|
|
121
|
+
Nan::Set(statvfs_result, Nan::New<String>("f_bavail").ToLocalChecked(), Nan::New<Number>(store_data->statvfs_buf.f_bavail));
|
|
122
|
+
Nan::Set(statvfs_result, Nan::New<String>("f_bfree").ToLocalChecked(), Nan::New<Number>(store_data->statvfs_buf.f_bfree));
|
|
123
|
+
Nan::Set(statvfs_result, Nan::New<String>("f_files").ToLocalChecked(), Nan::New<Number>(store_data->statvfs_buf.f_files));
|
|
124
|
+
Nan::Set(statvfs_result, Nan::New<String>("f_favail").ToLocalChecked(), Nan::New<Number>(store_data->statvfs_buf.f_favail));
|
|
125
|
+
Nan::Set(statvfs_result, Nan::New<String>("f_ffree").ToLocalChecked(), Nan::New<Number>(store_data->statvfs_buf.f_ffree));
|
|
126
|
+
#else
|
|
127
|
+
argc = 1;
|
|
128
|
+
#endif
|
|
129
|
+
break;
|
|
130
|
+
#ifndef _WIN32
|
|
131
|
+
case FS_OP_FCNTL:
|
|
132
|
+
argc = 2;
|
|
133
|
+
argv[1] = Nan::New<Number>(store_data->result);
|
|
134
|
+
break;
|
|
135
|
+
#endif
|
|
136
|
+
default:
|
|
137
|
+
assert(0 && "Unhandled op type value");
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
Nan::TryCatch try_catch;
|
|
142
|
+
|
|
143
|
+
Nan::AsyncResource async_resource("fs-ext:EIO_After");
|
|
144
|
+
store_data->cb->Call(argc, argv, &async_resource);
|
|
145
|
+
|
|
146
|
+
if (try_catch.HasCaught()) {
|
|
147
|
+
Nan::FatalException(try_catch);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// Dispose of the persistent handle
|
|
151
|
+
delete store_data->cb;
|
|
152
|
+
delete store_data;
|
|
153
|
+
delete req;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
static void EIO_StatVFS(uv_work_t *req) {
|
|
157
|
+
store_data_t* statvfs_data = static_cast<store_data_t *>(req->data);
|
|
158
|
+
statvfs_data->result = 0;
|
|
159
|
+
#ifndef _WIN32
|
|
160
|
+
struct statvfs *data = &(statvfs_data->statvfs_buf);
|
|
161
|
+
if (statvfs(statvfs_data->path, data)) {
|
|
162
|
+
statvfs_data->result = -1;
|
|
163
|
+
memset(data, 0, sizeof(struct statvfs));
|
|
164
|
+
};
|
|
165
|
+
#endif
|
|
166
|
+
free(statvfs_data->path);
|
|
167
|
+
;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
#ifdef _WIN32
|
|
171
|
+
static off_t _win32_lseek(int fd, off_t offset, int whence) {
|
|
172
|
+
HANDLE fh;
|
|
173
|
+
LARGE_INTEGER new_offset;
|
|
174
|
+
|
|
175
|
+
fh = (HANDLE)uv_get_osfhandle(fd);
|
|
176
|
+
if (fh == (HANDLE)-1) {
|
|
177
|
+
errno = EBADF;
|
|
178
|
+
return -1;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
DWORD method;
|
|
182
|
+
switch (whence) {
|
|
183
|
+
case SEEK_SET:
|
|
184
|
+
method = FILE_BEGIN;
|
|
185
|
+
break;
|
|
186
|
+
case SEEK_CUR:
|
|
187
|
+
method = FILE_CURRENT;
|
|
188
|
+
break;
|
|
189
|
+
case SEEK_END:
|
|
190
|
+
method = FILE_END;
|
|
191
|
+
break;
|
|
192
|
+
default:
|
|
193
|
+
errno = EINVAL;
|
|
194
|
+
return -1;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
LARGE_INTEGER distance;
|
|
198
|
+
distance.QuadPart = offset;
|
|
199
|
+
|
|
200
|
+
if (SetFilePointerEx(fh, distance, &new_offset, method)) {
|
|
201
|
+
return new_offset.QuadPart;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
errno = EINVAL;
|
|
205
|
+
return -1;
|
|
206
|
+
}
|
|
207
|
+
#endif
|
|
208
|
+
|
|
209
|
+
static void EIO_Seek(uv_work_t *req) {
|
|
210
|
+
store_data_t* seek_data = static_cast<store_data_t *>(req->data);
|
|
211
|
+
|
|
212
|
+
#ifdef _WIN32
|
|
213
|
+
off_t offs = _win32_lseek(seek_data->fd, seek_data->offset, seek_data->oper);
|
|
214
|
+
#else
|
|
215
|
+
off_t offs = lseek(seek_data->fd, seek_data->offset, seek_data->oper);
|
|
216
|
+
#endif
|
|
217
|
+
|
|
218
|
+
if (offs == -1) {
|
|
219
|
+
seek_data->result = -1;
|
|
220
|
+
seek_data->error = errno;
|
|
221
|
+
} else {
|
|
222
|
+
seek_data->offset = offs;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
#ifndef _WIN32
|
|
228
|
+
static void EIO_Fcntl(uv_work_t *req) {
|
|
229
|
+
store_data_t* data = static_cast<store_data_t *>(req->data);
|
|
230
|
+
|
|
231
|
+
struct flock lk;
|
|
232
|
+
lk.l_start = 0;
|
|
233
|
+
lk.l_len = 0;
|
|
234
|
+
lk.l_type = 0;
|
|
235
|
+
lk.l_whence = 0;
|
|
236
|
+
lk.l_pid = 0;
|
|
237
|
+
|
|
238
|
+
int result = -1;
|
|
239
|
+
if (data->oper == F_GETLK || data->oper == F_SETLK || data->oper == F_SETLKW) {
|
|
240
|
+
if (data->oper == F_SETLK || data->oper == F_SETLKW) {
|
|
241
|
+
lk.l_whence = SEEK_SET;
|
|
242
|
+
lk.l_type = data->arg;
|
|
243
|
+
}
|
|
244
|
+
data->result = result = fcntl(data->fd, data->oper, &lk);
|
|
245
|
+
} else {
|
|
246
|
+
data->result = result = fcntl(data->fd, data->oper, data->arg);
|
|
247
|
+
}
|
|
248
|
+
if (result == -1) {
|
|
249
|
+
data->error = errno;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
#endif
|
|
253
|
+
|
|
254
|
+
#ifdef _WIN32
|
|
255
|
+
|
|
256
|
+
static void uv__crt_invalid_parameter_handler(const wchar_t* expression,
|
|
257
|
+
const wchar_t* function, const wchar_t * file, unsigned int line,
|
|
258
|
+
uintptr_t reserved) {
|
|
259
|
+
/* No-op. */
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
#define LK_LEN 0xffff0000
|
|
263
|
+
|
|
264
|
+
static int _win32_flock(int fd, int oper) {
|
|
265
|
+
OVERLAPPED o;
|
|
266
|
+
HANDLE fh;
|
|
267
|
+
|
|
268
|
+
int i = -1;
|
|
269
|
+
|
|
270
|
+
fh = (HANDLE)uv_get_osfhandle(fd);
|
|
271
|
+
if (fh == (HANDLE)-1) {
|
|
272
|
+
errno = EBADF;
|
|
273
|
+
return -1;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
memset(&o, 0, sizeof(o));
|
|
277
|
+
|
|
278
|
+
switch(oper) {
|
|
279
|
+
case LOCK_SH: /* shared lock */
|
|
280
|
+
if (LockFileEx(fh, 0, 0, LK_LEN, 0, &o))
|
|
281
|
+
i = 0;
|
|
282
|
+
break;
|
|
283
|
+
case LOCK_EX: /* exclusive lock */
|
|
284
|
+
if (LockFileEx(fh, LOCKFILE_EXCLUSIVE_LOCK, 0, LK_LEN, 0, &o))
|
|
285
|
+
i = 0;
|
|
286
|
+
break;
|
|
287
|
+
case LOCK_SH|LOCK_NB: /* non-blocking shared lock */
|
|
288
|
+
if (LockFileEx(fh, LOCKFILE_FAIL_IMMEDIATELY, 0, LK_LEN, 0, &o))
|
|
289
|
+
i = 0;
|
|
290
|
+
break;
|
|
291
|
+
case LOCK_EX|LOCK_NB: /* non-blocking exclusive lock */
|
|
292
|
+
if (LockFileEx(fh, LOCKFILE_EXCLUSIVE_LOCK|LOCKFILE_FAIL_IMMEDIATELY,
|
|
293
|
+
0, LK_LEN, 0, &o))
|
|
294
|
+
i = 0;
|
|
295
|
+
break;
|
|
296
|
+
case LOCK_UN: /* unlock lock */
|
|
297
|
+
if (UnlockFileEx(fh, 0, LK_LEN, 0, &o) ||
|
|
298
|
+
GetLastError() == ERROR_NOT_LOCKED)
|
|
299
|
+
i = 0;
|
|
300
|
+
break;
|
|
301
|
+
default: /* unknown */
|
|
302
|
+
errno = EINVAL;
|
|
303
|
+
return -1;
|
|
304
|
+
}
|
|
305
|
+
if (i == -1) {
|
|
306
|
+
if (GetLastError() == ERROR_LOCK_VIOLATION)
|
|
307
|
+
errno = EWOULDBLOCK;
|
|
308
|
+
else
|
|
309
|
+
errno = EINVAL;
|
|
310
|
+
}
|
|
311
|
+
return i;
|
|
312
|
+
}
|
|
313
|
+
#endif
|
|
314
|
+
|
|
315
|
+
static void EIO_Flock(uv_work_t *req) {
|
|
316
|
+
store_data_t* flock_data = static_cast<store_data_t *>(req->data);
|
|
317
|
+
|
|
318
|
+
#ifdef _WIN32
|
|
319
|
+
int i = _win32_flock(flock_data->fd, flock_data->oper);
|
|
320
|
+
#else
|
|
321
|
+
int i = flock(flock_data->fd, flock_data->oper);
|
|
322
|
+
#endif
|
|
323
|
+
|
|
324
|
+
flock_data->result = i;
|
|
325
|
+
flock_data->error = errno;
|
|
326
|
+
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
static NAN_METHOD(Flock) {
|
|
330
|
+
if (info.Length() < 2 || !info[0]->IsInt32() || !info[1]->IsInt32()) {
|
|
331
|
+
return THROW_BAD_ARGS;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
store_data_t* flock_data = new store_data_t();
|
|
335
|
+
|
|
336
|
+
flock_data->fs_op = FS_OP_FLOCK;
|
|
337
|
+
flock_data->fd = info[0].As<v8::Int32>()->Value();
|
|
338
|
+
flock_data->oper = info[1].As<v8::Int32>()->Value();
|
|
339
|
+
|
|
340
|
+
if (info[2]->IsFunction()) {
|
|
341
|
+
flock_data->cb = new Nan::Callback((Local<Function>) info[2].As<Function>());
|
|
342
|
+
uv_work_t *req = new uv_work_t;
|
|
343
|
+
req->data = flock_data;
|
|
344
|
+
uv_queue_work(uv_default_loop(), req, EIO_Flock, (uv_after_work_cb)EIO_After);
|
|
345
|
+
info.GetReturnValue().SetUndefined();
|
|
346
|
+
} else {
|
|
347
|
+
#ifdef _WIN32
|
|
348
|
+
int i = _win32_flock(flock_data->fd, flock_data->oper);
|
|
349
|
+
#else
|
|
350
|
+
int i = flock(flock_data->fd, flock_data->oper);
|
|
351
|
+
#endif
|
|
352
|
+
delete flock_data;
|
|
353
|
+
if (i != 0) return Nan::ThrowError(Nan::ErrnoException(errno, "Flock", ""));
|
|
354
|
+
info.GetReturnValue().SetUndefined();
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
|
|
359
|
+
#ifdef _LARGEFILE_SOURCE
|
|
360
|
+
static inline int IsInt64(double x) {
|
|
361
|
+
return x == static_cast<double>(static_cast<int64_t>(x));
|
|
362
|
+
}
|
|
363
|
+
#endif
|
|
364
|
+
|
|
365
|
+
#ifndef _LARGEFILE_SOURCE
|
|
366
|
+
#define ASSERT_OFFSET(a) \
|
|
367
|
+
if (!(a)->IsUndefined() && !(a)->IsNull() && !(a)->IsInt32()) { \
|
|
368
|
+
return Nan::ThrowTypeError("Not an integer"); \
|
|
369
|
+
}
|
|
370
|
+
#define GET_OFFSET(a) ((a)->IsInt32() ? (a).As<v8::Int32>()->Value() : -1)
|
|
371
|
+
#else
|
|
372
|
+
#define ASSERT_OFFSET(a) \
|
|
373
|
+
if (!(a)->IsUndefined() && !(a)->IsNull() && !((a)->IsNumber() && IsInt64((a).As<v8::Number>()->Value()))) { \
|
|
374
|
+
return Nan::ThrowTypeError("Not an integer"); \
|
|
375
|
+
}
|
|
376
|
+
#define GET_OFFSET(a) ((a)->IsNumber() ? static_cast<int64_t>((a).As<v8::Number>()->Value()) : -1)
|
|
377
|
+
#endif
|
|
378
|
+
|
|
379
|
+
// fs.seek(fd, position, whence [, callback] )
|
|
380
|
+
|
|
381
|
+
static NAN_METHOD(Seek) {
|
|
382
|
+
if (info.Length() < 3 ||
|
|
383
|
+
!info[0]->IsInt32() ||
|
|
384
|
+
!info[2]->IsInt32()) {
|
|
385
|
+
return THROW_BAD_ARGS;
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
int fd = info[0].As<v8::Int32>()->Value();
|
|
389
|
+
ASSERT_OFFSET(info[1]);
|
|
390
|
+
off_t offs = GET_OFFSET(info[1]);
|
|
391
|
+
int whence = info[2].As<v8::Int32>()->Value();
|
|
392
|
+
|
|
393
|
+
if ( ! info[3]->IsFunction()) {
|
|
394
|
+
#ifdef _WIN32
|
|
395
|
+
off_t offs_result = _win32_lseek(fd, offs, whence);
|
|
396
|
+
#else
|
|
397
|
+
off_t offs_result = lseek(fd, offs, whence);
|
|
398
|
+
#endif
|
|
399
|
+
if (offs_result == -1) return Nan::ThrowError(Nan::ErrnoException(errno, "Seek", ""));
|
|
400
|
+
info.GetReturnValue().Set(Nan::New<Number>(static_cast<double>(offs_result)));
|
|
401
|
+
return;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
store_data_t* seek_data = new store_data_t();
|
|
405
|
+
|
|
406
|
+
seek_data->cb = new Nan::Callback((Local<Function>) info[3].As<Function>());
|
|
407
|
+
seek_data->fs_op = FS_OP_SEEK;
|
|
408
|
+
seek_data->fd = fd;
|
|
409
|
+
seek_data->offset = offs;
|
|
410
|
+
seek_data->oper = whence;
|
|
411
|
+
|
|
412
|
+
uv_work_t *req = new uv_work_t;
|
|
413
|
+
req->data = seek_data;
|
|
414
|
+
uv_queue_work(uv_default_loop(), req, EIO_Seek, (uv_after_work_cb)EIO_After);
|
|
415
|
+
|
|
416
|
+
info.GetReturnValue().SetUndefined();
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
// fs.fcntl(fd, cmd, [arg])
|
|
420
|
+
|
|
421
|
+
#ifndef _WIN32
|
|
422
|
+
static NAN_METHOD(Fcntl) {
|
|
423
|
+
if (info.Length() < 3 ||
|
|
424
|
+
!info[0]->IsInt32() ||
|
|
425
|
+
!info[1]->IsInt32() ||
|
|
426
|
+
!info[2]->IsInt32()) {
|
|
427
|
+
return THROW_BAD_ARGS;
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
int fd = info[0].As<v8::Int32>()->Value();
|
|
431
|
+
int cmd = info[1].As<v8::Int32>()->Value();
|
|
432
|
+
int arg = info[2].As<v8::Int32>()->Value();
|
|
433
|
+
|
|
434
|
+
if ( ! info[3]->IsFunction()) {
|
|
435
|
+
int result = fcntl(fd, cmd, arg);
|
|
436
|
+
if (result == -1) return Nan::ThrowError(Nan::ErrnoException(errno, "Fcntl", ""));
|
|
437
|
+
info.GetReturnValue().Set(Nan::New<Number>(result));
|
|
438
|
+
return;
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
store_data_t* data = new store_data_t();
|
|
442
|
+
|
|
443
|
+
data->cb = new Nan::Callback((Local<Function>) info[3].As<Function>());
|
|
444
|
+
data->fs_op = FS_OP_FCNTL;
|
|
445
|
+
data->fd = fd;
|
|
446
|
+
data->oper = cmd;
|
|
447
|
+
data->arg = arg;
|
|
448
|
+
|
|
449
|
+
uv_work_t *req = new uv_work_t;
|
|
450
|
+
req->data = data;
|
|
451
|
+
uv_queue_work(uv_default_loop(), req, EIO_Fcntl, (uv_after_work_cb)EIO_After);
|
|
452
|
+
|
|
453
|
+
info.GetReturnValue().SetUndefined();
|
|
454
|
+
}
|
|
455
|
+
#endif
|
|
456
|
+
|
|
457
|
+
// Wrapper for statvfs(2).
|
|
458
|
+
// fs.statVFS( path, [callback] )
|
|
459
|
+
|
|
460
|
+
static NAN_METHOD(StatVFS) {
|
|
461
|
+
if (info.Length() < 1 ||
|
|
462
|
+
!info[0]->IsString() ) {
|
|
463
|
+
return THROW_BAD_ARGS;
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
Nan::Utf8String path(info[0]);
|
|
467
|
+
|
|
468
|
+
// Synchronous call needs much less work
|
|
469
|
+
if (!info[1]->IsFunction()) {
|
|
470
|
+
#ifndef _WIN32
|
|
471
|
+
struct statvfs buf;
|
|
472
|
+
int ret = statvfs(*path, &buf);
|
|
473
|
+
if (ret != 0) return Nan::ThrowError(Nan::ErrnoException(errno, "statvfs", "", *path));
|
|
474
|
+
Local<Object> result = Nan::New<Object>();
|
|
475
|
+
Nan::Set(result, Nan::New<String>("f_namemax").ToLocalChecked(), Nan::New<Integer>(static_cast<uint32_t>(buf.f_namemax)));
|
|
476
|
+
Nan::Set(result, Nan::New<String>("f_bsize").ToLocalChecked(), Nan::New<Integer>(static_cast<uint32_t>(buf.f_bsize)));
|
|
477
|
+
Nan::Set(result, Nan::New<String>("f_frsize").ToLocalChecked(), Nan::New<Integer>(static_cast<uint32_t>(buf.f_frsize)));
|
|
478
|
+
|
|
479
|
+
Nan::Set(result, Nan::New<String>("f_blocks").ToLocalChecked(), Nan::New<Number>(buf.f_blocks));
|
|
480
|
+
Nan::Set(result, Nan::New<String>("f_bavail").ToLocalChecked(), Nan::New<Number>(buf.f_bavail));
|
|
481
|
+
Nan::Set(result, Nan::New<String>("f_bfree").ToLocalChecked(), Nan::New<Number>(buf.f_bfree));
|
|
482
|
+
|
|
483
|
+
Nan::Set(result, Nan::New<String>("f_files").ToLocalChecked(), Nan::New<Number>(buf.f_files));
|
|
484
|
+
Nan::Set(result, Nan::New<String>("f_favail").ToLocalChecked(), Nan::New<Number>(buf.f_favail));
|
|
485
|
+
Nan::Set(result, Nan::New<String>("f_ffree").ToLocalChecked(), Nan::New<Number>(buf.f_ffree));
|
|
486
|
+
info.GetReturnValue().Set(result);
|
|
487
|
+
#else
|
|
488
|
+
info.GetReturnValue().SetUndefined();
|
|
489
|
+
#endif
|
|
490
|
+
return;
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
store_data_t* statvfs_data = new store_data_t();
|
|
494
|
+
|
|
495
|
+
statvfs_data->cb = new Nan::Callback((Local<Function>) info[1].As<Function>());
|
|
496
|
+
statvfs_data->fs_op = FS_OP_STATVFS;
|
|
497
|
+
statvfs_data->path = strdup(*path);
|
|
498
|
+
|
|
499
|
+
uv_work_t *req = new uv_work_t;
|
|
500
|
+
req->data = statvfs_data;
|
|
501
|
+
uv_queue_work(uv_default_loop(), req, EIO_StatVFS,(uv_after_work_cb)EIO_After);
|
|
502
|
+
|
|
503
|
+
info.GetReturnValue().SetUndefined();
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
extern "C"
|
|
507
|
+
NAN_MODULE_INIT(init)
|
|
508
|
+
{
|
|
509
|
+
Nan::HandleScope scope;
|
|
510
|
+
|
|
511
|
+
#ifdef _WIN32
|
|
512
|
+
_set_invalid_parameter_handler(uv__crt_invalid_parameter_handler);
|
|
513
|
+
#endif
|
|
514
|
+
|
|
515
|
+
v8::Local<v8::Object> constants = Nan::New<v8::Object>();
|
|
516
|
+
|
|
517
|
+
#ifdef SEEK_SET
|
|
518
|
+
NODE_DEFINE_CONSTANT(constants, SEEK_SET);
|
|
519
|
+
#endif
|
|
520
|
+
|
|
521
|
+
#ifdef SEEK_CUR
|
|
522
|
+
NODE_DEFINE_CONSTANT(constants, SEEK_CUR);
|
|
523
|
+
#endif
|
|
524
|
+
|
|
525
|
+
#ifdef SEEK_END
|
|
526
|
+
NODE_DEFINE_CONSTANT(constants, SEEK_END);
|
|
527
|
+
#endif
|
|
528
|
+
|
|
529
|
+
#ifdef LOCK_SH
|
|
530
|
+
NODE_DEFINE_CONSTANT(constants, LOCK_SH);
|
|
531
|
+
#endif
|
|
532
|
+
|
|
533
|
+
#ifdef LOCK_EX
|
|
534
|
+
NODE_DEFINE_CONSTANT(constants, LOCK_EX);
|
|
535
|
+
#endif
|
|
536
|
+
|
|
537
|
+
#ifdef LOCK_NB
|
|
538
|
+
NODE_DEFINE_CONSTANT(constants, LOCK_NB);
|
|
539
|
+
#endif
|
|
540
|
+
|
|
541
|
+
#ifdef LOCK_UN
|
|
542
|
+
NODE_DEFINE_CONSTANT(constants, LOCK_UN);
|
|
543
|
+
#endif
|
|
544
|
+
|
|
545
|
+
#ifdef F_GETFD
|
|
546
|
+
NODE_DEFINE_CONSTANT(constants, F_GETFD);
|
|
547
|
+
#endif
|
|
548
|
+
|
|
549
|
+
#ifdef F_SETFD
|
|
550
|
+
NODE_DEFINE_CONSTANT(constants, F_SETFD);
|
|
551
|
+
#endif
|
|
552
|
+
|
|
553
|
+
#ifdef FD_CLOEXEC
|
|
554
|
+
NODE_DEFINE_CONSTANT(constants, FD_CLOEXEC);
|
|
555
|
+
#endif
|
|
556
|
+
|
|
557
|
+
#ifdef F_RDLCK
|
|
558
|
+
NODE_DEFINE_CONSTANT(constants, F_RDLCK);
|
|
559
|
+
#endif
|
|
560
|
+
|
|
561
|
+
#ifdef F_WRLCK
|
|
562
|
+
NODE_DEFINE_CONSTANT(constants, F_WRLCK);
|
|
563
|
+
#endif
|
|
564
|
+
|
|
565
|
+
#ifdef F_UNLCK
|
|
566
|
+
NODE_DEFINE_CONSTANT(constants, F_UNLCK);
|
|
567
|
+
#endif
|
|
568
|
+
|
|
569
|
+
#ifdef F_SETLK
|
|
570
|
+
NODE_DEFINE_CONSTANT(constants, F_SETLK);
|
|
571
|
+
#endif
|
|
572
|
+
|
|
573
|
+
#ifdef F_GETLK
|
|
574
|
+
NODE_DEFINE_CONSTANT(constants, F_GETLK);
|
|
575
|
+
#endif
|
|
576
|
+
|
|
577
|
+
#ifdef F_SETLKW
|
|
578
|
+
NODE_DEFINE_CONSTANT(constants, F_SETLKW);
|
|
579
|
+
#endif
|
|
580
|
+
|
|
581
|
+
Nan::Set(target, Nan::New("constants").ToLocalChecked(), constants);
|
|
582
|
+
|
|
583
|
+
Export(target, "seek", Seek);
|
|
584
|
+
#ifndef _WIN32
|
|
585
|
+
Export(target, "fcntl", Fcntl);
|
|
586
|
+
#endif
|
|
587
|
+
Export(target, "flock", Flock);
|
|
588
|
+
Export(target, "statVFS", StatVFS);
|
|
589
|
+
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
#if NODE_MODULE_VERSION > 1
|
|
593
|
+
NODE_MODULE_INIT() {
|
|
594
|
+
init(exports);
|
|
595
|
+
}
|
|
596
|
+
#endif
|
package/index.cjs
ADDED
package/index.d.ts
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "thesidedoor-flock",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "Native operating-system file locking for Sidedoor file-backed state",
|
|
5
|
+
"author": "Andres Romero <me@afromero.co> (https://afromero.co)",
|
|
6
|
+
"homepage": "https://github.com/affromero/sidedoor#readme",
|
|
7
|
+
"bugs": {
|
|
8
|
+
"url": "https://github.com/affromero/sidedoor/issues"
|
|
9
|
+
},
|
|
10
|
+
"keywords": [
|
|
11
|
+
"file-locking",
|
|
12
|
+
"flock",
|
|
13
|
+
"native-addon",
|
|
14
|
+
"self-hosted",
|
|
15
|
+
"nodejs"
|
|
16
|
+
],
|
|
17
|
+
"license": "MIT",
|
|
18
|
+
"repository": {
|
|
19
|
+
"type": "git",
|
|
20
|
+
"url": "git+https://github.com/affromero/sidedoor.git",
|
|
21
|
+
"directory": "packages/flock"
|
|
22
|
+
},
|
|
23
|
+
"main": "index.cjs",
|
|
24
|
+
"types": "index.d.ts",
|
|
25
|
+
"engines": {
|
|
26
|
+
"node": ">=22"
|
|
27
|
+
},
|
|
28
|
+
"files": [
|
|
29
|
+
"fs-ext.cc",
|
|
30
|
+
"binding.gyp",
|
|
31
|
+
"index.cjs",
|
|
32
|
+
"index.d.ts",
|
|
33
|
+
"LICENSE",
|
|
34
|
+
"README.md"
|
|
35
|
+
],
|
|
36
|
+
"scripts": {
|
|
37
|
+
"install": "node-gyp rebuild"
|
|
38
|
+
},
|
|
39
|
+
"dependencies": {
|
|
40
|
+
"nan": "2.28.0"
|
|
41
|
+
}
|
|
42
|
+
}
|