Browse Source

Merge branch 'v0.8'

v0.9.1-release
Bert Belder 12 years ago
parent
commit
ba0efd6de0
  1. 2
      Makefile
  2. 18
      configure
  3. 3
      deps/uv/include/uv.h
  4. 2
      deps/uv/src/unix/dl.c
  5. 1
      deps/uv/src/unix/error.c
  6. 71
      deps/uv/src/unix/stream.c
  7. 8
      deps/uv/src/unix/sunos.c
  8. 3
      deps/uv/src/win/error.c
  9. 312
      deps/uv/src/win/fs.c
  10. 4
      deps/uv/test/test-fs.c
  11. 2
      doc/api/child_process.markdown
  12. 16
      doc/api/fs.markdown
  13. 37
      doc/blog/release/node-v0.8.0.md
  14. 105
      lib/fs.js
  15. 25
      lib/sys.js
  16. 21
      lib/util.js
  17. 7
      node.gyp
  18. 3
      test/simple/test-fs-realpath.js
  19. 54
      test/simple/test-regress-GH-3542.js
  20. 13
      tools/blog/generate.js

2
Makefile

@ -31,7 +31,7 @@ out/Debug/node:
$(MAKE) -C out BUILDTYPE=Debug
out/Makefile: common.gypi deps/uv/uv.gyp deps/http_parser/http_parser.gyp deps/zlib/zlib.gyp deps/v8/build/common.gypi deps/v8/tools/gyp/v8.gyp node.gyp config.gypi
tools/gyp_node -f make
$(PYTHON) tools/gyp_node -f make
install: all
out/Release/node tools/installer.js install $(DESTDIR)

18
configure

@ -241,24 +241,24 @@ def target_arch():
def compiler_version():
try:
proc = subprocess.Popen([CC, '-v'], stderr=subprocess.PIPE)
proc = subprocess.Popen(CC.split() + ['-v'], stderr=subprocess.PIPE)
except OSError:
return None
return (False, False, None)
lines = proc.communicate()[1].split('\n')
version_line = None
for i, line in enumerate(lines):
if 'version' in line:
version_line = line
if not version_line:
return None
return (False, False, None)
version = version_line.split("version")[1].strip().split()[0].split(".")
if not version:
return None
return (False, False, None)
return ('LLVM' in version_line, 'clang' in CC, tuple(version))
def configure_node(o):
# TODO add gdb
o['variables']['node_prefix'] = options.prefix if options.prefix else ''
o['variables']['node_prefix'] = os.path.expanduser(options.prefix or '')
o['variables']['node_install_npm'] = b(not options.without_npm)
o['variables']['node_install_waf'] = b(not options.without_waf)
o['variables']['host_arch'] = host_arch()
@ -327,7 +327,6 @@ def configure_v8(o):
o['libraries'] += ['-lv8']
if options.shared_v8_includes:
o['include_dirs'] += [options.shared_v8_includes]
o['variables']['node_shared_v8_includes'] = options.shared_v8_includes
def configure_openssl(o):
@ -398,7 +397,8 @@ write('config.mk', "# Do not edit. Generated by the configure script.\n" +
("BUILDTYPE=%s\n" % ('Debug' if options.debug else 'Release')))
if os.name == 'nt':
subprocess.call(['python', 'tools/gyp_node', '-f', 'msvs',
'-G', 'msvs_version=2010'])
gyp_args = ['-f', 'msvs', '-G', 'msvs_version=2010']
else:
subprocess.call(['tools/gyp_node', '-f', 'make'])
gyp_args = ['-f', 'make']
subprocess.call([sys.executable, 'tools/gyp_node'] + gyp_args)

3
deps/uv/include/uv.h

