]> gerrit.simantics Code Review - simantics/district.git/blob - org.simantics.maps.server/node/node-v4.8.0-win-x64/node_modules/npm/node_modules/lockfile/lockfile.js
Adding integrated tile server
[simantics/district.git] / org.simantics.maps.server / node / node-v4.8.0-win-x64 / node_modules / npm / node_modules / lockfile / lockfile.js
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