1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177 | 1×
1×
1×
1×
1×
1×
1×
1×
1×
1×
10040×
5020×
5020×
5020×
5020×
5020×
5020×
5020×
5020×
5020×
5020×
1×
1×
5019×
5019×
1×
5019×
5019×
1×
5003×
1×
5014×
5014×
5014×
1×
5014×
5014×
5014×
5014×
1×
5014×
5014×
5014×
5013×
1×
5014×
5014×
5012×
5012×
5012×
1×
1×
2×
2×
1×
2×
2×
1×
1×
1×
1×
4×
1×
4×
1×
5012×
5012×
1×
5012×
5012×
5012×
1×
13×
13×
13×
13×
1×
13×
2×
1×
5×
5×
3×
1×
10022×
1×
10022×
10020×
10020×
10020×
5002×
1×
10020×
10019×
3×
1×
3×
2×
1×
2×
2×
2×
1×
1×
| var inherits = require('util').inherits
var RandomAccess = require('random-access-storage')
var fs = require('fs')
var mkdirp = require('mkdirp')
var path = require('path')
var constants = fs.constants || require('constants')
var READONLY = constants.O_RDONLY
var READWRITE = constants.O_RDWR | constants.O_CREAT
module.exports = RandomAccessFile
function RandomAccessFile (filename, opts) {
if (!(this instanceof RandomAccessFile)) return new RandomAccessFile(filename, opts)
RandomAccess.call(this)
if (!opts) opts = {}
if (opts.directory) filename = path.join(opts.directory, filename)
this.directory = opts.directory || null
this.filename = filename
this.fd = 0
// makes random-access-storage open in writable mode first
if (opts.writable || opts.truncate) this.preferReadonly = false
this._length = opts.size || opts.length || 0
this._truncate = !!opts.truncate || this._length > 0
this._rmdir = !!opts.rmdir
}
inherits(RandomAccessFile, RandomAccess)
RandomAccessFile.prototype._open = function (req) {
var self = this
mkdirp(path.dirname(this.filename), ondir)
function ondir (err) {
Iif (err) return req.callback(err)
open(self, READWRITE, req)
}
}
RandomAccessFile.prototype._openReadonly = function (req) {
open(this, READONLY, req)
}
RandomAccessFile.prototype._write = function (req) {
var data = req.data
var fd = this.fd
fs.write(fd, data, 0, req.size, req.offset, onwrite)
function onwrite (err, wrote) {
Iif (err) return req.callback(err)
req.size -= wrote
req.offset += wrote
Eif (!req.size) return req.callback(null)
fs.write(fd, data, data.length - req.size, req.size, req.offset, onwrite)
}
}
RandomAccessFile.prototype._read = function (req) {
var data = req.data || Buffer.allocUnsafe(req.size)
var fd = this.fd
if (!req.size) return process.nextTick(readEmpty, req)
fs.read(fd, data, 0, req.size, req.offset, onread)
function onread (err, read) {
Iif (err) return req.callback(err)
if (!read) return req.callback(new Error('Could not satisfy length'))
req.size -= read
req.offset += read
if (!req.size) return req.callback(null, data)
fs.read(fd, data, data.length - req.size, req.size, req.offset, onread)
}
}
RandomAccessFile.prototype._del = function (req) {
var fd = this.fd
fs.fstat(fd, onstat)
function onstat (err, st) {
Iif (err) return req.callback(err)
if (req.offset + req.size < st.size) return req.callback(null)
fs.ftruncate(fd, req.offset, ontruncate)
}
function ontruncate (err) {
req.callback(err)
}
}
RandomAccessFile.prototype._stat = function (req) {
fs.fstat(this.fd, onstat)
function onstat (err, st) {
req.callback(err, st)
}
}
RandomAccessFile.prototype._close = function (req) {
var self = this
fs.close(this.fd, onclose)
function onclose (err) {
Iif (err) return req.callback(err)
self.fd = 0
req.callback(null)
}
}
RandomAccessFile.prototype._destroy = function (req) {
var self = this
var root = this.directory && path.resolve(path.join(this.directory, '.'))
var dir = path.resolve(path.dirname(this.filename))
fs.unlink(this.filename, onunlink)
function onunlink (err) {
if (!self._rmdir || !root || dir === root) return req.callback(err)
fs.rmdir(dir, onrmdir)
}
function onrmdir (err) {
dir = path.join(dir, '..')
if (err || dir === root) return req.callback(null)
fs.rmdir(dir, onrmdir)
}
}
function open (self, mode, req) {
fs.open(self.filename, mode, onopen)
function onopen (err, fd) {
if (err) return req.callback(err)
var old = self.fd
self.fd = fd
if (!old) return oncloseoldfd(null)
// if we are moving from readonly -> readwrite, close the old fd
fs.close(old, oncloseoldfd)
}
function oncloseoldfd (err) {
if (err) return onerrorafteropen(err)
if (!self._truncate || mode === READONLY) return req.callback(null)
fs.ftruncate(self.fd, self._length, ontruncate)
}
function ontruncate (err) {
if (err) return onerrorafteropen(err)
req.callback(null)
}
function onerrorafteropen (err) {
fs.close(self.fd, function () {
self.fd = 0
req.callback(err)
})
}
}
function readEmpty (req) {
req.callback(null, Buffer.alloc(0))
}
|