5
5
#include " stream_base-inl.h"
6
6
#include " util-inl.h"
7
7
8
+ // Copied from https://github.com/nodejs/node/blob/b07dc4d19fdbc15b4f76557dc45b3ce3a43ad0c3/src/util.cc#L36-L41.
9
+ #ifdef _WIN32
10
+ #include < io.h> // _S_IREAD _S_IWRITE
11
+ #ifndef S_IRUSR
12
+ #define S_IRUSR _S_IREAD
13
+ #endif // S_IRUSR
14
+ #ifndef S_IWUSR
15
+ #define S_IWUSR _S_IWRITE
16
+ #endif // S_IWUSR
17
+ #endif
18
+
8
19
using v8::Array;
9
20
using v8::Boolean ;
10
21
using v8::Context;
@@ -16,8 +27,11 @@ using v8::Global;
16
27
using v8::HandleScope;
17
28
using v8::HeapSnapshot;
18
29
using v8::Isolate;
30
+ using v8::JustVoid;
19
31
using v8::Local;
32
+ using v8::Maybe;
20
33
using v8::MaybeLocal;
34
+ using v8::Nothing;
21
35
using v8::Number;
22
36
using v8::Object;
23
37
using v8::ObjectTemplate;
@@ -206,26 +220,44 @@ void BuildEmbedderGraph(const FunctionCallbackInfo<Value>& args) {
206
220
namespace {
207
221
class FileOutputStream : public v8 ::OutputStream {
208
222
public:
209
- explicit FileOutputStream (FILE* stream ) : stream_(stream ) {}
223
+ FileOutputStream (const int fd, uv_fs_t * req ) : fd_(fd), req_(req ) {}
210
224
211
225
int GetChunkSize () override {
212
226
return 65536 ; // big chunks == faster
213
227
}
214
228
215
229
void EndOfStream () override {}
216
230
217
- WriteResult WriteAsciiChunk (char * data, int size) override {
218
- const size_t len = static_cast <size_t >(size);
219
- size_t off = 0 ;
220
-
221
- while (off < len && !feof (stream_) && !ferror (stream_))
222
- off += fwrite (data + off, 1 , len - off, stream_);
223
-
224
- return off == len ? kContinue : kAbort ;
231
+ WriteResult WriteAsciiChunk (char * data, const int size) override {
232
+ DCHECK_EQ (status_, 0 );
233
+ int offset = 0 ;
234
+ while (offset < size) {
235
+ const uv_buf_t buf = uv_buf_init (data + offset, size - offset);
236
+ const int num_bytes_written = uv_fs_write (nullptr ,
237
+ req_,
238
+ fd_,
239
+ &buf,
240
+ 1 ,
241
+ -1 ,
242
+ nullptr );
243
+ uv_fs_req_cleanup (req_);
244
+ if (num_bytes_written < 0 ) {
245
+ status_ = num_bytes_written;
246
+ return kAbort ;
247
+ }
248
+ DCHECK_LE (num_bytes_written, buf.len );
249
+ offset += num_bytes_written;
250
+ }
251
+ DCHECK_EQ (offset, size);
252
+ return kContinue ;
225
253
}
226
254
255
+ int status () const { return status_; }
256
+
227
257
private:
228
- FILE* stream_;
258
+ const int fd_;
259
+ uv_fs_t * req_;
260
+ int status_ = 0 ;
229
261
};
230
262
231
263
class HeapSnapshotStream : public AsyncWrap ,
@@ -316,19 +348,37 @@ inline void TakeSnapshot(Environment* env, v8::OutputStream* out) {
316
348
317
349
} // namespace
318
350
319
- bool WriteSnapshot (Environment* env, const char * filename) {
320
- FILE* fp = fopen (filename, " w" );
321
- if (fp == nullptr ) {
322
- env->ThrowErrnoException (errno, " open" );
323
- return false ;
351
+ Maybe<void > WriteSnapshot (Environment* env, const char * filename) {
352
+ uv_fs_t req;
353
+ int err;
354
+
355
+ const int fd = uv_fs_open (nullptr ,
356
+ &req,
357
+ filename,
358
+ O_WRONLY | O_CREAT | O_TRUNC,
359
+ S_IWUSR | S_IRUSR,
360
+ nullptr );
361
+ uv_fs_req_cleanup (&req);
362
+ if ((err = fd) < 0 ) {
363
+ env->ThrowUVException (err, " open" , nullptr , filename);
364
+ return Nothing<void >();
324
365
}
325
- FileOutputStream stream (fp);
366
+
367
+ FileOutputStream stream (fd, &req);
326
368
TakeSnapshot (env, &stream);
327
- if (fclose (fp) == EOF ) {
328
- env->ThrowErrnoException (errno , " close " );
329
- return false ;
369
+ if ((err = stream. status ()) < 0 ) {
370
+ env->ThrowUVException (err , " write " , nullptr , filename );
371
+ return Nothing< void >() ;
330
372
}
331
- return true ;
373
+
374
+ err = uv_fs_close (nullptr , &req, fd, nullptr );
375
+ uv_fs_req_cleanup (&req);
376
+ if (err < 0 ) {
377
+ env->ThrowUVException (err, " close" , nullptr , filename);
378
+ return Nothing<void >();
379
+ }
380
+
381
+ return JustVoid ();
332
382
}
333
383
334
384
void DeleteHeapSnapshot (const HeapSnapshot* snapshot) {
@@ -379,7 +429,7 @@ void TriggerHeapSnapshot(const FunctionCallbackInfo<Value>& args) {
379
429
380
430
if (filename_v->IsUndefined ()) {
381
431
DiagnosticFilename name (env, " Heap" , " heapsnapshot" );
382
- if (! WriteSnapshot (env, *name))
432
+ if (WriteSnapshot (env, *name). IsNothing ( ))
383
433
return ;
384
434
if (String::NewFromUtf8 (isolate, *name).ToLocal (&filename_v)) {
385
435
args.GetReturnValue ().Set (filename_v);
@@ -389,7 +439,7 @@ void TriggerHeapSnapshot(const FunctionCallbackInfo<Value>& args) {
389
439
390
440
BufferValue path (isolate, filename_v);
391
441
CHECK_NOT_NULL (*path);
392
- if (! WriteSnapshot (env, *path))
442
+ if (WriteSnapshot (env, *path). IsNothing ( ))
393
443
return ;
394
444
return args.GetReturnValue ().Set (filename_v);
395
445
}
0 commit comments