Skip to content

Instantly share code, notes, and snippets.

@igorzi
Created November 24, 2011 20:43
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save igorzi/1392239 to your computer and use it in GitHub Desktop.
Save igorzi/1392239 to your computer and use it in GitHub Desktop.
From 3cdd08199b79f858a89fe228d724d6ff8be77df3 Mon Sep 17 00:00:00 2001
From: Igor Zinkovsky <igorzi@microsoft.com>
Date: Thu, 24 Nov 2011 12:36:46 -0800
Subject: [PATCH] enable long paths on windows
---
lib/fs.js | 91 +++++++++++---------
lib/path.js | 21 +++++
test/simple/test-fs-long-path.js | 49 +++++++++++
test/simple/test-path-makelong.js | 37 ++++++++
5 files changed, 157 insertions(+), 42 deletions(-)
create mode 100644 test/simple/test-fs-long-path.js
create mode 100644 test/simple/test-path-makelong.js
diff --git a/lib/fs.js b/lib/fs.js
index b69a240..f7f8fe2 100644
--- a/lib/fs.js
+++ b/lib/fs.js
@@ -26,6 +26,7 @@
// var mode = 438; /* mode=0666 */
var util = require('util');
+var pathModule = require('path');
var binding = process.binding('fs');
var constants = process.binding('constants');
@@ -220,12 +221,13 @@ fs.open = function(path, flags, mode, callback) {
mode = modeNum(mode, 438 /*=0666*/);
- binding.open(path, stringToFlags(flags), mode, callback);
+ binding.open(pathModule._makeLong(path), stringToFlags(flags), mode,
+ callback);
};
fs.openSync = function(path, flags, mode) {
mode = modeNum(mode, 438 /*=0666*/);
- return binding.open(path, stringToFlags(flags), mode);
+ return binding.open(pathModule._makeLong(path), stringToFlags(flags), mode);
};
fs.read = function(fd, buffer, offset, length, position, callback) {
@@ -320,11 +322,13 @@ fs.writeSync = function(fd, buffer, offset, length, position) {
};
fs.rename = function(oldPath, newPath, callback) {
- binding.rename(oldPath, newPath, callback || noop);
+ binding.rename(pathModule._makeLong(oldPath), pathModule._makeLong(newPath),
+ callback || noop);
};
fs.renameSync = function(oldPath, newPath) {
- return binding.rename(oldPath, newPath);
+ return binding.rename(pathModule._makeLong(oldPath),
+ pathModule._makeLong(newPath));
};
fs.truncate = function(fd, len, callback) {
@@ -336,11 +340,11 @@ fs.truncateSync = function(fd, len) {
};
fs.rmdir = function(path, callback) {
- binding.rmdir(path, callback || noop);
+ binding.rmdir(pathModule._makeLong(path), callback || noop);
};
fs.rmdirSync = function(path) {
- return binding.rmdir(path);
+ return binding.rmdir(pathModule._makeLong(path));
};
fs.fdatasync = function(fd, callback) {
@@ -361,11 +365,13 @@ fs.fsyncSync = function(fd) {
fs.mkdir = function(path, mode, callback) {
if (typeof mode === 'function') callback = mode;
- binding.mkdir(path, modeNum(mode, 511 /*=0777*/), callback || noop);
+ binding.mkdir(pathModule._makeLong(path), modeNum(mode, 511 /*=0777*/),
+ callback || noop);
};
fs.mkdirSync = function(path, mode) {
- return binding.mkdir(path, modeNum(mode, 511 /*=0777*/));
+ return binding.mkdir(pathModule._makeLong(path),
+ modeNum(mode, 511 /*=0777*/));
};
fs.sendfile = function(outFd, inFd, inOffset, length, callback) {
@@ -377,11 +383,11 @@ fs.sendfileSync = function(outFd, inFd, inOffset, length) {
};
fs.readdir = function(path, callback) {
- binding.readdir(path, callback || noop);
+ binding.readdir(pathModule._makeLong(path), callback || noop);
};
fs.readdirSync = function(path) {
- return binding.readdir(path);
+ return binding.readdir(pathModule._makeLong(path));
};
fs.fstat = function(fd, callback) {
@@ -389,11 +395,11 @@ fs.fstat = function(fd, callback) {
};
fs.lstat = function(path, callback) {
- binding.lstat(path, callback || noop);
+ binding.lstat(pathModule._makeLong(path), callback || noop);
};
fs.stat = function(path, callback) {
- binding.stat(path, callback || noop);
+ binding.stat(pathModule._makeLong(path), callback || noop);
};
fs.fstatSync = function(fd) {
@@ -401,46 +407,50 @@ fs.fstatSync = function(fd) {
};
fs.lstatSync = function(path) {
- return binding.lstat(path);
+ return binding.lstat(pathModule._makeLong(path));
};
fs.statSync = function(path) {
- return binding.stat(path);
+ return binding.stat(pathModule._makeLong(path));
};
fs.readlink = function(path, callback) {
- binding.readlink(path, callback || noop);
+ binding.readlink(pathModule._makeLong(path), callback || noop);
};
fs.readlinkSync = function(path) {
- return binding.readlink(path);
+ return binding.readlink(pathModule._makeLong(path));
};
fs.symlink = function(destination, path, mode_, callback) {
var mode = (typeof(mode_) == 'string' ? mode_ : null);
var callback_ = arguments[arguments.length - 1];
callback = (typeof(callback_) == 'function' ? callback_ : null);
- binding.symlink(destination, path, mode, callback);
+ binding.symlink(pathModule._makeLong(destination),
+ pathModule._makeLong(path), mode, callback);
};
fs.symlinkSync = function(destination, path, mode) {
- return binding.symlink(destination, path, mode);
+ return binding.symlink(pathModule._makeLong(destination),
+ pathModule._makeLong(path), mode);
};
fs.link = function(srcpath, dstpath, callback) {
- binding.link(srcpath, dstpath, callback || noop);
+ binding.link(pathModule._makeLong(srcpath), pathModule._makeLong(dstpath),
+ callback || noop);
};
fs.linkSync = function(srcpath, dstpath) {
- return binding.link(srcpath, dstpath);
+ return binding.link(pathModule._makeLong(srcpath),
+ pathModule._makeLong(dstpath));
};
fs.unlink = function(path, callback) {
- binding.unlink(path, callback || noop);
+ binding.unlink(pathModule._makeLong(path), callback || noop);
};
fs.unlinkSync = function(path) {
- return binding.unlink(path);
+ return binding.unlink(pathModule._makeLong(path));
};
fs.fchmod = function(fd, mode, callback) {
@@ -471,11 +481,11 @@ if (constants.hasOwnProperty('O_SYMLINK')) {
fs.chmod = function(path, mode, callback) {
- binding.chmod(path, modeNum(mode), callback || noop);
+ binding.chmod(pathModule._makeLong(path), modeNum(mode), callback || noop);
};
fs.chmodSync = function(path, mode) {
- return binding.chmod(path, modeNum(mode));
+ return binding.chmod(pathModule._makeLong(path), modeNum(mode));
};
if (constants.hasOwnProperty('O_SYMLINK')) {
@@ -505,11 +515,11 @@ fs.fchownSync = function(fd, uid, gid) {
};
fs.chown = function(path, uid, gid, callback) {
- binding.chown(path, uid, gid, callback || noop);
+ binding.chown(pathModule._makeLong(path), uid, gid, callback || noop);
};
fs.chownSync = function(path, uid, gid) {
- return binding.chown(path, uid, gid);
+ return binding.chown(pathModule._makeLong(path), uid, gid);
};
// converts Date or number to a fractional UNIX timestamp
@@ -530,13 +540,13 @@ fs._toUnixTimestamp = toUnixTimestamp;
fs.utimes = function(path, atime, mtime, callback) {
atime = toUnixTimestamp(atime);
mtime = toUnixTimestamp(mtime);
- binding.utimes(path, atime, mtime, callback || noop);
+ binding.utimes(pathModule._makeLong(path), atime, mtime, callback || noop);
};
fs.utimesSync = function(path, atime, mtime) {
atime = toUnixTimestamp(atime);
mtime = toUnixTimestamp(mtime);
- binding.utimes(path, atime, mtime);
+ binding.utimes(pathModule._makeLong(path), atime, mtime);
};
fs.futimes = function(fd, atime, mtime, callback) {
@@ -625,7 +635,7 @@ function FSWatcher() {
util.inherits(FSWatcher, EventEmitter);
FSWatcher.prototype.start = function(filename, persistent) {
- var r = this._handle.start(filename, persistent);
+ var r = this._handle.start(pathModule._makeLong(filename), persistent);
if (r) {
this._handle.close();
@@ -682,7 +692,7 @@ util.inherits(StatWatcher, EventEmitter);
StatWatcher.prototype.start = function(filename, persistent, interval) {
- this._handle.start(filename, persistent, interval);
+ this._handle.start(pathModule._makeLong(filename), persistent, interval);
};
@@ -745,8 +755,7 @@ fs.unwatchFile = function(filename) {
// Not using realpath(2) because it's bad.
// See: http://insanecoding.blogspot.com/2007/11/pathmax-simply-isnt.html
-var path = require('path'),
- normalize = path.normalize,
+var normalize = pathModule.normalize,
isWindows = process.platform === 'win32';
if (isWindows) {
@@ -755,7 +764,7 @@ if (isWindows) {
// windows version
fs.realpathSync = function realpathSync(p, cache) {
- p = path.resolve(p);
+ p = pathModule.resolve(p);
if (cache && Object.prototype.hasOwnProperty.call(cache, p)) {
return cache[p];
}
@@ -770,7 +779,7 @@ if (isWindows) {
cb = cache;
cache = null;
}
- p = path.resolve(p);
+ p = pathModule.resolve(p);
if (cache && Object.prototype.hasOwnProperty.call(cache, p)) {
return cb(null, cache[p]);
}
@@ -791,7 +800,7 @@ if (isWindows) {
// posix version
fs.realpathSync = function realpathSync(p, cache) {
// make p is absolute
- p = path.resolve(p);
+ p = pathModule.resolve(p);
if (cache && Object.prototype.hasOwnProperty.call(cache, p)) {
return cache[p];
@@ -844,14 +853,14 @@ if (isWindows) {
if (!seenLinks[id]) {
fs.statSync(base);
seenLinks[id] = fs.readlinkSync(base);
- resolvedLink = path.resolve(previous, seenLinks[id]);
+ resolvedLink = pathModule.resolve(previous, seenLinks[id]);
// track this, if given a cache.
if (cache) cache[base] = resolvedLink;
}
}
// resolve the link, then start over
- p = path.resolve(resolvedLink, p.slice(pos));
+ p = pathModule.resolve(resolvedLink, p.slice(pos));
pos = 0;
previous = base = current = '';
}
@@ -870,7 +879,7 @@ if (isWindows) {
}
// make p is absolute
- p = path.resolve(p);
+ p = pathModule.resolve(p);
if (cache && Object.prototype.hasOwnProperty.call(cache, p)) {
return cb(null, cache[p]);
@@ -948,7 +957,7 @@ if (isWindows) {
function gotTarget(err, target, base) {
if (err) return cb(err);
- var resolvedLink = path.resolve(previous, target);
+ var resolvedLink = pathModule.resolve(previous, target);
if (cache) cache[base] = resolvedLink;
gotResolvedLink(resolvedLink);
}
@@ -956,7 +965,7 @@ if (isWindows) {
function gotResolvedLink(resolvedLink) {
// resolve the link, then start over
- p = path.resolve(resolvedLink, p.slice(pos));
+ p = pathModule.resolve(resolvedLink, p.slice(pos));
pos = 0;
previous = base = current = '';
@@ -1404,4 +1413,4 @@ SyncWriteStream.prototype.destroy = function() {
return true;
};
-SyncWriteStream.prototype.destroySoon = SyncWriteStream.prototype.destroy;
+SyncWriteStream.prototype.destroySoon = SyncWriteStream.prototype.destroy;
\ No newline at end of file
diff --git a/lib/path.js b/lib/path.js
index c843d53..ecb81e1 100644
--- a/lib/path.js
+++ b/lib/path.js
@@ -421,3 +421,24 @@ exports.existsSync = function(path) {
return false;
}
};
+
+
+exports._makeLong = isWindows ?
+ function(path) {
+ var resolvedPath = exports.resolve(path);
+
+ if (resolvedPath.match(/^[a-zA-Z]\:\\/)) {
+ // path is local filesystem path, which needs to be converted
+ // to long UNC path.
+ return '\\\\?\\' + resolvedPath;
+ } else if (resolvedPath.match(/^\\\\[^?]/)) {
+ // path is network UNC path, which needs to be converted
+ // to long UNC path.
+ return '\\\\?\\UNC\\' + resolvedPath.substring(2);
+ }
+
+ return path;
+ } :
+ function(path) {
+ return path;
+ }
diff --git a/test/simple/test-fs-long-path.js b/test/simple/test-fs-long-path.js
new file mode 100644
index 0000000..dfd6880
--- /dev/null
+++ b/test/simple/test-fs-long-path.js
@@ -0,0 +1,49 @@
+// 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.
+
+var fs = require('fs');
+var path = require('path');
+var assert = require('assert');
+
+var successes = 0;
+
+// make a path that will be at least 260 chars long.
+var cwd = process.cwd();
+var fileNameLen = Math.max(260 - cwd.length - 1, 1);
+var fileName = new Array(fileNameLen + 1).join('x');
+var fullPath = path.resolve(fileName);
+
+console.log({ filenameLength: fileName.length,
+ fullPathLength: fullPath.length });
+
+fs.writeFile(fullPath, 'ok', function(err) {
+ if (err) throw err;
+ successes++;
+
+ fs.stat(fullPath, function(err, stats) {
+ if (err) throw err;
+ successes++;
+ });
+});
+
+process.on('exit', function() {
+ assert.equal(2, successes);
+});
diff --git a/test/simple/test-path-makelong.js b/test/simple/test-path-makelong.js
new file mode 100644
index 0000000..4a0aa3a
--- /dev/null
+++ b/test/simple/test-path-makelong.js
@@ -0,0 +1,37 @@
+// 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.
+
+if (process.platform === 'win32') {
+ var assert = require('assert');
+ var path = require('path');
+ var common = require('../common');
+
+ var file = path.join(common.fixturesDir, 'a.js');
+ var resolvedFile = path.resolve(file);
+ var networkFile = '\\\\someserver\\someshare\\somefile';
+
+ assert.equal('\\\\?\\' + resolvedFile, path._makeLong(file));
+ assert.equal('\\\\?\\' + resolvedFile, path._makeLong('\\\\?\\' + file));
+ assert.equal('\\\\?\\UNC\\someserver\\someshare\\somefile',
+ path._makeLong('\\\\someserver\\someshare\\somefile'));
+ assert.equal('\\\\?\\UNC\\someserver\\someshare\\somefile',
+ path._makeLong('\\\\?\\UNC\\someserver\\someshare\\somefile'));
+}
--
1.7.4.msysgit.0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment