Projekt

Obecné

Profil

Stáhnout (8.61 KB) Statistiky
| Větev: | Revize:
1
var fs = require('fs')
2
var polyfills = require('./polyfills.js')
3
var legacy = require('./legacy-streams.js')
4
var clone = require('./clone.js')
5

    
6
var util = require('util')
7

    
8
/* istanbul ignore next - node 0.x polyfill */
9
var gracefulQueue
10
var previousSymbol
11

    
12
/* istanbul ignore else - node 0.x polyfill */
13
if (typeof Symbol === 'function' && typeof Symbol.for === 'function') {
14
  gracefulQueue = Symbol.for('graceful-fs.queue')
15
  // This is used in testing by future versions
16
  previousSymbol = Symbol.for('graceful-fs.previous')
17
} else {
18
  gracefulQueue = '___graceful-fs.queue'
19
  previousSymbol = '___graceful-fs.previous'
20
}
21

    
22
function noop () {}
23

    
24
var debug = noop
25
if (util.debuglog)
26
  debug = util.debuglog('gfs4')
27
else if (/\bgfs4\b/i.test(process.env.NODE_DEBUG || ''))
28
  debug = function() {
29
    var m = util.format.apply(util, arguments)
30
    m = 'GFS4: ' + m.split(/\n/).join('\nGFS4: ')
31
    console.error(m)
32
  }
33

    
34
// Once time initialization
35
if (!global[gracefulQueue]) {
36
  // This queue can be shared by multiple loaded instances
37
  var queue = []
38
  Object.defineProperty(global, gracefulQueue, {
39
    get: function() {
40
      return queue
41
    }
42
  })
43

    
44
  // Patch fs.close/closeSync to shared queue version, because we need
45
  // to retry() whenever a close happens *anywhere* in the program.
46
  // This is essential when multiple graceful-fs instances are
47
  // in play at the same time.
48
  fs.close = (function (fs$close) {
49
    function close (fd, cb) {
50
      return fs$close.call(fs, fd, function (err) {
51
        // This function uses the graceful-fs shared queue
52
        if (!err) {
53
          retry()
54
        }
55

    
56
        if (typeof cb === 'function')
57
          cb.apply(this, arguments)
58
      })
59
    }
60

    
61
    Object.defineProperty(close, previousSymbol, {
62
      value: fs$close
63
    })
64
    return close
65
  })(fs.close)
66

    
67
  fs.closeSync = (function (fs$closeSync) {
68
    function closeSync (fd) {
69
      // This function uses the graceful-fs shared queue
70
      fs$closeSync.apply(fs, arguments)
71
      retry()
72
    }
73

    
74
    Object.defineProperty(closeSync, previousSymbol, {
75
      value: fs$closeSync
76
    })
77
    return closeSync
78
  })(fs.closeSync)
79

    
80
  if (/\bgfs4\b/i.test(process.env.NODE_DEBUG || '')) {
81
    process.on('exit', function() {
82
      debug(global[gracefulQueue])
83
      require('assert').equal(global[gracefulQueue].length, 0)
84
    })
85
  }
86
}
87

    
88
module.exports = patch(clone(fs))
89
if (process.env.TEST_GRACEFUL_FS_GLOBAL_PATCH && !fs.__patched) {
90
    module.exports = patch(fs)
91
    fs.__patched = true;
92
}
93

    
94
function patch (fs) {
95
  // Everything that references the open() function needs to be in here
96
  polyfills(fs)
97
  fs.gracefulify = patch
98

    
99
  fs.createReadStream = createReadStream
100
  fs.createWriteStream = createWriteStream
101
  var fs$readFile = fs.readFile
102
  fs.readFile = readFile
103
  function readFile (path, options, cb) {
104
    if (typeof options === 'function')
105
      cb = options, options = null
106

    
107
    return go$readFile(path, options, cb)
108

    
109
    function go$readFile (path, options, cb) {
110
      return fs$readFile(path, options, function (err) {
111
        if (err && (err.code === 'EMFILE' || err.code === 'ENFILE'))
112
          enqueue([go$readFile, [path, options, cb]])
113
        else {
114
          if (typeof cb === 'function')
115
            cb.apply(this, arguments)
116
          retry()
117
        }
118
      })
119
    }
120
  }
121

    
122
  var fs$writeFile = fs.writeFile
123
  fs.writeFile = writeFile
124
  function writeFile (path, data, options, cb) {
125
    if (typeof options === 'function')
126
      cb = options, options = null
127

    
128
    return go$writeFile(path, data, options, cb)
129

    
130
    function go$writeFile (path, data, options, cb) {
131
      return fs$writeFile(path, data, options, function (err) {
132
        if (err && (err.code === 'EMFILE' || err.code === 'ENFILE'))
133
          enqueue([go$writeFile, [path, data, options, cb]])
134
        else {
135
          if (typeof cb === 'function')
136
            cb.apply(this, arguments)
137
          retry()
138
        }
139
      })
140
    }
141
  }
142

    
143
  var fs$appendFile = fs.appendFile
144
  if (fs$appendFile)
145
    fs.appendFile = appendFile
146
  function appendFile (path, data, options, cb) {
147
    if (typeof options === 'function')
148
      cb = options, options = null
149

    
150
    return go$appendFile(path, data, options, cb)
151

    
152
    function go$appendFile (path, data, options, cb) {
153
      return fs$appendFile(path, data, options, function (err) {
154
        if (err && (err.code === 'EMFILE' || err.code === 'ENFILE'))
155
          enqueue([go$appendFile, [path, data, options, cb]])
156
        else {
157
          if (typeof cb === 'function')
158
            cb.apply(this, arguments)
159
          retry()
160
        }
161
      })
162
    }
163
  }
164

    
165
  var fs$readdir = fs.readdir
166
  fs.readdir = readdir
167
  function readdir (path, options, cb) {
168
    var args = [path]
169
    if (typeof options !== 'function') {
170
      args.push(options)
171
    } else {
172
      cb = options
173
    }
174
    args.push(go$readdir$cb)
175

    
176
    return go$readdir(args)
177

    
178
    function go$readdir$cb (err, files) {
179
      if (files && files.sort)
180
        files.sort()
181

    
182
      if (err && (err.code === 'EMFILE' || err.code === 'ENFILE'))
183
        enqueue([go$readdir, [args]])
184

    
185
      else {
186
        if (typeof cb === 'function')
187
          cb.apply(this, arguments)
188
        retry()
189
      }
190
    }
191
  }
192

    
193
  function go$readdir (args) {
194
    return fs$readdir.apply(fs, args)
195
  }
196

    
197
  if (process.version.substr(0, 4) === 'v0.8') {
198
    var legStreams = legacy(fs)
199
    ReadStream = legStreams.ReadStream
200
    WriteStream = legStreams.WriteStream
201
  }
202

    
203
  var fs$ReadStream = fs.ReadStream
204
  if (fs$ReadStream) {
205
    ReadStream.prototype = Object.create(fs$ReadStream.prototype)
206
    ReadStream.prototype.open = ReadStream$open
207
  }
208

    
209
  var fs$WriteStream = fs.WriteStream
210
  if (fs$WriteStream) {
211
    WriteStream.prototype = Object.create(fs$WriteStream.prototype)
212
    WriteStream.prototype.open = WriteStream$open
213
  }
214

    
215
  Object.defineProperty(fs, 'ReadStream', {
216
    get: function () {
217
      return ReadStream
218
    },
219
    set: function (val) {
220
      ReadStream = val
221
    },
222
    enumerable: true,
223
    configurable: true
224
  })
225
  Object.defineProperty(fs, 'WriteStream', {
226
    get: function () {
227
      return WriteStream
228
    },
229
    set: function (val) {
230
      WriteStream = val
231
    },
232
    enumerable: true,
233
    configurable: true
234
  })
235

    
236
  // legacy names
237
  var FileReadStream = ReadStream
238
  Object.defineProperty(fs, 'FileReadStream', {
239
    get: function () {
240
      return FileReadStream
241
    },
242
    set: function (val) {
243
      FileReadStream = val
244
    },
245
    enumerable: true,
246
    configurable: true
247
  })
248
  var FileWriteStream = WriteStream
249
  Object.defineProperty(fs, 'FileWriteStream', {
250
    get: function () {
251
      return FileWriteStream
252
    },
253
    set: function (val) {
254
      FileWriteStream = val
255
    },
256
    enumerable: true,
257
    configurable: true
258
  })
259

    
260
  function ReadStream (path, options) {
261
    if (this instanceof ReadStream)
262
      return fs$ReadStream.apply(this, arguments), this
263
    else
264
      return ReadStream.apply(Object.create(ReadStream.prototype), arguments)
265
  }
266

    
267
  function ReadStream$open () {
268
    var that = this
269
    open(that.path, that.flags, that.mode, function (err, fd) {
270
      if (err) {
271
        if (that.autoClose)
272
          that.destroy()
273

    
274
        that.emit('error', err)
275
      } else {
276
        that.fd = fd
277
        that.emit('open', fd)
278
        that.read()
279
      }
280
    })
281
  }
282

    
283
  function WriteStream (path, options) {
284
    if (this instanceof WriteStream)
285
      return fs$WriteStream.apply(this, arguments), this
286
    else
287
      return WriteStream.apply(Object.create(WriteStream.prototype), arguments)
288
  }
289

    
290
  function WriteStream$open () {
291
    var that = this
292
    open(that.path, that.flags, that.mode, function (err, fd) {
293
      if (err) {
294
        that.destroy()
295
        that.emit('error', err)
296
      } else {
297
        that.fd = fd
298
        that.emit('open', fd)
299
      }
300
    })
301
  }
302

    
303
  function createReadStream (path, options) {
304
    return new fs.ReadStream(path, options)
305
  }
306

    
307
  function createWriteStream (path, options) {
308
    return new fs.WriteStream(path, options)
309
  }
310

    
311
  var fs$open = fs.open
312
  fs.open = open
313
  function open (path, flags, mode, cb) {
314
    if (typeof mode === 'function')
315
      cb = mode, mode = null
316

    
317
    return go$open(path, flags, mode, cb)
318

    
319
    function go$open (path, flags, mode, cb) {
320
      return fs$open(path, flags, mode, function (err, fd) {
321
        if (err && (err.code === 'EMFILE' || err.code === 'ENFILE'))
322
          enqueue([go$open, [path, flags, mode, cb]])
323
        else {
324
          if (typeof cb === 'function')
325
            cb.apply(this, arguments)
326
          retry()
327
        }
328
      })
329
    }
330
  }
331

    
332
  return fs
333
}
334

    
335
function enqueue (elem) {
336
  debug('ENQUEUE', elem[0].name, elem[1])
337
  global[gracefulQueue].push(elem)
338
}
339

    
340
function retry () {
341
  var elem = global[gracefulQueue].shift()
342
  if (elem) {
343
    debug('RETRY', elem[0].name, elem[1])
344
    elem[0].apply(null, elem[1])
345
  }
346
}
(4-4/7)