src: deduplicate CHECK_EQ/CHECK_NE macros
[platform/upstream/nodejs.git] / src / node_file.cc
1 // Copyright Joyent, Inc. and other Node contributors.
2 //
3 // Permission is hereby granted, free of charge, to any person obtaining a
4 // copy of this software and associated documentation files (the
5 // "Software"), to deal in the Software without restriction, including
6 // without limitation the rights to use, copy, modify, merge, publish,
7 // distribute, sublicense, and/or sell copies of the Software, and to permit
8 // persons to whom the Software is furnished to do so, subject to the
9 // following conditions:
10 //
11 // The above copyright notice and this permission notice shall be included
12 // in all copies or substantial portions of the Software.
13 //
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
17 // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
18 // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19 // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
20 // USE OR OTHER DEALINGS IN THE SOFTWARE.
21
22 #include "node.h"
23 #include "node_file.h"
24 #include "node_buffer.h"
25 #include "node_internals.h"
26 #include "node_stat_watcher.h"
27
28 #include "env.h"
29 #include "env-inl.h"
30 #include "req_wrap.h"
31 #include "string_bytes.h"
32
33 #include <fcntl.h>
34 #include <sys/types.h>
35 #include <sys/stat.h>
36 #include <assert.h>
37 #include <string.h>
38 #include <errno.h>
39 #include <limits.h>
40
41 #if defined(__MINGW32__) || defined(_MSC_VER)
42 # include <io.h>
43 #endif
44
45 namespace node {
46
47 using v8::Array;
48 using v8::Context;
49 using v8::EscapableHandleScope;
50 using v8::Function;
51 using v8::FunctionCallbackInfo;
52 using v8::FunctionTemplate;
53 using v8::Handle;
54 using v8::HandleScope;
55 using v8::Integer;
56 using v8::Local;
57 using v8::Number;
58 using v8::Object;
59 using v8::String;
60 using v8::Value;
61
62 #define MIN(a, b) ((a) < (b) ? (a) : (b))
63
64 #define TYPE_ERROR(msg) env->ThrowTypeError(msg)
65
66 #define THROW_BAD_ARGS TYPE_ERROR("Bad argument")
67
68 class FSReqWrap: public ReqWrap<uv_fs_t> {
69  public:
70   void* operator new(size_t size) { return new char[size]; }
71   void* operator new(size_t size, char* storage) { return storage; }
72
73   FSReqWrap(Environment* env, const char* syscall, char* data = NULL)
74     : ReqWrap<uv_fs_t>(env, Object::New(env->isolate())),
75       syscall_(syscall),
76       data_(data),
77       dest_len_(0) {
78   }
79
80   void ReleaseEarly() {
81     if (data_ == NULL)
82       return;
83     delete[] data_;
84     data_ = NULL;
85   }
86
87   inline const char* syscall() const { return syscall_; }
88   inline const char* dest() const { return dest_; }
89   inline unsigned int dest_len() const { return dest_len_; }
90   inline void dest_len(unsigned int dest_len) { dest_len_ = dest_len; }
91
92  private:
93   const char* syscall_;
94   char* data_;
95   unsigned int dest_len_;
96   char dest_[1];
97 };
98
99
100 #define ASSERT_OFFSET(a) \
101   if (!(a)->IsUndefined() && !(a)->IsNull() && !IsInt64((a)->NumberValue())) { \
102     return env->ThrowTypeError("Not an integer"); \
103   }
104 #define ASSERT_TRUNCATE_LENGTH(a) \
105   if (!(a)->IsUndefined() && !(a)->IsNull() && !IsInt64((a)->NumberValue())) { \
106     return env->ThrowTypeError("Not an integer"); \
107   }
108 #define GET_OFFSET(a) ((a)->IsNumber() ? (a)->IntegerValue() : -1)
109 #define GET_TRUNCATE_LENGTH(a) ((a)->IntegerValue())
110
111 static inline bool IsInt64(double x) {
112   return x == static_cast<double>(static_cast<int64_t>(x));
113 }
114
115
116 static void After(uv_fs_t *req) {
117   FSReqWrap* req_wrap = static_cast<FSReqWrap*>(req->data);
118   assert(&req_wrap->req_ == req);
119   req_wrap->ReleaseEarly();  // Free memory that's no longer used now.
120
121   Environment* env = req_wrap->env();
122   HandleScope handle_scope(env->isolate());
123   Context::Scope context_scope(env->context());
124
125   // there is always at least one argument. "error"
126   int argc = 1;
127
128   // Allocate space for two args. We may only use one depending on the case.
129   // (Feel free to increase this if you need more)
130   Local<Value> argv[2];
131
132   if (req->result < 0) {
133     // If the request doesn't have a path parameter set.
134     if (req->path == NULL) {
135       argv[0] = UVException(req->result, NULL, req_wrap->syscall());
136     } else if ((req->result == UV_EEXIST ||
137                 req->result == UV_ENOTEMPTY ||
138                 req->result == UV_EPERM) &&
139                req_wrap->dest_len() > 0) {
140       argv[0] = UVException(req->result,
141                             NULL,
142                             req_wrap->syscall(),
143                             req_wrap->dest());
144     } else {
145       argv[0] = UVException(req->result,
146                             NULL,
147                             req_wrap->syscall(),
148                             static_cast<const char*>(req->path));
149     }
150   } else {
151     // error value is empty or null for non-error.
152     argv[0] = Null(env->isolate());
153
154     // All have at least two args now.
155     argc = 2;
156
157     switch (req->fs_type) {
158       // These all have no data to pass.
159       case UV_FS_CLOSE:
160       case UV_FS_RENAME:
161       case UV_FS_UNLINK:
162       case UV_FS_RMDIR:
163       case UV_FS_MKDIR:
164       case UV_FS_FTRUNCATE:
165       case UV_FS_FSYNC:
166       case UV_FS_FDATASYNC:
167       case UV_FS_LINK:
168       case UV_FS_SYMLINK:
169       case UV_FS_CHMOD:
170       case UV_FS_FCHMOD:
171       case UV_FS_CHOWN:
172       case UV_FS_FCHOWN:
173         // These, however, don't.
174         argc = 1;
175         break;
176
177       case UV_FS_UTIME:
178       case UV_FS_FUTIME:
179         argc = 0;
180         break;
181
182       case UV_FS_OPEN:
183         argv[1] = Integer::New(env->isolate(), req->result);
184         break;
185
186       case UV_FS_WRITE:
187         argv[1] = Integer::New(env->isolate(), req->result);
188         break;
189
190       case UV_FS_STAT:
191       case UV_FS_LSTAT:
192       case UV_FS_FSTAT:
193         argv[1] = BuildStatsObject(env,
194                                    static_cast<const uv_stat_t*>(req->ptr));
195         break;
196
197       case UV_FS_READLINK:
198         argv[1] = String::NewFromUtf8(env->isolate(),
199                                       static_cast<const char*>(req->ptr));
200         break;
201
202       case UV_FS_READ:
203         // Buffer interface
204         argv[1] = Integer::New(env->isolate(), req->result);
205         break;
206
207       case UV_FS_READDIR:
208         {
209           char *namebuf = static_cast<char*>(req->ptr);
210           int nnames = req->result;
211
212           Local<Array> names = Array::New(env->isolate(), nnames);
213
214           for (int i = 0; i < nnames; i++) {
215             Local<String> name = String::NewFromUtf8(env->isolate(), namebuf);
216             names->Set(i, name);
217 #ifndef NDEBUG
218             namebuf += strlen(namebuf);
219             assert(*namebuf == '\0');
220             namebuf += 1;
221 #else
222             namebuf += strlen(namebuf) + 1;
223 #endif
224           }
225
226           argv[1] = names;
227         }
228         break;
229
230       default:
231         assert(0 && "Unhandled eio response");
232     }
233   }
234
235   req_wrap->MakeCallback(env->oncomplete_string(), argc, argv);
236
237   uv_fs_req_cleanup(&req_wrap->req_);
238   delete req_wrap;
239 }
240
241 // This struct is only used on sync fs calls.
242 // For async calls FSReqWrap is used.
243 struct fs_req_wrap {
244   fs_req_wrap() {}
245   ~fs_req_wrap() { uv_fs_req_cleanup(&req); }
246   // Ensure that copy ctor and assignment operator are not used.
247   fs_req_wrap(const fs_req_wrap& req);
248   fs_req_wrap& operator=(const fs_req_wrap& req);
249   uv_fs_t req;
250 };
251
252
253 #define ASYNC_DEST_CALL(func, callback, dest_path, ...)                       \
254   Environment* env = Environment::GetCurrent(args.GetIsolate());              \
255   FSReqWrap* req_wrap;                                                        \
256   char* dest_str = (dest_path);                                               \
257   int dest_len = dest_str == NULL ? 0 : strlen(dest_str);                     \
258   char* storage = new char[sizeof(*req_wrap) + dest_len];                     \
259   req_wrap = new(storage) FSReqWrap(env, #func);                              \
260   req_wrap->dest_len(dest_len);                                               \
261   if (dest_str != NULL) {                                                     \
262     memcpy(const_cast<char*>(req_wrap->dest()),                               \
263            dest_str,                                                          \
264            dest_len + 1);                                                     \
265   }                                                                           \
266   int err = uv_fs_ ## func(env->event_loop() ,                                \
267                            &req_wrap->req_,                                   \
268                            __VA_ARGS__,                                       \
269                            After);                                            \
270   req_wrap->object()->Set(env->oncomplete_string(), callback);                \
271   req_wrap->Dispatched();                                                     \
272   if (err < 0) {                                                              \
273     uv_fs_t* req = &req_wrap->req_;                                           \
274     req->result = err;                                                        \
275     req->path = NULL;                                                         \
276     After(req);                                                               \
277   }                                                                           \
278   args.GetReturnValue().Set(req_wrap->persistent());
279
280 #define ASYNC_CALL(func, callback, ...)                                       \
281   ASYNC_DEST_CALL(func, callback, NULL, __VA_ARGS__)                          \
282
283 #define SYNC_DEST_CALL(func, path, dest, ...)                                 \
284   fs_req_wrap req_wrap;                                                       \
285   int err = uv_fs_ ## func(env->event_loop(),                                 \
286                          &req_wrap.req,                                       \
287                          __VA_ARGS__,                                         \
288                          NULL);                                               \
289   if (err < 0) {                                                              \
290     if (dest != NULL &&                                                       \
291         (err == UV_EEXIST ||                                                  \
292          err == UV_ENOTEMPTY ||                                               \
293          err == UV_EPERM)) {                                                  \
294       return env->ThrowUVException(err, #func, "", dest);                     \
295     } else {                                                                  \
296       return env->ThrowUVException(err, #func, "", path);                     \
297     }                                                                         \
298   }                                                                           \
299
300 #define SYNC_CALL(func, path, ...)                                            \
301   SYNC_DEST_CALL(func, path, NULL, __VA_ARGS__)                               \
302
303 #define SYNC_REQ req_wrap.req
304
305 #define SYNC_RESULT err
306
307
308 static void Close(const FunctionCallbackInfo<Value>& args) {
309   Environment* env = Environment::GetCurrent(args.GetIsolate());
310   HandleScope scope(env->isolate());
311
312   if (args.Length() < 1 || !args[0]->IsInt32()) {
313     return THROW_BAD_ARGS;
314   }
315
316   int fd = args[0]->Int32Value();
317
318   if (args[1]->IsFunction()) {
319     ASYNC_CALL(close, args[1], fd)
320   } else {
321     SYNC_CALL(close, 0, fd)
322   }
323 }
324
325
326 Local<Object> BuildStatsObject(Environment* env, const uv_stat_t* s) {
327   // If you hit this assertion, you forgot to enter the v8::Context first.
328   assert(env->context() == env->isolate()->GetCurrentContext());
329
330   EscapableHandleScope handle_scope(env->isolate());
331
332   Local<Object> stats = env->stats_constructor_function()->NewInstance();
333   if (stats.IsEmpty()) {
334     return handle_scope.Escape(Local<Object>());
335   }
336
337   // The code below is very nasty-looking but it prevents a segmentation fault
338   // when people run JS code like the snippet below. It's apparently more
339   // common than you would expect, several people have reported this crash...
340   //
341   //   function crash() {
342   //     fs.statSync('.');
343   //     crash();
344   //   }
345   //
346   // We need to check the return value of Integer::New() and Date::New()
347   // and make sure that we bail out when V8 returns an empty handle.
348 #define X(name)                                                               \
349   {                                                                           \
350     Local<Value> val = Integer::New(env->isolate(), s->st_##name);            \
351     if (val.IsEmpty())                                                        \
352       return handle_scope.Escape(Local<Object>());                            \
353     stats->Set(env->name ## _string(), val);                                  \
354   }
355   X(dev)
356   X(mode)
357   X(nlink)
358   X(uid)
359   X(gid)
360   X(rdev)
361 # if defined(__POSIX__)
362   X(blksize)
363 # endif
364 #undef X
365
366 #define X(name)                                                               \
367   {                                                                           \
368     Local<Value> val = Number::New(env->isolate(),                            \
369                                    static_cast<double>(s->st_##name));        \
370     if (val.IsEmpty())                                                        \
371       return handle_scope.Escape(Local<Object>());                            \
372     stats->Set(env->name ## _string(), val);                                  \
373   }
374   X(ino)
375   X(size)
376 # if defined(__POSIX__)
377   X(blocks)
378 # endif
379 #undef X
380
381 #define X(name, rec)                                                          \
382   {                                                                           \
383     double msecs = static_cast<double>(s->st_##rec.tv_sec) * 1000;            \
384     msecs += static_cast<double>(s->st_##rec.tv_nsec / 1000000);              \
385     Local<Value> val = v8::Date::New(env->isolate(), msecs);                  \
386     if (val.IsEmpty())                                                        \
387       return handle_scope.Escape(Local<Object>());                            \
388     stats->Set(env->name ## _string(), val);                                  \
389   }
390   X(atime, atim)
391   X(mtime, mtim)
392   X(ctime, ctim)
393   X(birthtime, birthtim)
394 #undef X
395
396   return handle_scope.Escape(stats);
397 }
398
399 static void Stat(const FunctionCallbackInfo<Value>& args) {
400   Environment* env = Environment::GetCurrent(args.GetIsolate());
401   HandleScope scope(env->isolate());
402
403   if (args.Length() < 1)
404     return TYPE_ERROR("path required");
405   if (!args[0]->IsString())
406     return TYPE_ERROR("path must be a string");
407
408   String::Utf8Value path(args[0]);
409
410   if (args[1]->IsFunction()) {
411     ASYNC_CALL(stat, args[1], *path)
412   } else {
413     SYNC_CALL(stat, *path, *path)
414     args.GetReturnValue().Set(
415         BuildStatsObject(env, static_cast<const uv_stat_t*>(SYNC_REQ.ptr)));
416   }
417 }
418
419 static void LStat(const FunctionCallbackInfo<Value>& args) {
420   Environment* env = Environment::GetCurrent(args.GetIsolate());
421   HandleScope scope(env->isolate());
422
423   if (args.Length() < 1)
424     return TYPE_ERROR("path required");
425   if (!args[0]->IsString())
426     return TYPE_ERROR("path must be a string");
427
428   String::Utf8Value path(args[0]);
429
430   if (args[1]->IsFunction()) {
431     ASYNC_CALL(lstat, args[1], *path)
432   } else {
433     SYNC_CALL(lstat, *path, *path)
434     args.GetReturnValue().Set(
435         BuildStatsObject(env, static_cast<const uv_stat_t*>(SYNC_REQ.ptr)));
436   }
437 }
438
439 static void FStat(const FunctionCallbackInfo<Value>& args) {
440   Environment* env = Environment::GetCurrent(args.GetIsolate());
441   HandleScope scope(env->isolate());
442
443   if (args.Length() < 1 || !args[0]->IsInt32()) {
444     return THROW_BAD_ARGS;
445   }
446
447   int fd = args[0]->Int32Value();
448
449   if (args[1]->IsFunction()) {
450     ASYNC_CALL(fstat, args[1], fd)
451   } else {
452     SYNC_CALL(fstat, 0, fd)
453     args.GetReturnValue().Set(
454         BuildStatsObject(env, static_cast<const uv_stat_t*>(SYNC_REQ.ptr)));
455   }
456 }
457
458 static void Symlink(const FunctionCallbackInfo<Value>& args) {
459   Environment* env = Environment::GetCurrent(args.GetIsolate());
460   HandleScope scope(env->isolate());
461
462   int len = args.Length();
463   if (len < 1)
464     return TYPE_ERROR("dest path required");
465   if (len < 2)
466     return TYPE_ERROR("src path required");
467   if (!args[0]->IsString())
468     return TYPE_ERROR("dest path must be a string");
469   if (!args[1]->IsString())
470     return TYPE_ERROR("src path must be a string");
471
472   String::Utf8Value dest(args[0]);
473   String::Utf8Value path(args[1]);
474   int flags = 0;
475
476   if (args[2]->IsString()) {
477     String::Utf8Value mode(args[2]);
478     if (strcmp(*mode, "dir") == 0) {
479       flags |= UV_FS_SYMLINK_DIR;
480     } else if (strcmp(*mode, "junction") == 0) {
481       flags |= UV_FS_SYMLINK_JUNCTION;
482     } else if (strcmp(*mode, "file") != 0) {
483       return env->ThrowError("Unknown symlink type");
484     }
485   }
486
487   if (args[3]->IsFunction()) {
488     ASYNC_DEST_CALL(symlink, args[3], *dest, *dest, *path, flags)
489   } else {
490     SYNC_DEST_CALL(symlink, *path, *dest, *dest, *path, flags)
491   }
492 }
493
494 static void Link(const FunctionCallbackInfo<Value>& args) {
495   Environment* env = Environment::GetCurrent(args.GetIsolate());
496   HandleScope scope(env->isolate());
497
498   int len = args.Length();
499   if (len < 1)
500     return TYPE_ERROR("dest path required");
501   if (len < 2)
502     return TYPE_ERROR("src path required");
503   if (!args[0]->IsString())
504     return TYPE_ERROR("dest path must be a string");
505   if (!args[1]->IsString())
506     return TYPE_ERROR("src path must be a string");
507
508   String::Utf8Value orig_path(args[0]);
509   String::Utf8Value new_path(args[1]);
510
511   if (args[2]->IsFunction()) {
512     ASYNC_DEST_CALL(link, args[2], *new_path, *orig_path, *new_path)
513   } else {
514     SYNC_DEST_CALL(link, *orig_path, *new_path, *orig_path, *new_path)
515   }
516 }
517
518 static void ReadLink(const FunctionCallbackInfo<Value>& args) {
519   Environment* env = Environment::GetCurrent(args.GetIsolate());
520   HandleScope scope(env->isolate());
521
522   if (args.Length() < 1)
523     return TYPE_ERROR("path required");
524   if (!args[0]->IsString())
525     return TYPE_ERROR("path must be a string");
526
527   String::Utf8Value path(args[0]);
528
529   if (args[1]->IsFunction()) {
530     ASYNC_CALL(readlink, args[1], *path)
531   } else {
532     SYNC_CALL(readlink, *path, *path)
533     const char* link_path = static_cast<const char*>(SYNC_REQ.ptr);
534     Local<String> rc = String::NewFromUtf8(env->isolate(), link_path);
535     args.GetReturnValue().Set(rc);
536   }
537 }
538
539 static void Rename(const FunctionCallbackInfo<Value>& args) {
540   Environment* env = Environment::GetCurrent(args.GetIsolate());
541   HandleScope scope(env->isolate());
542
543   int len = args.Length();
544   if (len < 1)
545     return TYPE_ERROR("old path required");
546   if (len < 2)
547     return TYPE_ERROR("new path required");
548   if (!args[0]->IsString())
549     return TYPE_ERROR("old path must be a string");
550   if (!args[1]->IsString())
551     return TYPE_ERROR("new path must be a string");
552
553   String::Utf8Value old_path(args[0]);
554   String::Utf8Value new_path(args[1]);
555
556   if (args[2]->IsFunction()) {
557     ASYNC_DEST_CALL(rename, args[2], *new_path, *old_path, *new_path)
558   } else {
559     SYNC_DEST_CALL(rename, *old_path, *new_path, *old_path, *new_path)
560   }
561 }
562
563 static void FTruncate(const FunctionCallbackInfo<Value>& args) {
564   Environment* env = Environment::GetCurrent(args.GetIsolate());
565   HandleScope scope(env->isolate());
566
567   if (args.Length() < 2 || !args[0]->IsInt32()) {
568     return THROW_BAD_ARGS;
569   }
570
571   int fd = args[0]->Int32Value();
572
573   ASSERT_TRUNCATE_LENGTH(args[1]);
574   int64_t len = GET_TRUNCATE_LENGTH(args[1]);
575
576   if (args[2]->IsFunction()) {
577     ASYNC_CALL(ftruncate, args[2], fd, len)
578   } else {
579     SYNC_CALL(ftruncate, 0, fd, len)
580   }
581 }
582
583 static void Fdatasync(const FunctionCallbackInfo<Value>& args) {
584   Environment* env = Environment::GetCurrent(args.GetIsolate());
585   HandleScope scope(env->isolate());
586
587   if (args.Length() < 1 || !args[0]->IsInt32()) {
588     return THROW_BAD_ARGS;
589   }
590
591   int fd = args[0]->Int32Value();
592
593   if (args[1]->IsFunction()) {
594     ASYNC_CALL(fdatasync, args[1], fd)
595   } else {
596     SYNC_CALL(fdatasync, 0, fd)
597   }
598 }
599
600 static void Fsync(const FunctionCallbackInfo<Value>& args) {
601   Environment* env = Environment::GetCurrent(args.GetIsolate());
602   HandleScope scope(env->isolate());
603
604   if (args.Length() < 1 || !args[0]->IsInt32()) {
605     return THROW_BAD_ARGS;
606   }
607
608   int fd = args[0]->Int32Value();
609
610   if (args[1]->IsFunction()) {
611     ASYNC_CALL(fsync, args[1], fd)
612   } else {
613     SYNC_CALL(fsync, 0, fd)
614   }
615 }
616
617 static void Unlink(const FunctionCallbackInfo<Value>& args) {
618   Environment* env = Environment::GetCurrent(args.GetIsolate());
619   HandleScope scope(env->isolate());
620
621   if (args.Length() < 1)
622     return TYPE_ERROR("path required");
623   if (!args[0]->IsString())
624     return TYPE_ERROR("path must be a string");
625
626   String::Utf8Value path(args[0]);
627
628   if (args[1]->IsFunction()) {
629     ASYNC_CALL(unlink, args[1], *path)
630   } else {
631     SYNC_CALL(unlink, *path, *path)
632   }
633 }
634
635 static void RMDir(const FunctionCallbackInfo<Value>& args) {
636   Environment* env = Environment::GetCurrent(args.GetIsolate());
637   HandleScope scope(env->isolate());
638
639   if (args.Length() < 1)
640     return TYPE_ERROR("path required");
641   if (!args[0]->IsString())
642     return TYPE_ERROR("path must be a string");
643
644   String::Utf8Value path(args[0]);
645
646   if (args[1]->IsFunction()) {
647     ASYNC_CALL(rmdir, args[1], *path)
648   } else {
649     SYNC_CALL(rmdir, *path, *path)
650   }
651 }
652
653 static void MKDir(const FunctionCallbackInfo<Value>& args) {
654   Environment* env = Environment::GetCurrent(args.GetIsolate());
655   HandleScope scope(env->isolate());
656
657   if (args.Length() < 2 || !args[0]->IsString() || !args[1]->IsInt32()) {
658     return THROW_BAD_ARGS;
659   }
660
661   String::Utf8Value path(args[0]);
662   int mode = static_cast<int>(args[1]->Int32Value());
663
664   if (args[2]->IsFunction()) {
665     ASYNC_CALL(mkdir, args[2], *path, mode)
666   } else {
667     SYNC_CALL(mkdir, *path, *path, mode)
668   }
669 }
670
671 static void ReadDir(const FunctionCallbackInfo<Value>& args) {
672   Environment* env = Environment::GetCurrent(args.GetIsolate());
673   HandleScope scope(env->isolate());
674
675   if (args.Length() < 1)
676     return TYPE_ERROR("path required");
677   if (!args[0]->IsString())
678     return TYPE_ERROR("path must be a string");
679
680   String::Utf8Value path(args[0]);
681
682   if (args[1]->IsFunction()) {
683     ASYNC_CALL(readdir, args[1], *path, 0 /*flags*/)
684   } else {
685     SYNC_CALL(readdir, *path, *path, 0 /*flags*/)
686
687     assert(SYNC_REQ.result >= 0);
688     char* namebuf = static_cast<char*>(SYNC_REQ.ptr);
689     uint32_t nnames = SYNC_REQ.result;
690     Local<Array> names = Array::New(env->isolate(), nnames);
691
692     for (uint32_t i = 0; i < nnames; ++i) {
693       names->Set(i, String::NewFromUtf8(env->isolate(), namebuf));
694 #ifndef NDEBUG
695       namebuf += strlen(namebuf);
696       assert(*namebuf == '\0');
697       namebuf += 1;
698 #else
699       namebuf += strlen(namebuf) + 1;
700 #endif
701     }
702
703     args.GetReturnValue().Set(names);
704   }
705 }
706
707 static void Open(const FunctionCallbackInfo<Value>& args) {
708   Environment* env = Environment::GetCurrent(args.GetIsolate());
709   HandleScope scope(env->isolate());
710
711   int len = args.Length();
712   if (len < 1)
713     return TYPE_ERROR("path required");
714   if (len < 2)
715     return TYPE_ERROR("flags required");
716   if (len < 3)
717     return TYPE_ERROR("mode required");
718   if (!args[0]->IsString())
719     return TYPE_ERROR("path must be a string");
720   if (!args[1]->IsInt32())
721     return TYPE_ERROR("flags must be an int");
722   if (!args[2]->IsInt32())
723     return TYPE_ERROR("mode must be an int");
724
725   String::Utf8Value path(args[0]);
726   int flags = args[1]->Int32Value();
727   int mode = static_cast<int>(args[2]->Int32Value());
728
729   if (args[3]->IsFunction()) {
730     ASYNC_CALL(open, args[3], *path, flags, mode)
731   } else {
732     SYNC_CALL(open, *path, *path, flags, mode)
733     args.GetReturnValue().Set(SYNC_RESULT);
734   }
735 }
736
737
738 // Wrapper for write(2).
739 //
740 // bytesWritten = write(fd, buffer, offset, length, position, callback)
741 // 0 fd        integer. file descriptor
742 // 1 buffer    the data to write
743 // 2 offset    where in the buffer to start from
744 // 3 length    how much to write
745 // 4 position  if integer, position to write at in the file.
746 //             if null, write from the current position
747 static void WriteBuffer(const FunctionCallbackInfo<Value>& args) {
748   Environment* env = Environment::GetCurrent(args.GetIsolate());
749   HandleScope scope(env->isolate());
750
751   assert(args[0]->IsInt32());
752   assert(Buffer::HasInstance(args[1]));
753
754   int fd = args[0]->Int32Value();
755   Local<Object> obj = args[1].As<Object>();
756   const char* buf = Buffer::Data(obj);
757   size_t buffer_length = Buffer::Length(obj);
758   size_t off = args[2]->Uint32Value();
759   size_t len = args[3]->Uint32Value();
760   int64_t pos = GET_OFFSET(args[4]);
761   Local<Value> cb = args[5];
762
763   if (off > buffer_length)
764     return env->ThrowRangeError("offset out of bounds");
765   if (len > buffer_length)
766     return env->ThrowRangeError("length out of bounds");
767   if (off + len < off)
768     return env->ThrowRangeError("off + len overflow");
769   if (!Buffer::IsWithinBounds(off, len, buffer_length))
770     return env->ThrowRangeError("off + len > buffer.length");
771
772   buf += off;
773
774   uv_buf_t uvbuf = uv_buf_init(const_cast<char*>(buf), len);
775
776   if (cb->IsFunction()) {
777     ASYNC_CALL(write, cb, fd, &uvbuf, 1, pos)
778     return;
779   }
780
781   SYNC_CALL(write, NULL, fd, &uvbuf, 1, pos)
782   args.GetReturnValue().Set(SYNC_RESULT);
783 }
784
785
786 // Wrapper for write(2).
787 //
788 // bytesWritten = write(fd, string, position, enc, callback)
789 // 0 fd        integer. file descriptor
790 // 1 string    non-buffer values are converted to strings
791 // 2 position  if integer, position to write at in the file.
792 //             if null, write from the current position
793 // 3 enc       encoding of string
794 static void WriteString(const FunctionCallbackInfo<Value>& args) {
795   HandleScope handle_scope(args.GetIsolate());
796   Environment* env = Environment::GetCurrent(args.GetIsolate());
797
798   if (!args[0]->IsInt32())
799     return env->ThrowTypeError("First argument must be file descriptor");
800
801   Local<Value> cb;
802   Local<Value> string = args[1];
803   int fd = args[0]->Int32Value();
804   char* buf = NULL;
805   int64_t pos;
806   size_t len;
807   bool must_free = false;
808
809   // will assign buf and len if string was external
810   if (!StringBytes::GetExternalParts(env->isolate(),
811                                      string,
812                                      const_cast<const char**>(&buf),
813                                      &len)) {
814     enum encoding enc = ParseEncoding(args[3], UTF8);
815     len = StringBytes::StorageSize(env->isolate(), string, enc);
816     buf = new char[len];
817     // StorageSize may return too large a char, so correct the actual length
818     // by the write size
819     len = StringBytes::Write(env->isolate(), buf, len, args[1], enc);
820     must_free = true;
821   }
822   pos = GET_OFFSET(args[2]);
823   cb = args[4];
824
825   uv_buf_t uvbuf = uv_buf_init(const_cast<char*>(buf), len);
826
827   if (!cb->IsFunction()) {
828     SYNC_CALL(write, NULL, fd, &uvbuf, 1, pos)
829     if (must_free)
830       delete[] buf;
831     return args.GetReturnValue().Set(SYNC_RESULT);
832   }
833
834   FSReqWrap* req_wrap = new FSReqWrap(env, "write", must_free ? buf : NULL);
835   int err = uv_fs_write(env->event_loop(),
836                         &req_wrap->req_,
837                         fd,
838                         &uvbuf,
839                         1,
840                         pos,
841                         After);
842   req_wrap->object()->Set(env->oncomplete_string(), cb);
843   req_wrap->Dispatched();
844   if (err < 0) {
845     uv_fs_t* req = &req_wrap->req_;
846     req->result = err;
847     req->path = NULL;
848     After(req);
849   }
850
851   return args.GetReturnValue().Set(req_wrap->persistent());
852 }
853
854
855 /*
856  * Wrapper for read(2).
857  *
858  * bytesRead = fs.read(fd, buffer, offset, length, position)
859  *
860  * 0 fd        integer. file descriptor
861  * 1 buffer    instance of Buffer
862  * 2 offset    integer. offset to start reading into inside buffer
863  * 3 length    integer. length to read
864  * 4 position  file position - null for current position
865  *
866  */
867 static void Read(const FunctionCallbackInfo<Value>& args) {
868   Environment* env = Environment::GetCurrent(args.GetIsolate());
869   HandleScope scope(env->isolate());
870
871   if (args.Length() < 2 || !args[0]->IsInt32()) {
872     return THROW_BAD_ARGS;
873   }
874
875   int fd = args[0]->Int32Value();
876
877   Local<Value> cb;
878
879   size_t len;
880   int64_t pos;
881
882   char * buf = NULL;
883
884   if (!Buffer::HasInstance(args[1])) {
885     return env->ThrowError("Second argument needs to be a buffer");
886   }
887
888   Local<Object> buffer_obj = args[1]->ToObject();
889   char *buffer_data = Buffer::Data(buffer_obj);
890   size_t buffer_length = Buffer::Length(buffer_obj);
891
892   size_t off = args[2]->Int32Value();
893   if (off >= buffer_length) {
894     return env->ThrowError("Offset is out of bounds");
895   }
896
897   len = args[3]->Int32Value();
898   if (!Buffer::IsWithinBounds(off, len, buffer_length))
899     return env->ThrowRangeError("Length extends beyond buffer");
900
901   pos = GET_OFFSET(args[4]);
902
903   buf = buffer_data + off;
904
905   uv_buf_t uvbuf = uv_buf_init(const_cast<char*>(buf), len);
906
907   cb = args[5];
908
909   if (cb->IsFunction()) {
910     ASYNC_CALL(read, cb, fd, &uvbuf, 1, pos);
911   } else {
912     SYNC_CALL(read, 0, fd, &uvbuf, 1, pos)
913     args.GetReturnValue().Set(SYNC_RESULT);
914   }
915 }
916
917
918 /* fs.chmod(path, mode);
919  * Wrapper for chmod(1) / EIO_CHMOD
920  */
921 static void Chmod(const FunctionCallbackInfo<Value>& args) {
922   Environment* env = Environment::GetCurrent(args.GetIsolate());
923   HandleScope scope(env->isolate());
924
925   if (args.Length() < 2 || !args[0]->IsString() || !args[1]->IsInt32()) {
926     return THROW_BAD_ARGS;
927   }
928   String::Utf8Value path(args[0]);
929   int mode = static_cast<int>(args[1]->Int32Value());
930
931   if (args[2]->IsFunction()) {
932     ASYNC_CALL(chmod, args[2], *path, mode);
933   } else {
934     SYNC_CALL(chmod, *path, *path, mode);
935   }
936 }
937
938
939 /* fs.fchmod(fd, mode);
940  * Wrapper for fchmod(1) / EIO_FCHMOD
941  */
942 static void FChmod(const FunctionCallbackInfo<Value>& args) {
943   Environment* env = Environment::GetCurrent(args.GetIsolate());
944   HandleScope scope(env->isolate());
945
946   if (args.Length() < 2 || !args[0]->IsInt32() || !args[1]->IsInt32()) {
947     return THROW_BAD_ARGS;
948   }
949   int fd = args[0]->Int32Value();
950   int mode = static_cast<int>(args[1]->Int32Value());
951
952   if (args[2]->IsFunction()) {
953     ASYNC_CALL(fchmod, args[2], fd, mode);
954   } else {
955     SYNC_CALL(fchmod, 0, fd, mode);
956   }
957 }
958
959
960 /* fs.chown(path, uid, gid);
961  * Wrapper for chown(1) / EIO_CHOWN
962  */
963 static void Chown(const FunctionCallbackInfo<Value>& args) {
964   Environment* env = Environment::GetCurrent(args.GetIsolate());
965   HandleScope scope(env->isolate());
966
967   int len = args.Length();
968   if (len < 1)
969     return TYPE_ERROR("path required");
970   if (len < 2)
971     return TYPE_ERROR("uid required");
972   if (len < 3)
973     return TYPE_ERROR("gid required");
974   if (!args[0]->IsString())
975     return TYPE_ERROR("path must be a string");
976   if (!args[1]->IsUint32())
977     return TYPE_ERROR("uid must be an unsigned int");
978   if (!args[2]->IsUint32())
979     return TYPE_ERROR("gid must be an unsigned int");
980
981   String::Utf8Value path(args[0]);
982   uv_uid_t uid = static_cast<uv_uid_t>(args[1]->Uint32Value());
983   uv_gid_t gid = static_cast<uv_gid_t>(args[2]->Uint32Value());
984
985   if (args[3]->IsFunction()) {
986     ASYNC_CALL(chown, args[3], *path, uid, gid);
987   } else {
988     SYNC_CALL(chown, *path, *path, uid, gid);
989   }
990 }
991
992
993 /* fs.fchown(fd, uid, gid);
994  * Wrapper for fchown(1) / EIO_FCHOWN
995  */
996 static void FChown(const FunctionCallbackInfo<Value>& args) {
997   Environment* env = Environment::GetCurrent(args.GetIsolate());
998   HandleScope scope(env->isolate());
999
1000   int len = args.Length();
1001   if (len < 1)
1002     return TYPE_ERROR("fd required");
1003   if (len < 2)
1004     return TYPE_ERROR("uid required");
1005   if (len < 3)
1006     return TYPE_ERROR("gid required");
1007   if (!args[0]->IsInt32())
1008     return TYPE_ERROR("fd must be an int");
1009   if (!args[1]->IsUint32())
1010     return TYPE_ERROR("uid must be an unsigned int");
1011   if (!args[2]->IsUint32())
1012     return TYPE_ERROR("gid must be an unsigned int");
1013
1014   int fd = args[0]->Int32Value();
1015   uv_uid_t uid = static_cast<uv_uid_t>(args[1]->Uint32Value());
1016   uv_gid_t gid = static_cast<uv_gid_t>(args[2]->Uint32Value());
1017
1018   if (args[3]->IsFunction()) {
1019     ASYNC_CALL(fchown, args[3], fd, uid, gid);
1020   } else {
1021     SYNC_CALL(fchown, 0, fd, uid, gid);
1022   }
1023 }
1024
1025
1026 static void UTimes(const FunctionCallbackInfo<Value>& args) {
1027   Environment* env = Environment::GetCurrent(args.GetIsolate());
1028   HandleScope scope(env->isolate());
1029
1030   int len = args.Length();
1031   if (len < 1)
1032     return TYPE_ERROR("path required");
1033   if (len < 2)
1034     return TYPE_ERROR("atime required");
1035   if (len < 3)
1036     return TYPE_ERROR("mtime required");
1037   if (!args[0]->IsString())
1038     return TYPE_ERROR("path must be a string");
1039   if (!args[1]->IsNumber())
1040     return TYPE_ERROR("atime must be a number");
1041   if (!args[2]->IsNumber())
1042     return TYPE_ERROR("mtime must be a number");
1043
1044   const String::Utf8Value path(args[0]);
1045   const double atime = static_cast<double>(args[1]->NumberValue());
1046   const double mtime = static_cast<double>(args[2]->NumberValue());
1047
1048   if (args[3]->IsFunction()) {
1049     ASYNC_CALL(utime, args[3], *path, atime, mtime);
1050   } else {
1051     SYNC_CALL(utime, *path, *path, atime, mtime);
1052   }
1053 }
1054
1055 static void FUTimes(const FunctionCallbackInfo<Value>& args) {
1056   Environment* env = Environment::GetCurrent(args.GetIsolate());
1057   HandleScope scope(env->isolate());
1058
1059   int len = args.Length();
1060   if (len < 1)
1061     return TYPE_ERROR("fd required");
1062   if (len < 2)
1063     return TYPE_ERROR("atime required");
1064   if (len < 3)
1065     return TYPE_ERROR("mtime required");
1066   if (!args[0]->IsInt32())
1067     return TYPE_ERROR("fd must be an int");
1068   if (!args[1]->IsNumber())
1069     return TYPE_ERROR("atime must be a number");
1070   if (!args[2]->IsNumber())
1071     return TYPE_ERROR("mtime must be a number");
1072
1073   const int fd = args[0]->Int32Value();
1074   const double atime = static_cast<double>(args[1]->NumberValue());
1075   const double mtime = static_cast<double>(args[2]->NumberValue());
1076
1077   if (args[3]->IsFunction()) {
1078     ASYNC_CALL(futime, args[3], fd, atime, mtime);
1079   } else {
1080     SYNC_CALL(futime, 0, fd, atime, mtime);
1081   }
1082 }
1083
1084
1085 void InitFs(Handle<Object> target,
1086             Handle<Value> unused,
1087             Handle<Context> context,
1088             void* priv) {
1089   Environment* env = Environment::GetCurrent(context);
1090
1091   // Initialize the stats object
1092   Local<Function> constructor =
1093       FunctionTemplate::New(env->isolate())->GetFunction();
1094   target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "Stats"), constructor);
1095   env->set_stats_constructor_function(constructor);
1096
1097   NODE_SET_METHOD(target, "close", Close);
1098   NODE_SET_METHOD(target, "open", Open);
1099   NODE_SET_METHOD(target, "read", Read);
1100   NODE_SET_METHOD(target, "fdatasync", Fdatasync);
1101   NODE_SET_METHOD(target, "fsync", Fsync);
1102   NODE_SET_METHOD(target, "rename", Rename);
1103   NODE_SET_METHOD(target, "ftruncate", FTruncate);
1104   NODE_SET_METHOD(target, "rmdir", RMDir);
1105   NODE_SET_METHOD(target, "mkdir", MKDir);
1106   NODE_SET_METHOD(target, "readdir", ReadDir);
1107   NODE_SET_METHOD(target, "stat", Stat);
1108   NODE_SET_METHOD(target, "lstat", LStat);
1109   NODE_SET_METHOD(target, "fstat", FStat);
1110   NODE_SET_METHOD(target, "link", Link);
1111   NODE_SET_METHOD(target, "symlink", Symlink);
1112   NODE_SET_METHOD(target, "readlink", ReadLink);
1113   NODE_SET_METHOD(target, "unlink", Unlink);
1114   NODE_SET_METHOD(target, "writeBuffer", WriteBuffer);
1115   NODE_SET_METHOD(target, "writeString", WriteString);
1116
1117   NODE_SET_METHOD(target, "chmod", Chmod);
1118   NODE_SET_METHOD(target, "fchmod", FChmod);
1119   // NODE_SET_METHOD(target, "lchmod", LChmod);
1120
1121   NODE_SET_METHOD(target, "chown", Chown);
1122   NODE_SET_METHOD(target, "fchown", FChown);
1123   // NODE_SET_METHOD(target, "lchown", LChown);
1124
1125   NODE_SET_METHOD(target, "utimes", UTimes);
1126   NODE_SET_METHOD(target, "futimes", FUTimes);
1127
1128   StatWatcher::Initialize(env, target);
1129 }
1130
1131 }  // end namespace node
1132
1133 NODE_MODULE_CONTEXT_AWARE_BUILTIN(fs, node::InitFs)