@@ -26,6 +26,18 @@ function closeFd(propagatedErr, fd, callback) {
2626 }
2727}
2828
29+ function isValidUnixId ( id ) {
30+ if ( typeof id !== 'number' ) {
31+ return false ;
32+ }
33+
34+ if ( id < 0 ) {
35+ return false ;
36+ }
37+
38+ return true ;
39+ }
40+
2941function getModeDiff ( fsMode , vinylMode ) {
3042 var modeDiff = 0 ;
3143
@@ -66,6 +78,40 @@ function getTimesDiff(fsStat, vinylStat) {
6678 return timesDiff ;
6779}
6880
81+ function getOwnerDiff ( fsStat , vinylStat ) {
82+ if ( ! isValidUnixId ( vinylStat . uid ) &&
83+ ! isValidUnixId ( vinylStat . gid ) ) {
84+ return ;
85+ }
86+
87+ if ( ( ! isValidUnixId ( fsStat . uid ) && ! isValidUnixId ( vinylStat . uid ) ) ||
88+ ( ! isValidUnixId ( fsStat . gid ) && ! isValidUnixId ( vinylStat . gid ) ) ) {
89+ return ;
90+ }
91+
92+ var uid = fsStat . uid ; // Default to current uid.
93+ if ( isValidUnixId ( vinylStat . uid ) ) {
94+ uid = vinylStat . uid ;
95+ }
96+
97+ var gid = fsStat . gid ; // Default to current gid.
98+ if ( isValidUnixId ( vinylStat . gid ) ) {
99+ gid = vinylStat . gid ;
100+ }
101+
102+ if ( isEqual ( uid , fsStat . uid ) &&
103+ isEqual ( gid , fsStat . gid ) ) {
104+ return ;
105+ }
106+
107+ var ownerDiff = {
108+ uid : uid ,
109+ gid : gid ,
110+ } ;
111+
112+ return ownerDiff ;
113+ }
114+
69115function isOwner ( fsStat ) {
70116 var hasGetuid = ( typeof process . getuid === 'function' ) ;
71117 var hasGeteuid = ( typeof process . geteuid === 'function' ) ;
@@ -106,11 +152,14 @@ function updateMetadata(fd, file, callback) {
106152 // Check if atime/mtime need to be updated
107153 var timesDiff = getTimesDiff ( stat , file . stat ) ;
108154
155+ // Check if uid/gid need to be updated
156+ var ownerDiff = getOwnerDiff ( stat , file . stat ) ;
157+
109158 // Set file.stat to the reflect current state on disk
110159 assign ( file . stat , stat ) ;
111160
112161 // Nothing to do
113- if ( ! modeDiff && ! timesDiff ) {
162+ if ( ! modeDiff && ! timesDiff && ! ownerDiff ) {
114163 return callback ( null ) ;
115164 }
116165
@@ -123,7 +172,10 @@ function updateMetadata(fd, file, callback) {
123172 if ( modeDiff ) {
124173 return mode ( ) ;
125174 }
126- times ( ) ;
175+ if ( timesDiff ) {
176+ return times ( ) ;
177+ }
178+ owner ( ) ;
127179
128180 function mode ( ) {
129181 var mode = stat . mode ^ modeDiff ;
@@ -137,6 +189,9 @@ function updateMetadata(fd, file, callback) {
137189 if ( timesDiff ) {
138190 return times ( fchmodErr ) ;
139191 }
192+ if ( ownerDiff ) {
193+ return owner ( fchmodErr ) ;
194+ }
140195 callback ( fchmodErr ) ;
141196 }
142197 }
@@ -149,9 +204,24 @@ function updateMetadata(fd, file, callback) {
149204 file . stat . atime = timesDiff . atime ;
150205 file . stat . mtime = timesDiff . mtime ;
151206 }
207+ if ( ownerDiff ) {
208+ return owner ( fchmodErr || futimesErr ) ;
209+ }
152210 callback ( fchmodErr || futimesErr ) ;
153211 }
154212 }
213+
214+ function owner ( earlierErr ) {
215+ fs . fchown ( fd , ownerDiff . uid , ownerDiff . gid , onFchown ) ;
216+
217+ function onFchown ( fchownErr ) {
218+ if ( ! fchownErr ) {
219+ file . stat . uid = ownerDiff . uid ;
220+ file . stat . gid = ownerDiff . gid ;
221+ }
222+ callback ( earlierErr || fchownErr ) ;
223+ }
224+ }
155225 }
156226}
157227
@@ -257,8 +327,10 @@ function mkdirp(dirpath, customMode, callback) {
257327
258328module . exports = {
259329 closeFd : closeFd ,
330+ isValidUnixId : isValidUnixId ,
260331 getModeDiff : getModeDiff ,
261332 getTimesDiff : getTimesDiff ,
333+ getOwnerDiff : getOwnerDiff ,
262334 isOwner : isOwner ,
263335 updateMetadata : updateMetadata ,
264336 writeFile : writeFile ,
0 commit comments