"Fossies" - the Fresh Open Source Software Archive

Member "Atom/resources/app/apm/node_modules/fstream/lib/writer.js" (8 Mar 2017, 10999 Bytes) of archive /windows/misc/atom-windows.zip:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Javascript source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

    1 module.exports = Writer
    2 
    3 var fs = require('graceful-fs')
    4 var inherits = require('inherits')
    5 var rimraf = require('rimraf')
    6 var mkdir = require('mkdirp')
    7 var path = require('path')
    8 var umask = process.platform === 'win32' ? 0 : process.umask()
    9 var getType = require('./get-type.js')
   10 var Abstract = require('./abstract.js')
   11 
   12 // Must do this *before* loading the child classes
   13 inherits(Writer, Abstract)
   14 
   15 Writer.dirmode = parseInt('0777', 8) & (~umask)
   16 Writer.filemode = parseInt('0666', 8) & (~umask)
   17 
   18 var DirWriter = require('./dir-writer.js')
   19 var LinkWriter = require('./link-writer.js')
   20 var FileWriter = require('./file-writer.js')
   21 var ProxyWriter = require('./proxy-writer.js')
   22 
   23 // props is the desired state.  current is optionally the current stat,
   24 // provided here so that subclasses can avoid statting the target
   25 // more than necessary.
   26 function Writer (props, current) {
   27   var self = this
   28 
   29   if (typeof props === 'string') {
   30     props = { path: props }
   31   }
   32 
   33   // polymorphism.
   34   // call fstream.Writer(dir) to get a DirWriter object, etc.
   35   var type = getType(props)
   36   var ClassType = Writer
   37 
   38   switch (type) {
   39     case 'Directory':
   40       ClassType = DirWriter
   41       break
   42     case 'File':
   43       ClassType = FileWriter
   44       break
   45     case 'Link':
   46     case 'SymbolicLink':
   47       ClassType = LinkWriter
   48       break
   49     case null:
   50     default:
   51       // Don't know yet what type to create, so we wrap in a proxy.
   52       ClassType = ProxyWriter
   53       break
   54   }
   55 
   56   if (!(self instanceof ClassType)) return new ClassType(props)
   57 
   58   // now get down to business.
   59 
   60   Abstract.call(self)
   61 
   62   if (!props.path) self.error('Must provide a path', null, true)
   63 
   64   // props is what we want to set.
   65   // set some convenience properties as well.
   66   self.type = props.type
   67   self.props = props
   68   self.depth = props.depth || 0
   69   self.clobber = props.clobber === false ? props.clobber : true
   70   self.parent = props.parent || null
   71   self.root = props.root || (props.parent && props.parent.root) || self
   72 
   73   self._path = self.path = path.resolve(props.path)
   74   if (process.platform === 'win32') {
   75     self.path = self._path = self.path.replace(/\?/g, '_')
   76     if (self._path.length >= 260) {
   77       self._swallowErrors = true
   78       self._path = '\\\\?\\' + self.path.replace(/\//g, '\\')
   79     }
   80   }
   81   self.basename = path.basename(props.path)
   82   self.dirname = path.dirname(props.path)
   83   self.linkpath = props.linkpath || null
   84 
   85   props.parent = props.root = null
   86 
   87   // console.error("\n\n\n%s setting size to", props.path, props.size)
   88   self.size = props.size
   89 
   90   if (typeof props.mode === 'string') {
   91     props.mode = parseInt(props.mode, 8)
   92   }
   93 
   94   self.readable = false
   95   self.writable = true
   96 
   97   // buffer until ready, or while handling another entry
   98   self._buffer = []
   99   self.ready = false
  100 
  101   self.filter = typeof props.filter === 'function' ? props.filter : null
  102 
  103   // start the ball rolling.
  104   // this checks what's there already, and then calls
  105   // self._create() to call the impl-specific creation stuff.
  106   self._stat(current)
  107 }
  108 
  109 // Calling this means that it's something we can't create.
  110 // Just assert that it's already there, otherwise raise a warning.
  111 Writer.prototype._create = function () {
  112   var self = this
  113   fs[self.props.follow ? 'stat' : 'lstat'](self._path, function (er) {
  114     if (er) {
  115       return self.warn('Cannot create ' + self._path + '\n' +
  116         'Unsupported type: ' + self.type, 'ENOTSUP')
  117     }
  118     self._finish()
  119   })
  120 }
  121 
  122 Writer.prototype._stat = function (current) {
  123   var self = this
  124   var props = self.props
  125   var stat = props.follow ? 'stat' : 'lstat'
  126   var who = self._proxy || self
  127 
  128   if (current) statCb(null, current)
  129   else fs[stat](self._path, statCb)
  130 
  131   function statCb (er, current) {
  132     if (self.filter && !self.filter.call(who, who, current)) {
  133       self._aborted = true
  134       self.emit('end')
  135       self.emit('close')
  136       return
  137     }
  138 
  139     // if it's not there, great.  We'll just create it.
  140     // if it is there, then we'll need to change whatever differs
  141     if (er || !current) {
  142       return create(self)
  143     }
  144 
  145     self._old = current
  146     var currentType = getType(current)
  147 
  148     // if it's a type change, then we need to clobber or error.
  149     // if it's not a type change, then let the impl take care of it.
  150     if (currentType !== self.type) {
  151       return rimraf(self._path, function (er) {
  152         if (er) return self.error(er)
  153         self._old = null
  154         create(self)
  155       })
  156     }
  157 
  158     // otherwise, just handle in the app-specific way
  159     // this creates a fs.WriteStream, or mkdir's, or whatever
  160     create(self)
  161   }
  162 }
  163 
  164 function create (self) {
  165   // console.error("W create", self._path, Writer.dirmode)
  166 
  167   // XXX Need to clobber non-dirs that are in the way,
  168   // unless { clobber: false } in the props.
  169   mkdir(path.dirname(self._path), Writer.dirmode, function (er, made) {
  170     // console.error("W created", path.dirname(self._path), er)
  171     if (er) return self.error(er)
  172 
  173     // later on, we have to set the mode and owner for these
  174     self._madeDir = made
  175     return self._create()
  176   })
  177 }
  178 
  179 function endChmod (self, want, current, path, cb) {
  180   var wantMode = want.mode
  181   var chmod = want.follow || self.type !== 'SymbolicLink'
  182     ? 'chmod' : 'lchmod'
  183 
  184   if (!fs[chmod]) return cb()
  185   if (typeof wantMode !== 'number') return cb()
  186 
  187   var curMode = current.mode & parseInt('0777', 8)
  188   wantMode = wantMode & parseInt('0777', 8)
  189   if (wantMode === curMode) return cb()
  190 
  191   fs[chmod](path, wantMode, cb)
  192 }
  193 
  194 function endChown (self, want, current, path, cb) {
  195   // Don't even try it unless root.  Too easy to EPERM.
  196   if (process.platform === 'win32') return cb()
  197   if (!process.getuid || process.getuid() !== 0) return cb()
  198   if (typeof want.uid !== 'number' &&
  199     typeof want.gid !== 'number') return cb()
  200 
  201   if (current.uid === want.uid &&
  202     current.gid === want.gid) return cb()
  203 
  204   var chown = (self.props.follow || self.type !== 'SymbolicLink')
  205     ? 'chown' : 'lchown'
  206   if (!fs[chown]) return cb()
  207 
  208   if (typeof want.uid !== 'number') want.uid = current.uid
  209   if (typeof want.gid !== 'number') want.gid = current.gid
  210 
  211   fs[chown](path, want.uid, want.gid, cb)
  212 }
  213 
  214 function endUtimes (self, want, current, path, cb) {
  215   if (!fs.utimes || process.platform === 'win32') return cb()
  216 
  217   var utimes = (want.follow || self.type !== 'SymbolicLink')
  218     ? 'utimes' : 'lutimes'
  219 
  220   if (utimes === 'lutimes' && !fs[utimes]) {
  221     utimes = 'utimes'
  222   }
  223 
  224   if (!fs[utimes]) return cb()
  225 
  226   var curA = current.atime
  227   var curM = current.mtime
  228   var meA = want.atime
  229   var meM = want.mtime
  230 
  231   if (meA === undefined) meA = curA
  232   if (meM === undefined) meM = curM
  233 
  234   if (!isDate(meA)) meA = new Date(meA)
  235   if (!isDate(meM)) meA = new Date(meM)
  236 
  237   if (meA.getTime() === curA.getTime() &&
  238     meM.getTime() === curM.getTime()) return cb()
  239 
  240   fs[utimes](path, meA, meM, cb)
  241 }
  242 
  243 // XXX This function is beastly.  Break it up!
  244 Writer.prototype._finish = function () {
  245   var self = this
  246 
  247   if (self._finishing) return
  248   self._finishing = true
  249 
  250   // console.error(" W Finish", self._path, self.size)
  251 
  252   // set up all the things.
  253   // At this point, we're already done writing whatever we've gotta write,
  254   // adding files to the dir, etc.
  255   var todo = 0
  256   var errState = null
  257   var done = false
  258 
  259   if (self._old) {
  260     // the times will almost *certainly* have changed.
  261     // adds the utimes syscall, but remove another stat.
  262     self._old.atime = new Date(0)
  263     self._old.mtime = new Date(0)
  264     // console.error(" W Finish Stale Stat", self._path, self.size)
  265     setProps(self._old)
  266   } else {
  267     var stat = self.props.follow ? 'stat' : 'lstat'
  268     // console.error(" W Finish Stating", self._path, self.size)
  269     fs[stat](self._path, function (er, current) {
  270       // console.error(" W Finish Stated", self._path, self.size, current)
  271       if (er) {
  272         // if we're in the process of writing out a
  273         // directory, it's very possible that the thing we're linking to
  274         // doesn't exist yet (especially if it was intended as a symlink),
  275         // so swallow ENOENT errors here and just soldier on.
  276         if (er.code === 'ENOENT' &&
  277           (self.type === 'Link' || self.type === 'SymbolicLink') &&
  278           process.platform === 'win32') {
  279           self.ready = true
  280           self.emit('ready')
  281           self.emit('end')
  282           self.emit('close')
  283           self.end = self._finish = function () {}
  284           return
  285         } else return self.error(er)
  286       }
  287       setProps(self._old = current)
  288     })
  289   }
  290 
  291   return
  292 
  293   function setProps (current) {
  294     todo += 3
  295     endChmod(self, self.props, current, self._path, next('chmod'))
  296     endChown(self, self.props, current, self._path, next('chown'))
  297     endUtimes(self, self.props, current, self._path, next('utimes'))
  298   }
  299 
  300   function next (what) {
  301     return function (er) {
  302       // console.error("   W Finish", what, todo)
  303       if (errState) return
  304       if (er) {
  305         er.fstream_finish_call = what
  306         return self.error(errState = er)
  307       }
  308       if (--todo > 0) return
  309       if (done) return
  310       done = true
  311 
  312       // we may still need to set the mode/etc. on some parent dirs
  313       // that were created previously.  delay end/close until then.
  314       if (!self._madeDir) return end()
  315       else endMadeDir(self, self._path, end)
  316 
  317       function end (er) {
  318         if (er) {
  319           er.fstream_finish_call = 'setupMadeDir'
  320           return self.error(er)
  321         }
  322         // all the props have been set, so we're completely done.
  323         self.emit('end')
  324         self.emit('close')
  325       }
  326     }
  327   }
  328 }
  329 
  330 function endMadeDir (self, p, cb) {
  331   var made = self._madeDir
  332   // everything *between* made and path.dirname(self._path)
  333   // needs to be set up.  Note that this may just be one dir.
  334   var d = path.dirname(p)
  335 
  336   endMadeDir_(self, d, function (er) {
  337     if (er) return cb(er)
  338     if (d === made) {
  339       return cb()
  340     }
  341     endMadeDir(self, d, cb)
  342   })
  343 }
  344 
  345 function endMadeDir_ (self, p, cb) {
  346   var dirProps = {}
  347   Object.keys(self.props).forEach(function (k) {
  348     dirProps[k] = self.props[k]
  349 
  350     // only make non-readable dirs if explicitly requested.
  351     if (k === 'mode' && self.type !== 'Directory') {
  352       dirProps[k] = dirProps[k] | parseInt('0111', 8)
  353     }
  354   })
  355 
  356   var todo = 3
  357   var errState = null
  358   fs.stat(p, function (er, current) {
  359     if (er) return cb(errState = er)
  360     endChmod(self, dirProps, current, p, next)
  361     endChown(self, dirProps, current, p, next)
  362     endUtimes(self, dirProps, current, p, next)
  363   })
  364 
  365   function next (er) {
  366     if (errState) return
  367     if (er) return cb(errState = er)
  368     if (--todo === 0) return cb()
  369   }
  370 }
  371 
  372 Writer.prototype.pipe = function () {
  373   this.error("Can't pipe from writable stream")
  374 }
  375 
  376 Writer.prototype.add = function () {
  377   this.error("Can't add to non-Directory type")
  378 }
  379 
  380 Writer.prototype.write = function () {
  381   return true
  382 }
  383 
  384 function objectToString (d) {
  385   return Object.prototype.toString.call(d)
  386 }
  387 
  388 function isDate (d) {
  389   return typeof d === 'object' && objectToString(d) === '[object Date]'
  390 }