55#include " stream_base-inl.h"
66#include " util-inl.h"
77
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+
819using v8::Array;
920using v8::Boolean;
1021using v8::Context;
@@ -16,8 +27,11 @@ using v8::Global;
1627using v8::HandleScope;
1728using v8::HeapSnapshot;
1829using v8::Isolate;
30+ using v8::JustVoid;
1931using v8::Local;
32+ using v8::Maybe;
2033using v8::MaybeLocal;
34+ using v8::Nothing;
2135using v8::Number;
2236using v8::Object;
2337using v8::ObjectTemplate;
@@ -206,26 +220,44 @@ void BuildEmbedderGraph(const FunctionCallbackInfo<Value>& args) {
206220namespace {
207221class FileOutputStream : public v8 ::OutputStream {
208222 public:
209- explicit FileOutputStream (FILE* stream ) : stream_(stream ) {}
223+ FileOutputStream (const int fd, uv_fs_t * req ) : fd_(fd), req_(req ) {}
210224
211225 int GetChunkSize () override {
212226 return 65536 ; // big chunks == faster
213227 }
214228
215229 void EndOfStream () override {}
216230
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 ;
225253 }
226254
255+ int status () const { return status_; }
256+
227257 private:
228- FILE* stream_;
258+ const int fd_;
259+ uv_fs_t * req_;
260+ int status_ = 0 ;
229261};
230262
231263class HeapSnapshotStream : public AsyncWrap ,
@@ -316,19 +348,37 @@ inline void TakeSnapshot(Environment* env, v8::OutputStream* out) {
316348
317349} // namespace
318350
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 >();
324365 }
325- FileOutputStream stream (fp);
366+
367+ FileOutputStream stream (fd, &req);
326368 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 >() ;
330372 }
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 ();
332382}
333383
334384void DeleteHeapSnapshot (const HeapSnapshot* snapshot) {
@@ -379,7 +429,7 @@ void TriggerHeapSnapshot(const FunctionCallbackInfo<Value>& args) {
379429
380430 if (filename_v->IsUndefined ()) {
381431 DiagnosticFilename name (env, " Heap" , " heapsnapshot" );
382- if (! WriteSnapshot (env, *name))
432+ if (WriteSnapshot (env, *name). IsNothing ( ))
383433 return ;
384434 if (String::NewFromUtf8 (isolate, *name).ToLocal (&filename_v)) {
385435 args.GetReturnValue ().Set (filename_v);
@@ -389,7 +439,7 @@ void TriggerHeapSnapshot(const FunctionCallbackInfo<Value>& args) {
389439
390440 BufferValue path (isolate, filename_v);
391441 CHECK_NOT_NULL (*path);
392- if (! WriteSnapshot (env, *path))
442+ if (WriteSnapshot (env, *path). IsNothing ( ))
393443 return ;
394444 return args.GetReturnValue ().Set (filename_v);
395445}
0 commit comments