"Fossies" - the Fresh Open Source Software Archive

Member "Atom/resources/app/apm/node_modules/lockfile/lockfile.js" (7 Feb 2017, 8226 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 var fs = require('fs')
    2 
    3 var wx = 'wx'
    4 if (process.version.match(/^v0\.[0-6]/)) {
    5   var c = require('constants')
    6   wx = c.O_TRUNC | c.O_CREAT | c.O_WRONLY | c.O_EXCL
    7 }
    8 
    9 var os = require('os')
   10 exports.filetime = 'ctime'
   11 if (os.platform() == "win32") {
   12   exports.filetime = 'mtime'
   13 }
   14 
   15 var debug
   16 var util = require('util')
   17 if (util.debuglog)
   18   debug = util.debuglog('LOCKFILE')
   19 else if (/\blockfile\b/i.test(process.env.NODE_DEBUG))
   20   debug = function() {
   21     var msg = util.format.apply(util, arguments)
   22     console.error('LOCKFILE %d %s', process.pid, msg)
   23   }
   24 else
   25   debug = function() {}
   26 
   27 var locks = {}
   28 
   29 function hasOwnProperty (obj, prop) {
   30   return Object.prototype.hasOwnProperty.call(obj, prop)
   31 }
   32 
   33 process.on('exit', function () {
   34   debug('exit listener')
   35   // cleanup
   36   Object.keys(locks).forEach(exports.unlockSync)
   37 })
   38 
   39 // XXX https://github.com/joyent/node/issues/3555
   40 // Remove when node 0.8 is deprecated.
   41 if (/^v0\.[0-8]\./.test(process.version)) {
   42   debug('uncaughtException, version = %s', process.version)
   43   process.on('uncaughtException', function H (er) {
   44     debug('uncaughtException')
   45     var l = process.listeners('uncaughtException').filter(function (h) {
   46       return h !== H
   47     })
   48     if (!l.length) {
   49       // cleanup
   50       try { Object.keys(locks).forEach(exports.unlockSync) } catch (e) {}
   51       process.removeListener('uncaughtException', H)
   52       throw er
   53     }
   54   })
   55 }
   56 
   57 exports.unlock = function (path, cb) {
   58   debug('unlock', path)
   59   // best-effort.  unlocking an already-unlocked lock is a noop
   60   delete locks[path]
   61   fs.unlink(path, function (unlinkEr) { cb() })
   62 }
   63 
   64 exports.unlockSync = function (path) {
   65   debug('unlockSync', path)
   66   // best-effort.  unlocking an already-unlocked lock is a noop
   67   try { fs.unlinkSync(path) } catch (er) {}
   68   delete locks[path]
   69 }
   70 
   71 
   72 // if the file can be opened in readonly mode, then it's there.
   73 // if the error is something other than ENOENT, then it's not.
   74 exports.check = function (path, opts, cb) {
   75   if (typeof opts === 'function') cb = opts, opts = {}
   76   debug('check', path, opts)
   77   fs.open(path, 'r', function (er, fd) {
   78     if (er) {
   79       if (er.code !== 'ENOENT') return cb(er)
   80       return cb(null, false)
   81     }
   82 
   83     if (!opts.stale) {
   84       return fs.close(fd, function (er) {
   85         return cb(er, true)
   86       })
   87     }
   88 
   89     fs.fstat(fd, function (er, st) {
   90       if (er) return fs.close(fd, function (er2) {
   91         return cb(er)
   92       })
   93 
   94       fs.close(fd, function (er) {
   95         var age = Date.now() - st[exports.filetime].getTime()
   96         return cb(er, age <= opts.stale)
   97       })
   98     })
   99   })
  100 }
  101 
  102 exports.checkSync = function (path, opts) {
  103   opts = opts || {}
  104   debug('checkSync', path, opts)
  105   if (opts.wait) {
  106     throw new Error('opts.wait not supported sync for obvious reasons')
  107   }
  108 
  109   try {
  110     var fd = fs.openSync(path, 'r')
  111   } catch (er) {
  112     if (er.code !== 'ENOENT') throw er
  113     return false
  114   }
  115 
  116   if (!opts.stale) {
  117     try { fs.closeSync(fd) } catch (er) {}
  118     return true
  119   }
  120 
  121   // file exists.  however, might be stale
  122   if (opts.stale) {
  123     try {
  124       var st = fs.fstatSync(fd)
  125     } finally {
  126       fs.closeSync(fd)
  127     }
  128     var age = Date.now() - st[exports.filetime].getTime()
  129     return (age <= opts.stale)
  130   }
  131 }
  132 
  133 
  134 
  135 var req = 1
  136 exports.lock = function (path, opts, cb) {
  137   if (typeof opts === 'function') cb = opts, opts = {}
  138   opts.req = opts.req || req++
  139   debug('lock', path, opts)
  140   opts.start = opts.start || Date.now()
  141 
  142   if (typeof opts.retries === 'number' && opts.retries > 0) {
  143     debug('has retries', opts.retries)
  144     var retries = opts.retries
  145     opts.retries = 0
  146     cb = (function (orig) { return function cb (er, fd) {
  147       debug('retry-mutated callback')
  148       retries -= 1
  149       if (!er || retries < 0) return orig(er, fd)
  150 
  151       debug('lock retry', path, opts)
  152 
  153       if (opts.retryWait) setTimeout(retry, opts.retryWait)
  154       else retry()
  155 
  156       function retry () {
  157         opts.start = Date.now()
  158         debug('retrying', opts.start)
  159         exports.lock(path, opts, cb)
  160       }
  161     }})(cb)
  162   }
  163 
  164   // try to engage the lock.
  165   // if this succeeds, then we're in business.
  166   fs.open(path, wx, function (er, fd) {
  167     if (!er) {
  168       debug('locked', path, fd)
  169       locks[path] = fd
  170       return fs.close(fd, function () {
  171         return cb()
  172       })
  173     }
  174 
  175     // something other than "currently locked"
  176     // maybe eperm or something.
  177     if (er.code !== 'EEXIST') return cb(er)
  178 
  179     // someone's got this one.  see if it's valid.
  180     if (!opts.stale) return notStale(er, path, opts, cb)
  181 
  182     return maybeStale(er, path, opts, false, cb)
  183   })
  184 }
  185 
  186 
  187 // Staleness checking algorithm
  188 // 1. acquire $lock, fail
  189 // 2. stat $lock, find that it is stale
  190 // 3. acquire $lock.STALE
  191 // 4. stat $lock, assert that it is still stale
  192 // 5. unlink $lock
  193 // 6. link $lock.STALE $lock
  194 // 7. unlink $lock.STALE
  195 // On any failure, clean up whatever we've done, and raise the error.
  196 function maybeStale (originalEr, path, opts, hasStaleLock, cb) {
  197   fs.stat(path, function (statEr, st) {
  198     if (statEr) {
  199       if (statEr.code === 'ENOENT') {
  200         // expired already!
  201         opts.stale = false
  202         debug('lock stale enoent retry', path, opts)
  203         exports.lock(path, opts, cb)
  204         return
  205       }
  206       return cb(statEr)
  207     }
  208 
  209     var age = Date.now() - st[exports.filetime].getTime()
  210     if (age <= opts.stale) return notStale(originalEr, path, opts, cb)
  211 
  212     debug('lock stale', path, opts)
  213     if (hasStaleLock) {
  214       exports.unlock(path, function (er) {
  215         if (er) return cb(er)
  216         debug('lock stale retry', path, opts)
  217         fs.link(path + '.STALE', path, function (er) {
  218           fs.unlink(path + '.STALE', function () {
  219             // best effort.  if the unlink fails, oh well.
  220             cb(er)
  221           })
  222         })
  223       })
  224     } else {
  225       debug('acquire .STALE file lock', opts)
  226       exports.lock(path + '.STALE', opts, function (er) {
  227         if (er) return cb(er)
  228         maybeStale(originalEr, path, opts, true, cb)
  229       })
  230     }
  231   })
  232 }
  233 
  234 function notStale (er, path, opts, cb) {
  235   debug('notStale', path, opts)
  236 
  237   // if we can't wait, then just call it a failure
  238   if (typeof opts.wait !== 'number' || opts.wait <= 0)
  239     return cb(er)
  240 
  241   // poll for some ms for the lock to clear
  242   var now = Date.now()
  243   var start = opts.start || now
  244   var end = start + opts.wait
  245 
  246   if (end <= now)
  247     return cb(er)
  248 
  249   debug('now=%d, wait until %d (delta=%d)', start, end, end-start)
  250   var wait = Math.min(end - start, opts.pollPeriod || 100)
  251   var timer = setTimeout(poll, wait)
  252 
  253   function poll () {
  254     debug('notStale, polling', path, opts)
  255     exports.lock(path, opts, cb)
  256   }
  257 }
  258 
  259 exports.lockSync = function (path, opts) {
  260   opts = opts || {}
  261   opts.req = opts.req || req++
  262   debug('lockSync', path, opts)
  263   if (opts.wait || opts.retryWait) {
  264     throw new Error('opts.wait not supported sync for obvious reasons')
  265   }
  266 
  267   try {
  268     var fd = fs.openSync(path, wx)
  269     locks[path] = fd
  270     try { fs.closeSync(fd) } catch (er) {}
  271     debug('locked sync!', path, fd)
  272     return
  273   } catch (er) {
  274     if (er.code !== 'EEXIST') return retryThrow(path, opts, er)
  275 
  276     if (opts.stale) {
  277       var st = fs.statSync(path)
  278       var ct = st[exports.filetime].getTime()
  279       if (!(ct % 1000) && (opts.stale % 1000)) {
  280         // probably don't have subsecond resolution.
  281         // round up the staleness indicator.
  282         // Yes, this will be wrong 1/1000 times on platforms
  283         // with subsecond stat precision, but that's acceptable
  284         // in exchange for not mistakenly removing locks on
  285         // most other systems.
  286         opts.stale = 1000 * Math.ceil(opts.stale / 1000)
  287       }
  288       var age = Date.now() - ct
  289       if (age > opts.stale) {
  290         debug('lockSync stale', path, opts, age)
  291         exports.unlockSync(path)
  292         return exports.lockSync(path, opts)
  293       }
  294     }
  295 
  296     // failed to lock!
  297     debug('failed to lock', path, opts, er)
  298     return retryThrow(path, opts, er)
  299   }
  300 }
  301 
  302 function retryThrow (path, opts, er) {
  303   if (typeof opts.retries === 'number' && opts.retries > 0) {
  304     var newRT = opts.retries - 1
  305     debug('retryThrow', path, opts, newRT)
  306     opts.retries = newRT
  307     return exports.lockSync(path, opts)
  308   }
  309   throw er
  310 }
  311