@@ -1563,38 +1563,239 @@ fs.unwatchFile = function(filename, listener) {
1563
1563
} ;
1564
1564
1565
1565
1566
- fs . realpathSync = function realpathSync ( path , options ) {
1566
+ // Regexp that finds the next portion of a (partial) path
1567
+ // result is [base_with_slash, base], e.g. ['somedir/', 'somedir']
1568
+ const nextPartRe = isWindows ?
1569
+ / ( .* ?) (?: [ \/ \\ ] + | $ ) / g :
1570
+ / ( .* ?) (?: [ \/ ] + | $ ) / g;
1571
+
1572
+ // Regex to find the device root, including trailing slash. E.g. 'c:\\'.
1573
+ const splitRootRe = isWindows ?
1574
+ / ^ (?: [ a - z A - Z ] : | [ \\ \/ ] { 2 } [ ^ \\ \/ ] + [ \\ \/ ] [ ^ \\ \/ ] + ) ? [ \\ \/ ] * / :
1575
+ / ^ [ \/ ] * / ;
1576
+
1577
+ function encodeRealpathResult ( result , options , err ) {
1578
+ if ( ! options || ! options . encoding || options . encoding === 'utf8' || err )
1579
+ return result ;
1580
+ const asBuffer = Buffer . from ( result ) ;
1581
+ if ( options . encoding === 'buffer' ) {
1582
+ return asBuffer ;
1583
+ } else {
1584
+ return asBuffer . toString ( options . encoding ) ;
1585
+ }
1586
+ }
1587
+
1588
+ fs . realpathSync = function realpathSync ( p , options ) {
1567
1589
if ( ! options )
1568
1590
options = { } ;
1569
1591
else if ( typeof options === 'string' )
1570
1592
options = { encoding : options } ;
1571
1593
else if ( typeof options !== 'object' )
1572
1594
throw new TypeError ( '"options" must be a string or an object' ) ;
1573
- nullCheck ( path ) ;
1574
- return binding . realpath ( pathModule . _makeLong ( path ) , options . encoding ) ;
1595
+ nullCheck ( p ) ;
1596
+
1597
+ p = p . toString ( 'utf8' ) ;
1598
+ p = pathModule . resolve ( p ) ;
1599
+
1600
+ const seenLinks = { } ;
1601
+ const knownHard = { } ;
1602
+
1603
+ // current character position in p
1604
+ var pos ;
1605
+ // the partial path so far, including a trailing slash if any
1606
+ var current ;
1607
+ // the partial path without a trailing slash (except when pointing at a root)
1608
+ var base ;
1609
+ // the partial path scanned in the previous round, with slash
1610
+ var previous ;
1611
+
1612
+ start ( ) ;
1613
+
1614
+ function start ( ) {
1615
+ // Skip over roots
1616
+ var m = splitRootRe . exec ( p ) ;
1617
+ pos = m [ 0 ] . length ;
1618
+ current = m [ 0 ] ;
1619
+ base = m [ 0 ] ;
1620
+ previous = '' ;
1621
+
1622
+ // On windows, check that the root exists. On unix there is no need.
1623
+ if ( isWindows && ! knownHard [ base ] ) {
1624
+ fs . lstatSync ( base ) ;
1625
+ knownHard [ base ] = true ;
1626
+ }
1627
+ }
1628
+
1629
+ // walk down the path, swapping out linked pathparts for their real
1630
+ // values
1631
+ // NB: p.length changes.
1632
+ while ( pos < p . length ) {
1633
+ // find the next part
1634
+ nextPartRe . lastIndex = pos ;
1635
+ var result = nextPartRe . exec ( p ) ;
1636
+ previous = current ;
1637
+ current += result [ 0 ] ;
1638
+ base = previous + result [ 1 ] ;
1639
+ pos = nextPartRe . lastIndex ;
1640
+
1641
+ // continue if not a symlink
1642
+ if ( knownHard [ base ] ) {
1643
+ continue ;
1644
+ }
1645
+
1646
+ var resolvedLink ;
1647
+ var stat = fs . lstatSync ( base ) ;
1648
+ if ( ! stat . isSymbolicLink ( ) ) {
1649
+ knownHard [ base ] = true ;
1650
+ continue ;
1651
+ }
1652
+
1653
+ // read the link if it wasn't read before
1654
+ // dev/ino always return 0 on windows, so skip the check.
1655
+ var linkTarget = null ;
1656
+ if ( ! isWindows ) {
1657
+ var id = stat . dev . toString ( 32 ) + ':' + stat . ino . toString ( 32 ) ;
1658
+ if ( seenLinks . hasOwnProperty ( id ) ) {
1659
+ linkTarget = seenLinks [ id ] ;
1660
+ }
1661
+ }
1662
+ if ( linkTarget === null ) {
1663
+ fs . statSync ( base ) ;
1664
+ linkTarget = fs . readlinkSync ( base ) ;
1665
+ }
1666
+ resolvedLink = pathModule . resolve ( previous , linkTarget ) ;
1667
+
1668
+ if ( ! isWindows ) seenLinks [ id ] = linkTarget ;
1669
+
1670
+ // resolve the link, then start over
1671
+ p = pathModule . resolve ( resolvedLink , p . slice ( pos ) ) ;
1672
+ start ( ) ;
1673
+ }
1674
+
1675
+ return encodeRealpathResult ( p , options ) ;
1575
1676
} ;
1576
1677
1577
1678
1578
- fs . realpath = function realpath ( path , options , callback ) {
1679
+ fs . realpath = function realpath ( p , options , callback ) {
1680
+ if ( typeof callback !== 'function' ) {
1681
+ callback = maybeCallback ( options ) ;
1682
+ options = { } ;
1683
+ }
1684
+
1579
1685
if ( ! options ) {
1580
1686
options = { } ;
1581
1687
} else if ( typeof options === 'function' ) {
1582
- callback = options ;
1583
1688
options = { } ;
1584
1689
} else if ( typeof options === 'string' ) {
1585
1690
options = { encoding : options } ;
1586
1691
} else if ( typeof options !== 'object' ) {
1587
1692
throw new TypeError ( '"options" must be a string or an object' ) ;
1588
1693
}
1589
- callback = makeCallback ( callback ) ;
1590
- if ( ! nullCheck ( path , callback ) )
1694
+ if ( ! nullCheck ( p , callback ) )
1591
1695
return ;
1592
- var req = new FSReqWrap ( ) ;
1593
- req . oncomplete = callback ;
1594
- binding . realpath ( pathModule . _makeLong ( path ) , options . encoding , req ) ;
1595
- return ;
1596
- } ;
1597
1696
1697
+ p = p . toString ( 'utf8' ) ;
1698
+ p = pathModule . resolve ( p ) ;
1699
+
1700
+ const seenLinks = { } ;
1701
+ const knownHard = { } ;
1702
+
1703
+ // current character position in p
1704
+ var pos ;
1705
+ // the partial path so far, including a trailing slash if any
1706
+ var current ;
1707
+ // the partial path without a trailing slash (except when pointing at a root)
1708
+ var base ;
1709
+ // the partial path scanned in the previous round, with slash
1710
+ var previous ;
1711
+
1712
+ start ( ) ;
1713
+
1714
+ function start ( ) {
1715
+ // Skip over roots
1716
+ var m = splitRootRe . exec ( p ) ;
1717
+ pos = m [ 0 ] . length ;
1718
+ current = m [ 0 ] ;
1719
+ base = m [ 0 ] ;
1720
+ previous = '' ;
1721
+
1722
+ // On windows, check that the root exists. On unix there is no need.
1723
+ if ( isWindows && ! knownHard [ base ] ) {
1724
+ fs . lstat ( base , function ( err ) {
1725
+ if ( err ) return callback ( err ) ;
1726
+ knownHard [ base ] = true ;
1727
+ LOOP ( ) ;
1728
+ } ) ;
1729
+ } else {
1730
+ process . nextTick ( LOOP ) ;
1731
+ }
1732
+ }
1733
+
1734
+ // walk down the path, swapping out linked pathparts for their real
1735
+ // values
1736
+ function LOOP ( ) {
1737
+ // stop if scanned past end of path
1738
+ if ( pos >= p . length ) {
1739
+ return callback ( null , encodeRealpathResult ( p , options ) ) ;
1740
+ }
1741
+
1742
+ // find the next part
1743
+ nextPartRe . lastIndex = pos ;
1744
+ var result = nextPartRe . exec ( p ) ;
1745
+ previous = current ;
1746
+ current += result [ 0 ] ;
1747
+ base = previous + result [ 1 ] ;
1748
+ pos = nextPartRe . lastIndex ;
1749
+
1750
+ // continue if not a symlink
1751
+ if ( knownHard [ base ] ) {
1752
+ return process . nextTick ( LOOP ) ;
1753
+ }
1754
+
1755
+ return fs . lstat ( base , gotStat ) ;
1756
+ }
1757
+
1758
+ function gotStat ( err , stat ) {
1759
+ if ( err ) return callback ( err ) ;
1760
+
1761
+ // if not a symlink, skip to the next path part
1762
+ if ( ! stat . isSymbolicLink ( ) ) {
1763
+ knownHard [ base ] = true ;
1764
+ return process . nextTick ( LOOP ) ;
1765
+ }
1766
+
1767
+ // stat & read the link if not read before
1768
+ // call gotTarget as soon as the link target is known
1769
+ // dev/ino always return 0 on windows, so skip the check.
1770
+ if ( ! isWindows ) {
1771
+ var id = stat . dev . toString ( 32 ) + ':' + stat . ino . toString ( 32 ) ;
1772
+ if ( seenLinks . hasOwnProperty ( id ) ) {
1773
+ return gotTarget ( null , seenLinks [ id ] , base ) ;
1774
+ }
1775
+ }
1776
+ fs . stat ( base , function ( err ) {
1777
+ if ( err ) return callback ( err ) ;
1778
+
1779
+ fs . readlink ( base , function ( err , target ) {
1780
+ if ( ! isWindows ) seenLinks [ id ] = target ;
1781
+ gotTarget ( err , target ) ;
1782
+ } ) ;
1783
+ } ) ;
1784
+ }
1785
+
1786
+ function gotTarget ( err , target , base ) {
1787
+ if ( err ) return callback ( err ) ;
1788
+
1789
+ var resolvedLink = pathModule . resolve ( previous , target ) ;
1790
+ gotResolvedLink ( resolvedLink ) ;
1791
+ }
1792
+
1793
+ function gotResolvedLink ( resolvedLink ) {
1794
+ // resolve the link, then start over
1795
+ p = pathModule . resolve ( resolvedLink , p . slice ( pos ) ) ;
1796
+ start ( ) ;
1797
+ }
1798
+ } ;
1598
1799
1599
1800
fs . mkdtemp = function ( prefix , options , callback ) {
1600
1801
if ( ! prefix || typeof prefix !== 'string' )
0 commit comments