1 // Copyright Joyent, Inc. and other Node contributors.
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:
11 // The above copyright notice and this permission notice shall be included
12 // in all copies or substantial portions of the Software.
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.
23 #include "node_file.h"
24 #include "node_buffer.h"
25 #include "node_internals.h"
26 #include "node_stat_watcher.h"
31 #include "string_bytes.h"
34 #include <sys/types.h>
41 #if defined(__MINGW32__) || defined(_MSC_VER)
49 using v8::EscapableHandleScope;
51 using v8::FunctionCallbackInfo;
52 using v8::FunctionTemplate;
54 using v8::HandleScope;
62 #define MIN(a, b) ((a) < (b) ? (a) : (b))
64 #define TYPE_ERROR(msg) env->ThrowTypeError(msg)
66 #define THROW_BAD_ARGS TYPE_ERROR("Bad argument")
68 class FSReqWrap: public ReqWrap<uv_fs_t> {
70 void* operator new(size_t size) { return new char[size]; }
71 void* operator new(size_t size, char* storage) { return storage; }
73 FSReqWrap(Environment* env, const char* syscall, char* data = NULL)
74 : ReqWrap<uv_fs_t>(env, Object::New(env->isolate())),
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; }
95 unsigned int dest_len_;
100 #define ASSERT_OFFSET(a) \
101 if (!(a)->IsUndefined() && !(a)->IsNull() && !IsInt64((a)->NumberValue())) { \
102 return env->ThrowTypeError("Not an integer"); \
104 #define ASSERT_TRUNCATE_LENGTH(a) \
105 if (!(a)->IsUndefined() && !(a)->IsNull() && !IsInt64((a)->NumberValue())) { \
106 return env->ThrowTypeError("Not an integer"); \
108 #define GET_OFFSET(a) ((a)->IsNumber() ? (a)->IntegerValue() : -1)
109 #define GET_TRUNCATE_LENGTH(a) ((a)->IntegerValue())
111 static inline bool IsInt64(double x) {
112 return x == static_cast<double>(static_cast<int64_t>(x));
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.
121 Environment* env = req_wrap->env();
122 HandleScope handle_scope(env->isolate());
123 Context::Scope context_scope(env->context());
125 // there is always at least one argument. "error"
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];
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,
145 argv[0] = UVException(req->result,
148 static_cast<const char*>(req->path));
151 // error value is empty or null for non-error.
152 argv[0] = Null(env->isolate());
154 // All have at least two args now.
157 switch (req->fs_type) {
158 // These all have no data to pass.
164 case UV_FS_FTRUNCATE:
166 case UV_FS_FDATASYNC:
173 // These, however, don't.
183 argv[1] = Integer::New(env->isolate(), req->result);
187 argv[1] = Integer::New(env->isolate(), req->result);
193 argv[1] = BuildStatsObject(env,
194 static_cast<const uv_stat_t*>(req->ptr));
198 argv[1] = String::NewFromUtf8(env->isolate(),
199 static_cast<const char*>(req->ptr));
204 argv[1] = Integer::New(env->isolate(), req->result);
209 char *namebuf = static_cast<char*>(req->ptr);
210 int nnames = req->result;
212 Local<Array> names = Array::New(env->isolate(), nnames);
214 for (int i = 0; i < nnames; i++) {
215 Local<String> name = String::NewFromUtf8(env->isolate(), namebuf);
218 namebuf += strlen(namebuf);
219 assert(*namebuf == '\0');
222 namebuf += strlen(namebuf) + 1;
231 assert(0 && "Unhandled eio response");
235 req_wrap->MakeCallback(env->oncomplete_string(), argc, argv);
237 uv_fs_req_cleanup(&req_wrap->req_);
241 // This struct is only used on sync fs calls.
242 // For async calls FSReqWrap is used.
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);
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()), \
266 int err = uv_fs_ ## func(env->event_loop() , \
270 req_wrap->object()->Set(env->oncomplete_string(), callback); \
271 req_wrap->Dispatched(); \
273 uv_fs_t* req = &req_wrap->req_; \
278 args.GetReturnValue().Set(req_wrap->persistent());
280 #define ASYNC_CALL(func, callback, ...) \
281 ASYNC_DEST_CALL(func, callback, NULL, __VA_ARGS__) \
283 #define SYNC_DEST_CALL(func, path, dest, ...) \
284 fs_req_wrap req_wrap; \
285 int err = uv_fs_ ## func(env->event_loop(), \
290 if (dest != NULL && \
291 (err == UV_EEXIST || \
292 err == UV_ENOTEMPTY || \
293 err == UV_EPERM)) { \
294 return env->ThrowUVException(err, #func, "", dest); \
296 return env->ThrowUVException(err, #func, "", path); \
300 #define SYNC_CALL(func, path, ...) \
301 SYNC_DEST_CALL(func, path, NULL, __VA_ARGS__) \
303 #define SYNC_REQ req_wrap.req
305 #define SYNC_RESULT err
308 static void Close(const FunctionCallbackInfo<Value>& args) {
309 Environment* env = Environment::GetCurrent(args.GetIsolate());
310 HandleScope scope(env->isolate());
312 if (args.Length() < 1 || !args[0]->IsInt32()) {
313 return THROW_BAD_ARGS;
316 int fd = args[0]->Int32Value();
318 if (args[1]->IsFunction()) {
319 ASYNC_CALL(close, args[1], fd)
321 SYNC_CALL(close, 0, fd)
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());
330 EscapableHandleScope handle_scope(env->isolate());
332 Local<Object> stats = env->stats_constructor_function()->NewInstance();
333 if (stats.IsEmpty()) {
334 return handle_scope.Escape(Local<Object>());
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...
341 // function crash() {
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.
350 Local<Value> val = Integer::New(env->isolate(), s->st_##name); \
352 return handle_scope.Escape(Local<Object>()); \
353 stats->Set(env->name ## _string(), val); \
361 # if defined(__POSIX__)
368 Local<Value> val = Number::New(env->isolate(), \
369 static_cast<double>(s->st_##name)); \
371 return handle_scope.Escape(Local<Object>()); \
372 stats->Set(env->name ## _string(), val); \
376 # if defined(__POSIX__)
381 #define X(name, rec) \
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); \
387 return handle_scope.Escape(Local<Object>()); \
388 stats->Set(env->name ## _string(), val); \
393 X(birthtime, birthtim)
396 return handle_scope.Escape(stats);
399 static void Stat(const FunctionCallbackInfo<Value>& args) {
400 Environment* env = Environment::GetCurrent(args.GetIsolate());
401 HandleScope scope(env->isolate());
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");
408 String::Utf8Value path(args[0]);
410 if (args[1]->IsFunction()) {
411 ASYNC_CALL(stat, args[1], *path)
413 SYNC_CALL(stat, *path, *path)
414 args.GetReturnValue().Set(
415 BuildStatsObject(env, static_cast<const uv_stat_t*>(SYNC_REQ.ptr)));
419 static void LStat(const FunctionCallbackInfo<Value>& args) {
420 Environment* env = Environment::GetCurrent(args.GetIsolate());
421 HandleScope scope(env->isolate());
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");
428 String::Utf8Value path(args[0]);
430 if (args[1]->IsFunction()) {
431 ASYNC_CALL(lstat, args[1], *path)
433 SYNC_CALL(lstat, *path, *path)
434 args.GetReturnValue().Set(
435 BuildStatsObject(env, static_cast<const uv_stat_t*>(SYNC_REQ.ptr)));
439 static void FStat(const FunctionCallbackInfo<Value>& args) {
440 Environment* env = Environment::GetCurrent(args.GetIsolate());
441 HandleScope scope(env->isolate());
443 if (args.Length() < 1 || !args[0]->IsInt32()) {
444 return THROW_BAD_ARGS;
447 int fd = args[0]->Int32Value();
449 if (args[1]->IsFunction()) {
450 ASYNC_CALL(fstat, args[1], fd)
452 SYNC_CALL(fstat, 0, fd)
453 args.GetReturnValue().Set(
454 BuildStatsObject(env, static_cast<const uv_stat_t*>(SYNC_REQ.ptr)));
458 static void Symlink(const FunctionCallbackInfo<Value>& args) {
459 Environment* env = Environment::GetCurrent(args.GetIsolate());
460 HandleScope scope(env->isolate());
462 int len = args.Length();
464 return TYPE_ERROR("dest path required");
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");
472 String::Utf8Value dest(args[0]);
473 String::Utf8Value path(args[1]);
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");
487 if (args[3]->IsFunction()) {
488 ASYNC_DEST_CALL(symlink, args[3], *dest, *dest, *path, flags)
490 SYNC_DEST_CALL(symlink, *path, *dest, *dest, *path, flags)
494 static void Link(const FunctionCallbackInfo<Value>& args) {
495 Environment* env = Environment::GetCurrent(args.GetIsolate());
496 HandleScope scope(env->isolate());
498 int len = args.Length();
500 return TYPE_ERROR("dest path required");
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");
508 String::Utf8Value orig_path(args[0]);
509 String::Utf8Value new_path(args[1]);
511 if (args[2]->IsFunction()) {
512 ASYNC_DEST_CALL(link, args[2], *new_path, *orig_path, *new_path)
514 SYNC_DEST_CALL(link, *orig_path, *new_path, *orig_path, *new_path)
518 static void ReadLink(const FunctionCallbackInfo<Value>& args) {
519 Environment* env = Environment::GetCurrent(args.GetIsolate());
520 HandleScope scope(env->isolate());
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");
527 String::Utf8Value path(args[0]);
529 if (args[1]->IsFunction()) {
530 ASYNC_CALL(readlink, args[1], *path)
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);
539 static void Rename(const FunctionCallbackInfo<Value>& args) {
540 Environment* env = Environment::GetCurrent(args.GetIsolate());
541 HandleScope scope(env->isolate());
543 int len = args.Length();
545 return TYPE_ERROR("old path required");
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");
553 String::Utf8Value old_path(args[0]);
554 String::Utf8Value new_path(args[1]);
556 if (args[2]->IsFunction()) {
557 ASYNC_DEST_CALL(rename, args[2], *new_path, *old_path, *new_path)
559 SYNC_DEST_CALL(rename, *old_path, *new_path, *old_path, *new_path)
563 static void FTruncate(const FunctionCallbackInfo<Value>& args) {
564 Environment* env = Environment::GetCurrent(args.GetIsolate());
565 HandleScope scope(env->isolate());
567 if (args.Length() < 2 || !args[0]->IsInt32()) {
568 return THROW_BAD_ARGS;
571 int fd = args[0]->Int32Value();
573 ASSERT_TRUNCATE_LENGTH(args[1]);
574 int64_t len = GET_TRUNCATE_LENGTH(args[1]);
576 if (args[2]->IsFunction()) {
577 ASYNC_CALL(ftruncate, args[2], fd, len)
579 SYNC_CALL(ftruncate, 0, fd, len)
583 static void Fdatasync(const FunctionCallbackInfo<Value>& args) {
584 Environment* env = Environment::GetCurrent(args.GetIsolate());
585 HandleScope scope(env->isolate());
587 if (args.Length() < 1 || !args[0]->IsInt32()) {
588 return THROW_BAD_ARGS;
591 int fd = args[0]->Int32Value();
593 if (args[1]->IsFunction()) {
594 ASYNC_CALL(fdatasync, args[1], fd)
596 SYNC_CALL(fdatasync, 0, fd)
600 static void Fsync(const FunctionCallbackInfo<Value>& args) {
601 Environment* env = Environment::GetCurrent(args.GetIsolate());
602 HandleScope scope(env->isolate());
604 if (args.Length() < 1 || !args[0]->IsInt32()) {
605 return THROW_BAD_ARGS;
608 int fd = args[0]->Int32Value();
610 if (args[1]->IsFunction()) {
611 ASYNC_CALL(fsync, args[1], fd)
613 SYNC_CALL(fsync, 0, fd)
617 static void Unlink(const FunctionCallbackInfo<Value>& args) {
618 Environment* env = Environment::GetCurrent(args.GetIsolate());
619 HandleScope scope(env->isolate());
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");
626 String::Utf8Value path(args[0]);
628 if (args[1]->IsFunction()) {
629 ASYNC_CALL(unlink, args[1], *path)
631 SYNC_CALL(unlink, *path, *path)
635 static void RMDir(const FunctionCallbackInfo<Value>& args) {
636 Environment* env = Environment::GetCurrent(args.GetIsolate());
637 HandleScope scope(env->isolate());
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");
644 String::Utf8Value path(args[0]);
646 if (args[1]->IsFunction()) {
647 ASYNC_CALL(rmdir, args[1], *path)
649 SYNC_CALL(rmdir, *path, *path)
653 static void MKDir(const FunctionCallbackInfo<Value>& args) {
654 Environment* env = Environment::GetCurrent(args.GetIsolate());
655 HandleScope scope(env->isolate());
657 if (args.Length() < 2 || !args[0]->IsString() || !args[1]->IsInt32()) {
658 return THROW_BAD_ARGS;
661 String::Utf8Value path(args[0]);
662 int mode = static_cast<int>(args[1]->Int32Value());
664 if (args[2]->IsFunction()) {
665 ASYNC_CALL(mkdir, args[2], *path, mode)
667 SYNC_CALL(mkdir, *path, *path, mode)
671 static void ReadDir(const FunctionCallbackInfo<Value>& args) {
672 Environment* env = Environment::GetCurrent(args.GetIsolate());
673 HandleScope scope(env->isolate());
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");
680 String::Utf8Value path(args[0]);
682 if (args[1]->IsFunction()) {
683 ASYNC_CALL(readdir, args[1], *path, 0 /*flags*/)
685 SYNC_CALL(readdir, *path, *path, 0 /*flags*/)
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);
692 for (uint32_t i = 0; i < nnames; ++i) {
693 names->Set(i, String::NewFromUtf8(env->isolate(), namebuf));
695 namebuf += strlen(namebuf);
696 assert(*namebuf == '\0');
699 namebuf += strlen(namebuf) + 1;
703 args.GetReturnValue().Set(names);
707 static void Open(const FunctionCallbackInfo<Value>& args) {
708 Environment* env = Environment::GetCurrent(args.GetIsolate());
709 HandleScope scope(env->isolate());
711 int len = args.Length();
713 return TYPE_ERROR("path required");
715 return TYPE_ERROR("flags required");
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");
725 String::Utf8Value path(args[0]);
726 int flags = args[1]->Int32Value();
727 int mode = static_cast<int>(args[2]->Int32Value());
729 if (args[3]->IsFunction()) {
730 ASYNC_CALL(open, args[3], *path, flags, mode)
732 SYNC_CALL(open, *path, *path, flags, mode)
733 args.GetReturnValue().Set(SYNC_RESULT);
738 // Wrapper for write(2).
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());
751 assert(args[0]->IsInt32());
752 assert(Buffer::HasInstance(args[1]));
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];
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");
768 return env->ThrowRangeError("off + len overflow");
769 if (!Buffer::IsWithinBounds(off, len, buffer_length))
770 return env->ThrowRangeError("off + len > buffer.length");
774 uv_buf_t uvbuf = uv_buf_init(const_cast<char*>(buf), len);
776 if (cb->IsFunction()) {
777 ASYNC_CALL(write, cb, fd, &uvbuf, 1, pos)
781 SYNC_CALL(write, NULL, fd, &uvbuf, 1, pos)
782 args.GetReturnValue().Set(SYNC_RESULT);
786 // Wrapper for write(2).
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());
798 if (!args[0]->IsInt32())
799 return env->ThrowTypeError("First argument must be file descriptor");
802 Local<Value> string = args[1];
803 int fd = args[0]->Int32Value();
807 bool must_free = false;
809 // will assign buf and len if string was external
810 if (!StringBytes::GetExternalParts(env->isolate(),
812 const_cast<const char**>(&buf),
814 enum encoding enc = ParseEncoding(args[3], UTF8);
815 len = StringBytes::StorageSize(env->isolate(), string, enc);
817 // StorageSize may return too large a char, so correct the actual length
819 len = StringBytes::Write(env->isolate(), buf, len, args[1], enc);
822 pos = GET_OFFSET(args[2]);
825 uv_buf_t uvbuf = uv_buf_init(const_cast<char*>(buf), len);
827 if (!cb->IsFunction()) {
828 SYNC_CALL(write, NULL, fd, &uvbuf, 1, pos)
831 return args.GetReturnValue().Set(SYNC_RESULT);
834 FSReqWrap* req_wrap = new FSReqWrap(env, "write", must_free ? buf : NULL);
835 int err = uv_fs_write(env->event_loop(),
842 req_wrap->object()->Set(env->oncomplete_string(), cb);
843 req_wrap->Dispatched();
845 uv_fs_t* req = &req_wrap->req_;
851 return args.GetReturnValue().Set(req_wrap->persistent());
856 * Wrapper for read(2).
858 * bytesRead = fs.read(fd, buffer, offset, length, position)
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
867 static void Read(const FunctionCallbackInfo<Value>& args) {
868 Environment* env = Environment::GetCurrent(args.GetIsolate());
869 HandleScope scope(env->isolate());
871 if (args.Length() < 2 || !args[0]->IsInt32()) {
872 return THROW_BAD_ARGS;
875 int fd = args[0]->Int32Value();
884 if (!Buffer::HasInstance(args[1])) {
885 return env->ThrowError("Second argument needs to be a buffer");
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);
892 size_t off = args[2]->Int32Value();
893 if (off >= buffer_length) {
894 return env->ThrowError("Offset is out of bounds");
897 len = args[3]->Int32Value();
898 if (!Buffer::IsWithinBounds(off, len, buffer_length))
899 return env->ThrowRangeError("Length extends beyond buffer");
901 pos = GET_OFFSET(args[4]);
903 buf = buffer_data + off;
905 uv_buf_t uvbuf = uv_buf_init(const_cast<char*>(buf), len);
909 if (cb->IsFunction()) {
910 ASYNC_CALL(read, cb, fd, &uvbuf, 1, pos);
912 SYNC_CALL(read, 0, fd, &uvbuf, 1, pos)
913 args.GetReturnValue().Set(SYNC_RESULT);
918 /* fs.chmod(path, mode);
919 * Wrapper for chmod(1) / EIO_CHMOD
921 static void Chmod(const FunctionCallbackInfo<Value>& args) {
922 Environment* env = Environment::GetCurrent(args.GetIsolate());
923 HandleScope scope(env->isolate());
925 if (args.Length() < 2 || !args[0]->IsString() || !args[1]->IsInt32()) {
926 return THROW_BAD_ARGS;
928 String::Utf8Value path(args[0]);
929 int mode = static_cast<int>(args[1]->Int32Value());
931 if (args[2]->IsFunction()) {
932 ASYNC_CALL(chmod, args[2], *path, mode);
934 SYNC_CALL(chmod, *path, *path, mode);
939 /* fs.fchmod(fd, mode);
940 * Wrapper for fchmod(1) / EIO_FCHMOD
942 static void FChmod(const FunctionCallbackInfo<Value>& args) {
943 Environment* env = Environment::GetCurrent(args.GetIsolate());
944 HandleScope scope(env->isolate());
946 if (args.Length() < 2 || !args[0]->IsInt32() || !args[1]->IsInt32()) {
947 return THROW_BAD_ARGS;
949 int fd = args[0]->Int32Value();
950 int mode = static_cast<int>(args[1]->Int32Value());
952 if (args[2]->IsFunction()) {
953 ASYNC_CALL(fchmod, args[2], fd, mode);
955 SYNC_CALL(fchmod, 0, fd, mode);
960 /* fs.chown(path, uid, gid);
961 * Wrapper for chown(1) / EIO_CHOWN
963 static void Chown(const FunctionCallbackInfo<Value>& args) {
964 Environment* env = Environment::GetCurrent(args.GetIsolate());
965 HandleScope scope(env->isolate());
967 int len = args.Length();
969 return TYPE_ERROR("path required");
971 return TYPE_ERROR("uid required");
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");
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());
985 if (args[3]->IsFunction()) {
986 ASYNC_CALL(chown, args[3], *path, uid, gid);
988 SYNC_CALL(chown, *path, *path, uid, gid);
993 /* fs.fchown(fd, uid, gid);
994 * Wrapper for fchown(1) / EIO_FCHOWN
996 static void FChown(const FunctionCallbackInfo<Value>& args) {
997 Environment* env = Environment::GetCurrent(args.GetIsolate());
998 HandleScope scope(env->isolate());
1000 int len = args.Length();
1002 return TYPE_ERROR("fd required");
1004 return TYPE_ERROR("uid required");
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");
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());
1018 if (args[3]->IsFunction()) {
1019 ASYNC_CALL(fchown, args[3], fd, uid, gid);
1021 SYNC_CALL(fchown, 0, fd, uid, gid);
1026 static void UTimes(const FunctionCallbackInfo<Value>& args) {
1027 Environment* env = Environment::GetCurrent(args.GetIsolate());
1028 HandleScope scope(env->isolate());
1030 int len = args.Length();
1032 return TYPE_ERROR("path required");
1034 return TYPE_ERROR("atime required");
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");
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());
1048 if (args[3]->IsFunction()) {
1049 ASYNC_CALL(utime, args[3], *path, atime, mtime);
1051 SYNC_CALL(utime, *path, *path, atime, mtime);
1055 static void FUTimes(const FunctionCallbackInfo<Value>& args) {
1056 Environment* env = Environment::GetCurrent(args.GetIsolate());
1057 HandleScope scope(env->isolate());
1059 int len = args.Length();
1061 return TYPE_ERROR("fd required");
1063 return TYPE_ERROR("atime required");
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");
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());
1077 if (args[3]->IsFunction()) {
1078 ASYNC_CALL(futime, args[3], fd, atime, mtime);
1080 SYNC_CALL(futime, 0, fd, atime, mtime);
1085 void InitFs(Handle<Object> target,
1086 Handle<Value> unused,
1087 Handle<Context> context,
1089 Environment* env = Environment::GetCurrent(context);
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);
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);
1117 NODE_SET_METHOD(target, "chmod", Chmod);
1118 NODE_SET_METHOD(target, "fchmod", FChmod);
1119 // NODE_SET_METHOD(target, "lchmod", LChmod);
1121 NODE_SET_METHOD(target, "chown", Chown);
1122 NODE_SET_METHOD(target, "fchown", FChown);
1123 // NODE_SET_METHOD(target, "lchown", LChown);
1125 NODE_SET_METHOD(target, "utimes", UTimes);
1126 NODE_SET_METHOD(target, "futimes", FUTimes);
1128 StatWatcher::Initialize(env, target);
1131 } // end namespace node
1133 NODE_MODULE_CONTEXT_AWARE_BUILTIN(fs, node::InitFs)