@ -126,7 +126,8 @@ extern "C" {
XX( 53, ENOTEMPTY, "directory not empty") \
XX( 54, ENOSPC, "no space left on device") \
XX( 55, EIO, "i/o error") \
XX( 56, EROFS, "read-only file system" )
XX( 56, EROFS, "read-only file system" ) \
XX( 57, ENODEV, "no such device" )
#define UV_ERRNO_GEN(val, name, s) UV_##name = val,

2
deps/uv/src/unix/dl.c

@ -34,7 +34,7 @@ int uv_dlopen(const char* filename, uv_lib_t* lib) {
dlerror(); /* Reset error status. */
lib->errmsg = NULL;
lib->handle = dlopen(filename, RTLD_LAZY);
return uv__dlerror(lib);
return lib->handle ? 0 : uv__dlerror(lib);
}

1
deps/uv/src/unix/error.c

@ -86,6 +86,7 @@ uv_err_code uv_translate_sys_error(int sys_errno) {
case EADDRNOTAVAIL: return UV_EADDRNOTAVAIL;
case ENOTDIR: return UV_ENOTDIR;
case EISDIR: return UV_EISDIR;
case ENODEV: return UV_ENODEV;
case ENOTCONN: return UV_ENOTCONN;
case EEXIST: return UV_EEXIST;
case EHOSTUNREACH: return UV_EHOSTUNREACH;

71
deps/uv/src/unix/stream.c

@ -802,62 +802,51 @@ int uv__connect(uv_connect_t* req, uv_stream_t* stream, struct sockaddr* addr,
int sockfd;
int r;
if (stream->type != UV_TCP)
return uv__set_sys_error(stream->loop, ENOTSOCK);
if (stream->connect_req)
return uv__set_sys_error(stream->loop, EALREADY);
if (stream->fd <= 0) {
if ((sockfd = uv__socket(addr->sa_family, SOCK_STREAM, 0)) == -1) {
uv__set_sys_error(stream->loop, errno);
return -1;
}
sockfd = uv__socket(addr->sa_family, SOCK_STREAM, 0);
if (sockfd == -1)
return uv__set_sys_error(stream->loop, errno);
if (uv__stream_open(stream,
sockfd,
UV_STREAM_READABLE | UV_STREAM_WRITABLE)) {
close(sockfd);
return -2;
return -1;
}
}
uv__req_init(stream->loop, req, UV_CONNECT);
req->cb = cb;
req->handle = stream;
ngx_queue_init(&req->queue);
if (stream->connect_req) {
uv__set_sys_error(stream->loop, EALREADY);
return -1;
}
if (stream->type != UV_TCP) {
uv__set_sys_error(stream->loop, ENOTSOCK);
return -1;
}
stream->connect_req = req;
stream->delayed_error = 0;
do {
do
r = connect(stream->fd, addr, addrlen);
}
while (r == -1 && errno == EINTR);
stream->delayed_error = 0;
if (r != 0 && errno != EINPROGRESS) {
switch (errno) {
/* If we get a ECONNREFUSED wait until the next tick to report the
* error. Solaris wants to report immediately--other unixes want to
* wait.
*
* XXX: do the same for ECONNABORTED?
*/
case ECONNREFUSED:
stream->delayed_error = errno;
break;
default:
uv__set_sys_error(stream->loop, errno);
return -1;
}
if (r == -1) {
if (errno == EINPROGRESS)
; /* not an error */
else if (errno == ECONNREFUSED)
/* If we get a ECONNREFUSED wait until the next tick to report the
* error. Solaris wants to report immediately--other unixes want to
* wait.
*/
stream->delayed_error = errno;
else
return uv__set_sys_error(stream->loop, errno);
}
uv__req_init(stream->loop, req, UV_CONNECT);
req->cb = cb;
req->handle = stream;
ngx_queue_init(&req->queue);
stream->connect_req = req;
uv__io_start(stream->loop, &stream->write_watcher);
if (stream->delayed_error)

8
deps/uv/src/unix/sunos.c

@ -332,14 +332,6 @@ uv_err_t uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
lookup_instance = 0;
while ((ksp = kstat_lookup(kc, (char *)"cpu_info", lookup_instance, NULL))) {
if (kstat_read(kc, ksp, NULL) == -1) {
/*
* It is deeply annoying, but some kstats can return errors
* under otherwise routine conditions. (ACPI is one
* offender; there are surely others.) To prevent these
* fouled kstats from completely ruining our day, we assign
* an "error" member to the return value that consists of
* the strerror().
*/
cpu_info->speed = 0;
cpu_info->model = NULL;
} else {

3
deps/uv/src/win/error.c

@ -83,9 +83,11 @@ uv_err_code uv_translate_sys_error(int sys_errno) {
case ERROR_SIGNAL_REFUSED: return UV_EIO;
case ERROR_FILE_NOT_FOUND: return UV_ENOENT;
case ERROR_INVALID_NAME: return UV_ENOENT;
case ERROR_INVALID_REPARSE_DATA: return UV_ENOENT;
case ERROR_MOD_NOT_FOUND: return UV_ENOENT;
case ERROR_PATH_NOT_FOUND: return UV_ENOENT;
case ERROR_ACCESS_DENIED: return UV_EPERM;
case ERROR_PRIVILEGE_NOT_HELD: return UV_EPERM;
case ERROR_NOACCESS: return UV_EACCES;
case WSAEACCES: return UV_EACCES;
case ERROR_ADDRESS_ALREADY_ASSOCIATED: return UV_EADDRINUSE;
@ -110,6 +112,7 @@ uv_err_code uv_translate_sys_error(int sys_errno) {
case ERROR_OPERATION_ABORTED: return UV_EINTR;
case WSAEINTR: return UV_EINTR;
case ERROR_INVALID_DATA: return UV_EINVAL;
case ERROR_SYMLINK_NOT_SUPPORTED: return UV_EINVAL;
case WSAEINVAL: return UV_EINVAL;
case ERROR_CANT_RESOLVE_FILENAME: return UV_ELOOP;
case ERROR_TOO_MANY_OPEN_FILES: return UV_EMFILE;

312
deps/uv/src/win/fs.c

@ -161,47 +161,147 @@ static int is_path_dir(const wchar_t* path) {
}
static int get_reparse_point(HANDLE handle, int* target_length) {
void* buffer = NULL;
REPARSE_DATA_BUFFER* reparse_data;
DWORD bytes_returned;
int rv = 0;
buffer = malloc(MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
if (!buffer) {
uv_fatal_error(ERROR_OUTOFMEMORY, "malloc");
}
INLINE static int fs__readlink_handle(HANDLE handle, char** target_ptr,
int64_t* target_len_ptr) {
char buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
REPARSE_DATA_BUFFER* reparse_data = (REPARSE_DATA_BUFFER*) buffer;
WCHAR *w_target;
DWORD w_target_len;
char* target;
int target_len;
DWORD bytes;
if (!DeviceIoControl(handle,
FSCTL_GET_REPARSE_POINT,
NULL,
0,
buffer,
MAXIMUM_REPARSE_DATA_BUFFER_SIZE,
&bytes_returned,
sizeof buffer,
&bytes,
NULL)) {
free(buffer);
return 0;
return -1;
}
reparse_data = (REPARSE_DATA_BUFFER*)buffer;
if (reparse_data->ReparseTag == IO_REPARSE_TAG_SYMLINK) {
rv = 1;
if (target_length) {
*target_length = reparse_data->SymbolicLinkReparseBuffer.SubstituteNameLength /
sizeof(wchar_t);
/* Real symlink */
w_target = reparse_data->SymbolicLinkReparseBuffer.PathBuffer +
(reparse_data->SymbolicLinkReparseBuffer.SubstituteNameOffset /
sizeof(WCHAR));
w_target_len =
reparse_data->SymbolicLinkReparseBuffer.SubstituteNameLength /
sizeof(WCHAR);
/* Real symlinks can contain pretty much everything, but the only thing */
/* we really care about is undoing the implicit conversion to an NT */
/* namespaced path that CreateSymbolicLink will perform on absolute */
/* paths. If the path is win32-namespaced then the user must have */
/* explicitly made it so, and we better just return the unmodified */
/* reparse data. */
if (w_target_len >= 4 &&
w_target[0] == L'\\' &&
w_target[1] == L'?' &&
w_target[2] == L'?' &&
w_target[3] == L'\\') {
/* Starts with \??\ */
if (w_target_len >= 6 &&
((w_target[4] >= L'A' && w_target[4] <= L'Z') ||
(w_target[4] >= L'a' && w_target[4] <= L'z')) &&
w_target[5] == L':' &&
(w_target_len == 6 || w_target[6] == L'\\')) {
/* \??\«drive»:\ */
w_target += 4;
w_target_len -= 4;
} else if (w_target_len >= 8 &&
(w_target[4] == L'U' || w_target[4] == L'u') &&
(w_target[5] == L'N' || w_target[5] == L'n') &&
(w_target[6] == L'C' || w_target[6] == L'c') &&
w_target[7] == L'\\') {
/* \??\UNC\«server»\«share»\ - make sure the final path looks like */
/* \\«server»\«share»\ */
w_target += 6;
w_target[0] = L'\\';
w_target_len -= 6;
}
}
} else if (reparse_data->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT) {
rv = 1;
if (target_length) {
*target_length = reparse_data->MountPointReparseBuffer.SubstituteNameLength /
/* Junction. */
w_target = reparse_data->MountPointReparseBuffer.PathBuffer +
(reparse_data->MountPointReparseBuffer.SubstituteNameOffset /
sizeof(WCHAR));
w_target_len = reparse_data->MountPointReparseBuffer.SubstituteNameLength /
sizeof(wchar_t);
/* Only treat junctions that look like \??\«drive»:\ as symlink. */
/* Junctions can also be used as mount points, like \??\Volume{«guid»}, */
/* but that's confusing for programs since they wouldn't be able to */
/* actually understand such a path when returned by uv_readlink(). */
/* UNC paths are never valid for junctions so we don't care about them. */
if (!(w_target_len >= 6 &&
w_target[0] == L'\\' &&
w_target[1] == L'?' &&
w_target[2] == L'?' &&
w_target[3] == L'\\' &&
((w_target[4] >= L'A' && w_target[4] <= L'Z') ||
(w_target[4] >= L'a' && w_target[4] <= L'z')) &&
w_target[5] == L':' &&
(w_target_len == 6 || w_target[6] == L'\\'))) {
SetLastError(ERROR_SYMLINK_NOT_SUPPORTED);
return -1;
}
/* Remove leading \??\ */
w_target += 4;
w_target_len -= 4;
} else {
/* Reparse tag does not indicate a symlink. */
SetLastError(ERROR_SYMLINK_NOT_SUPPORTED);
return -1;
}
free(buffer);
return rv;
/* Compute the length of the target. */
target_len = WideCharToMultiByte(CP_UTF8,
0,
w_target,
w_target_len,
NULL,
0,
NULL,
NULL);
if (target_len == 0) {
return -1;
}
/* If requested, allocate memory and convert to UTF8. */
if (target_ptr != NULL) {
int r;
target = (char*) malloc(target_len + 1);
if (target == NULL) {
SetLastError(ERROR_OUTOFMEMORY);
return -1;
}
r = WideCharToMultiByte(CP_UTF8,
0,
w_target,
w_target_len,
target,
target_len,
NULL,
NULL);
assert(r == target_len);
target[target_len] = '\0';
*target_ptr = target;
}
if (target_len_ptr != NULL) {
*target_len_ptr = target_len;
}
return 0;
}
@ -455,11 +555,12 @@ void fs__unlink(uv_fs_t* req, const wchar_t* path) {
return;
}
is_dir_symlink = info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY &&
get_reparse_point(handle, NULL);
is_dir_symlink = (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
(info.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT);
CloseHandle(handle);
/* Todo: very inefficient; fix this. */
if (is_dir_symlink) {
fs__rmdir(req, path);
} else {
@ -583,7 +684,6 @@ void fs__readdir(uv_fs_t* req, const wchar_t* path, int flags) {
INLINE static int fs__stat_handle(HANDLE handle, uv_statbuf_t* statbuf) {
int target_length;
BY_HANDLE_FILE_INFORMATION info;
if (!GetFileInformationByHandle(handle, &info)) {
@ -600,28 +700,25 @@ INLINE static int fs__stat_handle(HANDLE handle, uv_statbuf_t* statbuf) {
statbuf->st_mode = 0;
if (info.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT &&
get_reparse_point(handle, &target_length)) {
statbuf->st_mode = S_IFLNK;
/* Adjust for long path */
statbuf->st_size = target_length - JUNCTION_PREFIX_LEN;
} else {
if (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY) {
statbuf->st_mode |= (_S_IREAD + (_S_IREAD >> 3) + (_S_IREAD >> 6));
} else {
statbuf->st_mode |= ((_S_IREAD|_S_IWRITE) + ((_S_IREAD|_S_IWRITE) >> 3) +
((_S_IREAD|_S_IWRITE) >> 6));
if (info.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
if (fs__readlink_handle(handle, NULL, &statbuf->st_size) != 0) {
return -1;
}
if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
statbuf->st_mode |= _S_IFDIR;
} else {
statbuf->st_mode |= _S_IFREG;
}
statbuf->st_mode |= S_IFLNK;
} else if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
statbuf->st_mode |= _S_IFDIR;
statbuf->st_size = 0;
} else {
statbuf->st_mode |= _S_IFREG;
statbuf->st_size = ((int64_t) info.nFileSizeHigh << 32) +
(int64_t) info.nFileSizeLow;
}
if (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY) {
statbuf->st_mode |= (_S_IREAD + (_S_IREAD >> 3) + (_S_IREAD >> 6));
} else {
statbuf->st_mode |= ((_S_IREAD|_S_IWRITE) + ((_S_IREAD|_S_IWRITE) >> 3) +
((_S_IREAD|_S_IWRITE) >> 6));
}
statbuf->st_mtime = FILETIME_TO_TIME_T(info.ftLastWriteTime);
@ -659,7 +756,16 @@ INLINE static void fs__stat(uv_fs_t* req, const wchar_t* path, int do_lstat) {
}
if (fs__stat_handle(handle, &req->stat) != 0) {
SET_REQ_WIN32_ERROR(req, GetLastError());
DWORD error = GetLastError();
if (do_lstat && error == ERROR_SYMLINK_NOT_SUPPORTED) {
/* We opened a reparse point but it was not a symlink. Try again. */
fs__stat(req, path, 0);
} else {
/* Stat failed. */
SET_REQ_WIN32_ERROR(req, GetLastError());
}
CloseHandle(handle);
return;
}
@ -1099,117 +1205,31 @@ void fs__symlink(uv_fs_t* req, const wchar_t* path, const wchar_t* new_path,
void fs__readlink(uv_fs_t* req, const wchar_t* path) {
int result = -1;
BOOL rv;
HANDLE symlink;
void* buffer = NULL;
DWORD bytes_returned;
REPARSE_DATA_BUFFER* reparse_data;
int utf8size;
wchar_t* substitute_name;
int substitute_name_length;
symlink = CreateFileW(path,
0,
0,
NULL,
OPEN_EXISTING,
FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS,
NULL);
if (INVALID_HANDLE_VALUE == symlink) {
result = -1;
SET_REQ_WIN32_ERROR(req, GetLastError());
goto done;
}
buffer = malloc(MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
if (!buffer) {
uv_fatal_error(ERROR_OUTOFMEMORY, "malloc");
}
HANDLE handle;
rv = DeviceIoControl(symlink,
FSCTL_GET_REPARSE_POINT,
NULL,
handle = CreateFileW(path,
0,
buffer,
MAXIMUM_REPARSE_DATA_BUFFER_SIZE,
&bytes_returned,
0,
NULL,
OPEN_EXISTING,
FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS,
NULL);
if (!rv) {
result = -1;
SET_REQ_WIN32_ERROR(req, GetLastError());
goto done;
}
reparse_data = (REPARSE_DATA_BUFFER*)buffer;
if (reparse_data->ReparseTag == IO_REPARSE_TAG_SYMLINK) {
substitute_name = reparse_data->SymbolicLinkReparseBuffer.PathBuffer +
(reparse_data->SymbolicLinkReparseBuffer.SubstituteNameOffset /
sizeof(wchar_t));
substitute_name_length =
reparse_data->SymbolicLinkReparseBuffer.SubstituteNameLength /
sizeof(wchar_t);
} else if (reparse_data->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT) {
substitute_name = reparse_data->MountPointReparseBuffer.PathBuffer +
(reparse_data->MountPointReparseBuffer.SubstituteNameOffset /
sizeof(wchar_t));
substitute_name_length =
reparse_data->MountPointReparseBuffer.SubstituteNameLength /
sizeof(wchar_t);
} else {
result = -1;
/* something is seriously wrong */
SET_REQ_WIN32_ERROR(req, GetLastError());
goto done;
}
/* Strip off the leading \??\ from the substitute name buffer.*/
if (wcsncmp(substitute_name, JUNCTION_PREFIX, JUNCTION_PREFIX_LEN) == 0) {
substitute_name += JUNCTION_PREFIX_LEN;
substitute_name_length -= JUNCTION_PREFIX_LEN;
}
utf8size = uv_utf16_to_utf8(substitute_name,
substitute_name_length,
NULL,
0);
if (!utf8size) {
result = -1;
if (handle == INVALID_HANDLE_VALUE) {
SET_REQ_WIN32_ERROR(req, GetLastError());
goto done;
}
req->ptr = malloc(utf8size + 1);
if (!req->ptr) {
uv_fatal_error(ERROR_OUTOFMEMORY, "malloc");
return;
}
utf8size = uv_utf16_to_utf8(substitute_name,
substitute_name_length,
(char*)req->ptr,
utf8size);
if (!utf8size) {
result = -1;
if (fs__readlink_handle(handle, (char**) &req->ptr, NULL) != 0) {
SET_REQ_WIN32_ERROR(req, GetLastError());
goto done;
CloseHandle(handle);
return;
}
req->flags |= UV_FS_FREE_PTR;
((char*)req->ptr)[utf8size] = '\0';
result = 0;
done:
if (buffer) {
free(buffer);
}
if (symlink != INVALID_HANDLE_VALUE) {
CloseHandle(symlink);
}
SET_REQ_RESULT(req, 0);
SET_REQ_RESULT(req, result);
CloseHandle(handle);
}

4
deps/uv/test/test-fs.c

@ -1224,10 +1224,10 @@ TEST_IMPL(fs_symlink) {
* We just pass the test and bail out early if we get ENOTSUP.
*/
return 0;
} else if (uv_last_error(loop).sys_errno_ == ERROR_PRIVILEGE_NOT_HELD) {
} else if (uv_last_error(loop).code == UV_EPERM) {
/*
* Creating a symlink is only allowed when running elevated.
* We pass the test and bail out early if we get ERROR_PRIVILEGE_NOT_HELD.
* We pass the test and bail out early if we get UV_EPERM.
*/
return 0;
}

2
doc/api/child_process.markdown

@ -404,7 +404,7 @@ file:
err = fs.openSync('./out.log', 'a');
var child = spawn('prg', [], {
detached: 'true',
detached: true,
stdio: [ 'ignore', out, err ]
});

16
doc/api/fs.markdown

@ -355,13 +355,7 @@ without waiting for the callback. For this scenario,
## fs.writeSync(fd, buffer, offset, length, position)
Synchronous version of buffer-based `fs.write()`. Returns the number of bytes
written.
## fs.writeSync(fd, str, position, [encoding])
Synchronous version of string-based `fs.write()`. `encoding` defaults to
`'utf8'`. Returns the number of _bytes_ written.
Synchronous version of `fs.write()`. Returns the number of bytes written.
## fs.read(fd, buffer, offset, length, position, [callback])
@ -380,13 +374,7 @@ The callback is given the three arguments, `(err, bytesRead, buffer)`.
## fs.readSync(fd, buffer, offset, length, position)
Synchronous version of buffer-based `fs.read`. Returns the number of
`bytesRead`.
## fs.readSync(fd, length, position, encoding)
Legacy synchronous version of string-based `fs.read`. Returns an array with the
data from the file specified and number of bytes read, `[string, bytesRead]`.
Synchronous version of `fs.read`. Returns the number of `bytesRead`.
## fs.readFile(filename, [encoding], [callback])

37
doc/blog/release/node-v0.8.0.md

@ -48,10 +48,10 @@ Wrote 16384 byte buffers: 83.97010664203543 mB/s
Wrote 65536 byte buffers: 97.4184120798831 mB/s
# 0.8.0, writes
Wrote 1024 byte buffers: 61.236987140232706 mB/s
Wrote 4096 byte buffers: 109.05125408942203 mB/s
Wrote 16384 byte buffers: 182.18254691200585 mB/s
Wrote 65536 byte buffers: 181.91740949608877 mB/s
Wrote 1024 byte buffers: 61.236987140232706 mB/s +215.19%
Wrote 4096 byte buffers: 109.05125408942203 mB/s +82.55%
Wrote 16384 byte buffers: 182.18254691200585 mB/s +116.96%
Wrote 65536 byte buffers: 181.91740949608877 mB/s +86.74%
# v0.6.19, reads
Read 1024 byte buffers: 29.96883241428914 mB/s
@ -60,10 +60,10 @@ Read 16384 byte buffers: 165.7550140891762 mB/s
Read 65536 byte buffers: 266.73779674579885 mB/s
# v0.8.0, reads
Read 1024 byte buffers: 57.63688760806916 mB/s
Read 4096 byte buffers: 136.7801942278758 mB/s
Read 16384 byte buffers: 244.8579823702253 mB/s
Read 65536 byte buffers: 302.2974607013301 mB/s
Read 1024 byte buffers: 57.63688760806916 mB/s +92.32%
Read 4096 byte buffers: 136.7801942278758 mB/s +119.40%
Read 16384 byte buffers: 244.8579823702253 mB/s +47.72%
Read 65536 byte buffers: 302.2974607013301 mB/s +13.33%
```
The difference is not small. If you are writing network programs with
@ -78,9 +78,9 @@ read the file 110948 times (higher is better)
11093.69 reads per sec (higher is better)
# v0.8.0
read the file 158193 times (higher is better)
63217.16 ns per read (lower is better)
15818.48 reads per sec (higher is better)
read the file 158193 times (higher is better) +42.58%
63217.16 ns per read (lower is better) -29.87%
15818.48 reads per sec (higher is better) +42.59%
```
And of course, the ubiquitous 'hello, world' http server benchmark got
@ -91,21 +91,21 @@ $ TYPE=bytes LENGTH=123 bash benchmark/http.sh 2>&1 | grep Req
# 0.6.19
Requests per second: 3317.24 [#/sec] (mean)
# 0.8.0
Requests per second: 3795.34 [#/sec] (mean)
Requests per second: 3795.34 [#/sec] (mean) +14.41%
$ TYPE=bytes LENGTH=1024 bash benchmark/http.sh 2>&1 | grep Req
# v0.6.19
Requests per second: 3258.42 [#/sec] (mean)
# 0.8.0
Requests per second: 3585.62 [#/sec] (mean)
Requests per second: 3585.62 [#/sec] (mean) +10.04%
$ TYPE=bytes LENGTH=123456 bash benchmark/http.sh 2>&1 | grep Req
# v0.6.19
Requests per second: 218.51 [#/sec] (mean)
# 0.8.0
Requests per second: 749.17 [#/sec] (mean)
Requests per second: 749.17 [#/sec] (mean) +242.85%
```
The difference with Unicode responses is even more pronounced:
@ -115,19 +115,19 @@ $ TYPE=unicode LENGTH=1024 bash benchmark/http.sh 2>&1 | grep Req
# v0.6.19
Requests per second: 3228.23 [#/sec] (mean)
# v0.8.0
Requests per second: 3317.60 [#/sec] (mean)
Requests per second: 3317.60 [#/sec] (mean) +2.77%
$ TYPE=unicode LENGTH=12345 bash benchmark/http.sh 2>&1 | grep Req
# v0.6.19
Requests per second: 1703.96 [#/sec] (mean)
# v0.8.0
Requests per second: 2431.61 [#/sec] (mean)
Requests per second: 2431.61 [#/sec] (mean) +42.70%
$ TYPE=unicode LENGTH=55555 bash benchmark/http.sh 2>&1 | grep Req
#v0.6.19
Requests per second: 161.65 [#/sec] (mean)
#v0.8.0
Requests per second: 980.38 [#/sec] (mean)
Requests per second: 980.38 [#/sec] (mean) +506.48%
$ TYPE=unicode LENGTH=99999 bash benchmark/http.sh 2>&1 | grep Req
# v0.6.19
@ -379,3 +379,6 @@ fc07b475d943f7681e1904d6d7d666b41874a6fa x64/node.exe
686c60d5ae5dad7fcffcdc88049c63b2cd23cffc x64/node.lib
75549cffab0c11107348a66ab0d94d4897bd6a27 x64/node.pdb
```
<ins>Edited by Tim Oxley to provide percentage differences in the
benchmarks.</ins>

105
lib/fs.js

@ -966,10 +966,12 @@ if (isWindows) {
var nextPartRe = /(.*?)(?:[\/]+|$)/g;
}
// Regex to split a windows path into three parts: [*, device, slash,
// tail] windows-only
var splitDeviceRe =
/^([a-zA-Z]:|[\\\/]{2}[^\\\/]+[\\\/][^\\\/]+)?([\\\/])?([\s\S]*?)$/;
// Regex to find the device root, including trailing slash. E.g. 'c:\\'.
if (isWindows) {
var splitRootRe = /^(?:[a-zA-Z]:|[\\\/]{2}[^\\\/]+[\\\/][^\\\/]+)?[\\\/]*/;
} else {
var splitRootRe = /^[\/]*/;
}
fs.realpathSync = function realpathSync(p, cache) {
// make p is absolute
@ -984,13 +986,30 @@ fs.realpathSync = function realpathSync(p, cache) {
knownHard = {};
// current character position in p
var pos = 0;
var pos;
// the partial path so far, including a trailing slash if any
var current = '';
// the partial path without a trailing slash
var base = '';
var current;
// the partial path without a trailing slash (except when pointing at a root)
var base;
// the partial path scanned in the previous round, with slash
var previous = '';
var previous;
start();
function start() {
// Skip over roots
var m = splitRootRe.exec(p);
pos = m[0].length;
current = m[0];
base = m[0];
previous = '';
// On windows, check that the root exists. On unix there is no need.
if (isWindows && !knownHard[base]) {
fs.lstatSync(base);
knownHard[base] = true;
}
}
// walk down the path, swapping out linked pathparts for their real
// values
@ -1004,16 +1023,8 @@ fs.realpathSync = function realpathSync(p, cache) {
base = previous + result[1];
pos = nextPartRe.lastIndex;
// continue if not a symlink, or if root
var isRoot = !base;
if (isWindows) {
// if it doens't have a tail, then it's the root.
var split = base.match(splitDeviceRe);
if (split) {
isRoot = !split[2];
}
}
if (isRoot || knownHard[base] || (cache && cache[base] === base)) {
// continue if not a symlink
if (knownHard[base] || (cache && cache[base] === base)) {
continue;
}
@ -1050,8 +1061,7 @@ fs.realpathSync = function realpathSync(p, cache) {
// resolve the link, then start over
p = pathModule.resolve(resolvedLink, p.slice(pos));
pos = 0;
previous = base = current = '';
start();
}
if (cache) cache[original] = p;
@ -1070,7 +1080,7 @@ fs.realpath = function realpath(p, cache, cb) {
p = pathModule.resolve(p);
if (cache && Object.prototype.hasOwnProperty.call(cache, p)) {
return cb(null, cache[p]);
return process.nextTick(cb.bind(null, null, cache[p]));
}
var original = p,
@ -1078,17 +1088,38 @@ fs.realpath = function realpath(p, cache, cb) {
knownHard = {};
// current character position in p
var pos = 0;
var pos;
// the partial path so far, including a trailing slash if any
var current = '';
// the partial path without a trailing slash
var base = '';
var current;
// the partial path without a trailing slash (except when pointing at a root)
var base;
// the partial path scanned in the previous round, with slash
var previous = '';
var previous;
start();
function start() {
// Skip over roots
var m = splitRootRe.exec(p);
pos = m[0].length;
current = m[0];
base = m[0];
previous = '';
// On windows, check that the root exists. On unix there is no need.
if (isWindows && !knownHard[base]) {
fs.lstat(base, function (err) {
if (err) return cb(err);
knownHard[base] = true;
LOOP();
});
} else {
process.nextTick(LOOP);
}
}
// walk down the path, swapping out linked pathparts for their real
// values
LOOP();
function LOOP() {
// stop if scanned past end of path
if (pos >= p.length) {
@ -1104,16 +1135,8 @@ fs.realpath = function realpath(p, cache, cb) {
base = previous + result[1];
pos = nextPartRe.lastIndex;
// continue if not a symlink, or if root
var isRoot = !base;
if (isWindows) {
// if it doens't have a tail, then it's the root.
var split = base.match(splitDeviceRe);
if (split) {
isRoot = !split[2];
}
}
if (isRoot || knownHard[base] || (cache && cache[base] === base)) {
// continue if not a symlink
if (knownHard[base] || (cache && cache[base] === base)) {
return process.nextTick(LOOP);
}
@ -1163,13 +1186,9 @@ fs.realpath = function realpath(p, cache, cb) {
}
function gotResolvedLink(resolvedLink) {
// resolve the link, then start over
p = pathModule.resolve(resolvedLink, p.slice(pos));
pos = 0;
previous = base = current = '';
return process.nextTick(LOOP);
start();
}
};

25
lib/sys.js

@ -1 +1,24 @@
throw new Error('The "sys" module is now called "util".');
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
// the sys module was renamed to 'util'.
// this shim remains to keep old programs working.
module.exports = require('util');

21
lib/util.js

@ -175,6 +175,17 @@ function stylizeNoColor(str, styleType) {
}
function arrayToHash(array) {
var hash = {};
array.forEach(function(val, idx) {
hash[val] = true;
});
return hash;
}
function formatValue(ctx, value, recurseTimes) {
// Provide a hook for user-specified inspect functions.
// Check that value is an object with an inspect function on it
@ -193,8 +204,12 @@ function formatValue(ctx, value, recurseTimes) {
}
// Look up the keys of the object.
var visibleKeys = Object.keys(value);
var keys = ctx.showHidden ? Object.getOwnPropertyNames(value) : visibleKeys;
var keys = Object.keys(value);
var visibleKeys = arrayToHash(keys);
if (ctx.showHidden) {
keys = Object.getOwnPropertyNames(value);
}
// Some type of object without properties can be shortcutted.
if (keys.length === 0) {
@ -334,7 +349,7 @@ function formatProperty(ctx, value, recurseTimes, visibleKeys, key, array) {
str = ctx.stylize('[Setter]', 'special');
}
}
if (visibleKeys.indexOf(key) < 0) {
if (!visibleKeys.hasOwnProperty(key)) {
name = '[' + key + ']';
}
if (!str) {

7
node.gyp

@ -177,12 +177,7 @@
'<(SHARED_INTERMEDIATE_DIR)/node_etw_provider.rc',
]
} ],
[ 'node_shared_v8=="true"', {
'sources': [
'<(node_shared_v8_includes)/v8.h',
'<(node_shared_v8_includes)/v8-debug.h',
],
}, {
[ 'node_shared_v8=="false"', {
'sources': [
'deps/v8/include/v8.h',
'deps/v8/include/v8-debug.h',

3
test/simple/test-fs-realpath.js

@ -515,10 +515,13 @@ function test_lying_cache_liar(cb) {
var rps = fs.realpathSync(bluff, cache);
assert.equal(cache[bluff], rps);
var nums = path.resolve('/1/2/3/4/5/6/7');
var called = false; // no sync cb calling!
fs.realpath(nums, cache, function(er, rp) {
called = true;
assert.equal(cache[nums], rp);
if (--n === 0) cb();
});
assert(called === false);
var test = path.resolve('/a/b/c/d'),
expect = path.resolve('/a/b/d');

54
test/simple/test-regress-GH-3542.js

@ -0,0 +1,54 @@
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
// This test is only relevant on Windows.
if (process.platform !== 'win32') {
return process.exit(0);
}
var common = require('../common.js'),
assert = require('assert'),
fs = require('fs'),
path = require('path'),
succeeded = 0;
function test(p) {
var result = fs.realpathSync(p);
assert.strictEqual(result, path.resolve(p));
fs.realpath(p, function(err, result) {
assert.ok(!err);
assert.strictEqual(result, path.resolve(p));
succeeded++;
});
}
test('//localhost/c$/windows/system32');
test('//localhost/c$/windows');
test('//localhost/c$/')
test('\\\\localhost\\c$')
test('c:\\');
test('c:');
test(process.env.windir);
process.on('exit', function() {
assert.strictEqual(succeeded, 7);
});

13
tools/blog/generate.js

@ -170,9 +170,18 @@ function buildFeeds(data) {
}
// filter non-latest release notices out of main feeds.
// still show the first stable release of the family, since
// it usually is an important milestone with benchmarks and stuff.
var main = posts.filter(function(post) {
if (post.version && post.family && post !== releases[post.family][0]) {
return false;
if (post.version && post.family) {
var ver = semver.parse(post.version)
if (+ver[2] % 2 === 0 && +ver[3] === 0) {
// 0.x.0, where x is event
return true;
}
if (post.version && post.family && post !== releases[post.family][0]) {
return false;
}
}
return true;
});

Loading…
Cancel
Save