@@ -14,6 +14,8 @@ const {
14
14
MathMin,
15
15
NumberIsSafeInteger,
16
16
Symbol,
17
+ Error,
18
+ Promise,
17
19
} = primordials ;
18
20
19
21
const {
@@ -64,6 +66,11 @@ const { promisify } = require('internal/util');
64
66
65
67
const kHandle = Symbol ( 'kHandle' ) ;
66
68
const kFd = Symbol ( 'kFd' ) ;
69
+ const kRefs = Symbol ( 'kRefs' ) ;
70
+ const kClosePromise = Symbol ( 'kClosePromise' ) ;
71
+ const kCloseResolve = Symbol ( 'kCloseResolve' ) ;
72
+ const kCloseReject = Symbol ( 'kCloseReject' ) ;
73
+
67
74
const { kUsePromises } = binding ;
68
75
const {
69
76
JSTransferable, kDeserialize, kTransfer, kTransferList
@@ -76,6 +83,9 @@ class FileHandle extends JSTransferable {
76
83
super ( ) ;
77
84
this [ kHandle ] = filehandle ;
78
85
this [ kFd ] = filehandle ? filehandle . fd : - 1 ;
86
+
87
+ this [ kRefs ] = 1 ;
88
+ this [ kClosePromise ] = null ;
79
89
}
80
90
81
91
getAsyncId ( ) {
@@ -87,70 +97,101 @@ class FileHandle extends JSTransferable {
87
97
}
88
98
89
99
appendFile ( data , options ) {
90
- return writeFile ( this , data , options ) ;
100
+ return fsCall ( writeFile , this , data , options ) ;
91
101
}
92
102
93
103
chmod ( mode ) {
94
- return fchmod ( this , mode ) ;
104
+ return fsCall ( fchmod , this , mode ) ;
95
105
}
96
106
97
107
chown ( uid , gid ) {
98
- return fchown ( this , uid , gid ) ;
108
+ return fsCall ( fchown , this , uid , gid ) ;
99
109
}
100
110
101
111
datasync ( ) {
102
- return fdatasync ( this ) ;
112
+ return fsCall ( fdatasync , this ) ;
103
113
}
104
114
105
115
sync ( ) {
106
- return fsync ( this ) ;
116
+ return fsCall ( fsync , this ) ;
107
117
}
108
118
109
119
read ( buffer , offset , length , position ) {
110
- return read ( this , buffer , offset , length , position ) ;
120
+ return fsCall ( read , this , buffer , offset , length , position ) ;
111
121
}
112
122
113
123
readv ( buffers , position ) {
114
- return readv ( this , buffers , position ) ;
124
+ return fsCall ( readv , this , buffers , position ) ;
115
125
}
116
126
117
127
readFile ( options ) {
118
- return readFile ( this , options ) ;
128
+ return fsCall ( readFile , this , options ) ;
119
129
}
120
130
121
131
stat ( options ) {
122
- return fstat ( this , options ) ;
132
+ return fsCall ( fstat , this , options ) ;
123
133
}
124
134
125
135
truncate ( len = 0 ) {
126
- return ftruncate ( this , len ) ;
136
+ return fsCall ( ftruncate , this , len ) ;
127
137
}
128
138
129
139
utimes ( atime , mtime ) {
130
- return futimes ( this , atime , mtime ) ;
140
+ return fsCall ( futimes , this , atime , mtime ) ;
131
141
}
132
142
133
143
write ( buffer , offset , length , position ) {
134
- return write ( this , buffer , offset , length , position ) ;
144
+ return fsCall ( write , this , buffer , offset , length , position ) ;
135
145
}
136
146
137
147
writev ( buffers , position ) {
138
- return writev ( this , buffers , position ) ;
148
+ return fsCall ( writev , this , buffers , position ) ;
139
149
}
140
150
141
151
writeFile ( data , options ) {
142
- return writeFile ( this , data , options ) ;
152
+ return fsCall ( writeFile , this , data , options ) ;
143
153
}
144
154
145
155
close = ( ) => {
146
- this [ kFd ] = - 1 ;
147
- return this [ kHandle ] . close ( ) ;
156
+ if ( this [ kFd ] === - 1 ) {
157
+ return Promise . resolve ( ) ;
158
+ }
159
+
160
+ if ( this [ kClosePromise ] ) {
161
+ return this [ kClosePromise ] ;
162
+ }
163
+
164
+ this [ kRefs ] -- ;
165
+ if ( this [ kRefs ] === 0 ) {
166
+ this [ kFd ] = - 1 ;
167
+ this [ kClosePromise ] = this [ kHandle ] . close ( ) . finally ( ( ) => {
168
+ this [ kClosePromise ] = undefined ;
169
+ } ) ;
170
+ } else {
171
+ this [ kClosePromise ] = new Promise ( ( resolve , reject ) => {
172
+ this [ kCloseResolve ] = resolve ;
173
+ this [ kCloseReject ] = reject ;
174
+ } ) . finally ( ( ) => {
175
+ this [ kClosePromise ] = undefined ;
176
+ this [ kCloseReject ] = undefined ;
177
+ this [ kCloseResolve ] = undefined ;
178
+ } ) ;
179
+ }
180
+
181
+ return this [ kClosePromise ] ;
148
182
}
149
183
150
184
[ kTransfer ] ( ) {
185
+ if ( this [ kClosePromise ] || this [ kRefs ] > 1 ) {
186
+ const DOMException = internalBinding ( 'messaging' ) . DOMException ;
187
+ throw new DOMException ( 'Cannot transfer FileHandle while in use' ,
188
+ 'DataCloneError' ) ;
189
+ }
190
+
151
191
const handle = this [ kHandle ] ;
152
192
this [ kFd ] = - 1 ;
153
193
this [ kHandle ] = null ;
194
+ this [ kRefs ] = 0 ;
154
195
155
196
return {
156
197
data : { handle } ,
@@ -168,9 +209,31 @@ class FileHandle extends JSTransferable {
168
209
}
169
210
}
170
211
171
- function validateFileHandle ( handle ) {
172
- if ( ! ( handle instanceof FileHandle ) )
212
+ async function fsCall ( fn , handle , ... args ) {
213
+ if ( handle [ kRefs ] === undefined ) {
173
214
throw new ERR_INVALID_ARG_TYPE ( 'filehandle' , 'FileHandle' , handle ) ;
215
+ }
216
+
217
+ if ( handle . fd === - 1 ) {
218
+ // eslint-disable-next-line no-restricted-syntax
219
+ const err = new Error ( 'file closed' ) ;
220
+ err . code = 'EBADF' ;
221
+ err . syscall = fn . name ;
222
+ throw err ;
223
+ }
224
+
225
+ try {
226
+ handle [ kRefs ] ++ ;
227
+ return await fn ( handle , ...args ) ;
228
+ } finally {
229
+ handle [ kRefs ] -- ;
230
+ if ( handle [ kRefs ] === 0 ) {
231
+ handle [ kFd ] = - 1 ;
232
+ handle [ kHandle ]
233
+ . close ( )
234
+ . then ( handle [ kCloseResolve ] , handle [ kCloseReject ] ) ;
235
+ }
236
+ }
174
237
}
175
238
176
239
async function writeFileHandle ( filehandle , data ) {
@@ -249,7 +312,6 @@ async function open(path, flags, mode) {
249
312
}
250
313
251
314
async function read ( handle , buffer , offset , length , position ) {
252
- validateFileHandle ( handle ) ;
253
315
validateBuffer ( buffer ) ;
254
316
255
317
if ( offset == null ) {
@@ -280,7 +342,6 @@ async function read(handle, buffer, offset, length, position) {
280
342
}
281
343
282
344
async function readv ( handle , buffers , position ) {
283
- validateFileHandle ( handle ) ;
284
345
validateBufferArray ( buffers ) ;
285
346
286
347
if ( typeof position !== 'number' )
@@ -292,8 +353,6 @@ async function readv(handle, buffers, position) {
292
353
}
293
354
294
355
async function write ( handle , buffer , offset , length , position ) {
295
- validateFileHandle ( handle ) ;
296
-
297
356
if ( buffer . length === 0 )
298
357
return { bytesWritten : 0 , buffer } ;
299
358
@@ -321,7 +380,6 @@ async function write(handle, buffer, offset, length, position) {
321
380
}
322
381
323
382
async function writev ( handle , buffers , position ) {
324
- validateFileHandle ( handle ) ;
325
383
validateBufferArray ( buffers ) ;
326
384
327
385
if ( typeof position !== 'number' )
@@ -346,7 +404,6 @@ async function truncate(path, len = 0) {
346
404
}
347
405
348
406
async function ftruncate ( handle , len = 0 ) {
349
- validateFileHandle ( handle ) ;
350
407
validateInteger ( len , 'len' ) ;
351
408
len = MathMax ( 0 , len ) ;
352
409
return binding . ftruncate ( handle . fd , len , kUsePromises ) ;
@@ -364,12 +421,10 @@ async function rmdir(path, options) {
364
421
}
365
422
366
423
async function fdatasync ( handle ) {
367
- validateFileHandle ( handle ) ;
368
424
return binding . fdatasync ( handle . fd , kUsePromises ) ;
369
425
}
370
426
371
427
async function fsync ( handle ) {
372
- validateFileHandle ( handle ) ;
373
428
return binding . fsync ( handle . fd , kUsePromises ) ;
374
429
}
375
430
@@ -420,7 +475,6 @@ async function symlink(target, path, type_) {
420
475
}
421
476
422
477
async function fstat ( handle , options = { bigint : false } ) {
423
- validateFileHandle ( handle ) ;
424
478
const result = await binding . fstat ( handle . fd , options . bigint , kUsePromises ) ;
425
479
return getStatsFromBinding ( result ) ;
426
480
}
@@ -453,7 +507,6 @@ async function unlink(path) {
453
507
}
454
508
455
509
async function fchmod ( handle , mode ) {
456
- validateFileHandle ( handle ) ;
457
510
mode = parseFileMode ( mode , 'mode' ) ;
458
511
return binding . fchmod ( handle . fd , mode , kUsePromises ) ;
459
512
}
@@ -481,7 +534,6 @@ async function lchown(path, uid, gid) {
481
534
}
482
535
483
536
async function fchown ( handle , uid , gid ) {
484
- validateFileHandle ( handle ) ;
485
537
validateUint32 ( uid , 'uid' ) ;
486
538
validateUint32 ( gid , 'gid' ) ;
487
539
return binding . fchown ( handle . fd , uid , gid , kUsePromises ) ;
@@ -504,7 +556,6 @@ async function utimes(path, atime, mtime) {
504
556
}
505
557
506
558
async function futimes ( handle , atime , mtime ) {
507
- validateFileHandle ( handle ) ;
508
559
atime = toUnixTimestamp ( atime , 'atime' ) ;
509
560
mtime = toUnixTimestamp ( mtime , 'mtime' ) ;
510
561
return binding . futimes ( handle . fd , atime , mtime , kUsePromises ) ;
0 commit comments