Skip to content

Commit

Permalink
Add support for UNC paths
Browse files Browse the repository at this point in the history
Wildcards that now work: \\host\directory\*

Wildcards that still don't work: \\host\*

[fixes isaacs#74, isaacs#123, isaacs#146] handle UNC paths on win32

credit to @staticshock for the WinPath work
  • Loading branch information
stefanpenner committed Nov 14, 2015
1 parent 7e59b55 commit 1f313a5
Show file tree
Hide file tree
Showing 6 changed files with 225 additions and 19 deletions.
45 changes: 38 additions & 7 deletions common.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ exports.finish = finish
exports.mark = mark
exports.isIgnored = isIgnored
exports.childrenIgnored = childrenIgnored
exports.WinPath = WinPath;

function ownProp (obj, field) {
return Object.prototype.hasOwnProperty.call(obj, field)
Expand All @@ -17,6 +18,22 @@ var minimatch = require("minimatch")
var isAbsolute = require("path-is-absolute")
var Minimatch = minimatch.Minimatch

function WinPath (p) {
if (!(this instanceof WinPath))
return new WinPath(p)

// pull off the device/UNC bit from a windows path.
// from node's lib/path.js
var splitDeviceRe =
/^([a-zA-Z]:|[\\\/]{2}[^\\\/]+[\\\/]+[^\\\/]+)?([\\\/])?([\s\S]*?)$/
var result = splitDeviceRe.exec(p)
this.device = result[1] || ''
this.sep = result[2] || ''
this.tail = result[3] || ''
this.isUnc = !!this.device && this.device.charAt(1) !== ':'
this.isAbsolute = !!this.sep || this.isUnc // UNC paths are always absolute
}

function alphasorti (a, b) {
return a.toLowerCase().localeCompare(b.toLowerCase())
}
Expand Down Expand Up @@ -64,6 +81,12 @@ function setopts (self, pattern, options) {

self.silent = !!options.silent
self.pattern = pattern

self.platform = options.platform || process.platform
self.isAbsolute = isAbsolute[self.platform] || isAbsolute
self.resolve = (path[self.platform] || path).resolve
self.sep = (path[self.platform] || path).sep;

self.strict = options.strict !== false
self.realpath = !!options.realpath
self.realpathCache = options.realpathCache || Object.create(null)
Expand Down Expand Up @@ -94,12 +117,20 @@ function setopts (self, pattern, options) {
self.cwd = cwd
else {
self.cwd = options.cwd
self.changedCwd = path.resolve(options.cwd) !== cwd
self.changedCwd = self.resolve(options.cwd) !== cwd
}

if (self.platform === "win32") {
var winPath = new WinPath(pattern)
if (winPath.isAbsolute) {
options.root = winPath.device
pattern = winPath.sep + winPath.tail
}
}

self.root = options.root || path.resolve(self.cwd, "/")
self.root = path.resolve(self.root)
if (process.platform === "win32")
self.root = options.root || self.resolve(self.cwd, "/")
self.root = self.resolve(self.root)
if (self.platform === "win32")
self.root = self.root.replace(/\\/g, "/")

self.nomount = !!options.nomount
Expand Down Expand Up @@ -194,12 +225,12 @@ function makeAbs (self, f) {
var abs = f
if (f.charAt(0) === '/') {
abs = path.join(self.root, f)
} else if (isAbsolute(f) || f === '') {
} else if (self.isAbsolute(f) || f === '') {
abs = f
} else if (self.changedCwd) {
abs = path.resolve(self.cwd, f)
abs = self.resolve(self.cwd, f)
} else {
abs = path.resolve(f)
abs = self.resolve(f)
}
return abs
}
Expand Down
14 changes: 6 additions & 8 deletions glob.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,7 @@ var minimatch = require('minimatch')
var Minimatch = minimatch.Minimatch
var inherits = require('inherits')
var EE = require('events').EventEmitter
var path = require('path')
var assert = require('assert')
var isAbsolute = require('path-is-absolute')
var globSync = require('./sync.js')
var common = require('./common.js')
var alphasort = common.alphasort
Expand All @@ -58,7 +56,7 @@ var inflight = require('inflight')
var util = require('util')
var childrenIgnored = common.childrenIgnored
var isIgnored = common.isIgnored

var path = require('path')
var once = require('once')

function glob (pattern, options, cb) {
Expand Down Expand Up @@ -320,8 +318,8 @@ Glob.prototype._process = function (pattern, index, inGlobStar, cb) {
var read
if (prefix === null)
read = '.'
else if (isAbsolute(prefix) || isAbsolute(pattern.join('/'))) {
if (!prefix || !isAbsolute(prefix))
else if (this.isAbsolute(prefix) || this.isAbsolute(pattern.join('/'))) {
if (!prefix || !this.isAbsolute(prefix))
prefix = '/' + prefix
read = prefix
} else
Expand Down Expand Up @@ -651,18 +649,18 @@ Glob.prototype._processSimple2 = function (prefix, index, er, exists, cb) {
if (!exists)
return cb()

if (prefix && isAbsolute(prefix) && !this.nomount) {
if (prefix && this.isAbsolute(prefix) && !this.nomount) {
var trail = /[\/\\]$/.test(prefix)
if (prefix.charAt(0) === '/') {
prefix = path.join(this.root, prefix)
} else {
prefix = path.resolve(this.root, prefix)
prefix = this.resolve(this.root, prefix)
if (trail)
prefix += '/'
}
}

if (process.platform === 'win32')
if (this.platform === 'win32')
prefix = prefix.replace(/\\/g, '/')

// Mark this as a match
Expand Down
7 changes: 3 additions & 4 deletions sync.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ var Glob = require('./glob.js').Glob
var util = require('util')
var path = require('path')
var assert = require('assert')
var isAbsolute = require('path-is-absolute')
var common = require('./common.js')
var alphasort = common.alphasort
var alphasorti = common.alphasorti
Expand Down Expand Up @@ -110,8 +109,8 @@ GlobSync.prototype._process = function (pattern, index, inGlobStar) {
var read
if (prefix === null)
read = '.'
else if (isAbsolute(prefix) || isAbsolute(pattern.join('/'))) {
if (!prefix || !isAbsolute(prefix))
else if (this.isAbsolute(prefix) || this.isAbsolute(pattern.join('/'))) {
if (!prefix || !this.isAbsolute(prefix))
prefix = '/' + prefix
read = prefix
} else
Expand Down Expand Up @@ -376,7 +375,7 @@ GlobSync.prototype._processSimple = function (prefix, index) {
if (!exists)
return

if (prefix && isAbsolute(prefix) && !this.nomount) {
if (prefix && this.isAbsolute(prefix) && !this.nomount) {
var trail = /[\/\\]$/.test(prefix)
if (prefix.charAt(0) === '/') {
prefix = path.join(this.root, prefix)
Expand Down
35 changes: 35 additions & 0 deletions test/setopts.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
var test = require("tap").test
var setopts = require("../common").setopts;

function stubPlatform(platform, fn) {
var descriptor = Object.getOwnPropertyDescriptor(process, 'platform');

try {
Object.defineProperty(process, 'platform', {
value: platform,
writable: false
});

fn();
} finally {
Object.defineProperty(process, 'platform', descriptor);
}

}

test("unit test – setopts – ensure UNC paths are handled correctly", function (t) {

stubPlatform("win32", function() {
var sentinel = { }
setopts(sentinel, "\\\\vmware-host\\Shared Folders\\-folder\\*", { platform: 'win32' })
t.same(sentinel.minimatch.pattern, "\\-folder\\\*")
})

stubPlatform("darwin", function() {
var sentinel = { }
setopts(sentinel, "\\\\vmware-host\\Shared Folders\\-folder\\*", { platform: 'darwin' })
t.same(sentinel.minimatch.pattern, "\\\\vmware-host\\Shared Folders\\-folder\\*")
})

t.end()
})
71 changes: 71 additions & 0 deletions test/unc-path.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
var test = require('tap').test;
var glob = require('../');
var fs = require('fs');
var path = require('path');

test('glob doesn\'t choke on UNC paths', function(t) {
stubPlatform('win32', function(restorePlatform) {
var readdir = fs.readdir;

fs.readdir = function(path, cb) {
if (path === '\\\\vmware-share\\share-name\\baz') {
return cb(undefined, [
'some-file.txt',
'some-other-file.txt'
])
}

readdir(path, cb)
}

var results = glob('\\\\vmware-share\\share-name\\baz\\*', function (er, results) {
restorePlatform();

if (er)
throw er

t.same(results, [
'\\\\vmware-share\\share-name\\baz\\some-file.txt',
'\\\\vmware-share\\share-name\\baz\\some-other-file.txt'
])

t.end()
}, { platform: 'win32' })
})
})

function stubPlatform(platform, fn) {
var descriptor = Object.getOwnPropertyDescriptor(process, 'platform')
var path = require('path');
var join = path.join;
var normalize = path.normalize;
var sep = path.sep;
var resolve = path.resolve;
var isAbsolute = require('path-is-absolute');

function restore() {
path.resolve = resolve;
path.sep = sep;
path.join = join;
path.normalize = normalize;
var isAbsolute = require('path-is-absolute');
Object.defineProperty(process, 'platform', descriptor);
}

try {
Object.defineProperty(process, 'platform', {
value: platform,
writable: false
});

path.sep = '\\';
path.resolve = path[platform].resolve;
path.join = path.win32.join;
path.normalize = path.win32.normalize;

return fn(restore);
} catch(e) {
restore();
throw e;
}
}
72 changes: 72 additions & 0 deletions test/win-path.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
var WinPath = require('../common').WinPath;
var test = require('tap').test

test("UNIT: WinPath – basic path", function(t) {
var path = new WinPath('basic-path')

t.same(path.device, '');
t.same(path.sep, '');
t.same(path.tail, 'basic-path')

t.end();
});

test("UNIT: WinPath – relative path", function(t) {
var path = new WinPath('relative\\path')

t.same(path.device, '');
t.same(path.sep, '');
t.same(path.tail, 'relative\\path')

t.end();
});

test("UNIT: WinPath – relative path \w glob", function(t) {
var path = new WinPath('relative\\path\\*')

t.same(path.device, '');
t.same(path.sep, '');
t.same(path.tail, 'relative\\path\\*')

t.end();
});

test("UNIT: WinPath – absolute path", function(t) {
var path = new WinPath('\\relative\\path')

t.same(path.device, '');
t.same(path.sep, '\\');
t.same(path.tail, 'relative\\path')

t.end();
});

test("UNIT: WinPath – absolute path \w glob", function(t) {
var path = new WinPath('\\relative\\path\\*')

t.same(path.device, '');
t.same(path.sep, '\\');
t.same(path.tail, 'relative\\path\\*')

t.end();
});

test("UNIT: WinPath – UNC path", function(t) {
var path = new WinPath('\\\\vmware-share\\share-name\\relative\\path')

t.same(path.device, '\\\\vmware-share\\share-name');
t.same(path.sep, '\\');
t.same(path.tail, 'relative\\path')

t.end();
});

test("UNIT: WinPath – UNC path \w glob", function(t) {
var path = new WinPath('\\\\vmware-share\\share-name\\relative\\path\\*')

t.same(path.device, '\\\\vmware-share\\share-name');
t.same(path.sep, '\\');
t.same(path.tail, 'relative\\path\\*')

t.end();
});

0 comments on commit 1f313a5

Please sign in to comment.