This repository has been archived by the owner on Mar 10, 2019. It is now read-only.
forked from mafintosh/level-filesystem
-
Notifications
You must be signed in to change notification settings - Fork 1
/
paths.js
116 lines (96 loc) · 2.85 KB
/
paths.js
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
var path = require('path');
var once = require('once');
var concat = require('concat-stream');
var octal = require('octal')
var stat = require('./stat');
var xtend = require('xtend');
var errno = require('./errno');
var ROOT = stat({
type: 'directory',
mode: octal(777),
size: 4096
});
var normalize = function(key) {
key = key[0] === '/' ? key : '/' + key;
key = path.normalize(key);
if (key === '/') return key;
return key[key.length - 1] === '/' ? key.slice(0, -1) : key;
};
var prefix = function(key) {
var depth = key.split('/').length.toString(36);
return '0000000000'.slice(depth.length) + depth + key;
};
module.exports = function(db) {
var that = {};
that.normalize = normalize;
that.get = function(key, cb) {
key = normalize(key);
if (key === '/') return process.nextTick(cb.bind(null, null, ROOT, '/'));
db.get(prefix(key), { valueEncoding: 'json' }, function(err, doc) {
if (err && err.notFound) return cb(errno.ENOENT(key), null, key);
if (err) return cb(err, null, key);
cb(null, stat(doc), key);
});
};
that.writable = function(key, cb) {
key = normalize(key);
if (key === '/') return process.nextTick(cb.bind(null, errno.EPERM(key)));
that.follow(path.dirname(key), function(err, parent) {
if (err) return cb(err);
if (!parent.isDirectory()) return cb(errno.ENOTDIR(key));
cb(null, key);
});
};
that.list = function(key, cb) {
key = normalize(key);
var start = prefix(key === '/' ? key : key + '/');
var keys = db.createKeyStream({ start: start, end: start + '\xff' });
cb = once(cb);
keys.on('error', cb);
keys.pipe(concat({ encoding: 'object' }, function(files) {
files = files.map(function(file) {
return file.split('/').pop();
});
cb(null, files);
}));
};
var resolve = function(dir, cb) {
var root = '/';
var parts = dir.split('/').slice(1);
var loop = function() {
that.get(path.join(root, parts.shift()), function(err, doc, key) {
if (err) return cb(err, doc, dir);
root = doc.target || key;
if (!parts.length) return cb(null, doc, key);
loop();
});
};
loop();
};
that.follow = function(key, cb) {
resolve(normalize(key), function loop(err, doc, key) {
if (err) return cb(err, null, key);
if (doc.target) return that.get(doc.target, loop);
cb(null, stat(doc), key);
});
};
that.update = function(key, opts, cb) {
that.get(key, function(err, doc, key) {
if (err) return cb(err);
if (key === '/') return cb(errno.EPERM(key));
that.put(key, xtend(doc, opts), cb);
});
};
that.put = function(key, opts, cb) {
that.writable(key, function(err, key) {
if (err) return cb(err);
db.put(prefix(key), stat(opts), { valueEncoding: 'json' }, cb);
});
};
that.del = function(key, cb) {
key = normalize(key);
if (key === '/') return process.nextTick(cb.bind(null, errno.EPERM(key)));
db.del(prefix(key), cb);
};
return that;
};