| | |
| | | console.log('source', src); |
| | | console.log('destination', dst); |
| | | |
| | | // say we completed (for now) |
| | | callback(null); |
| | | CLOUDFS.reconcile(mount, src, dst, callback); |
| | | }); |
| | | }); |
| | | }, |
| | |
| | | }, function(e) { |
| | | callback(e || new Error('failed request')); |
| | | }); |
| | | }, |
| | | // Fetching local and remote files |
| | | loadLocalEntry: function(path, callback) { |
| | | var stat, node; |
| | | |
| | | try { |
| | | var lookup = FS.lookupPath(path); |
| | | node = lookup.node; |
| | | stat = FS.stat(path); |
| | | } catch (e) { |
| | | return callback(e); |
| | | } |
| | | |
| | | if (FS.isDir(stat.mode)) { |
| | | return callback(null, { timestamp: stat.mtime, mode: stat.mode }); |
| | | } else if (FS.isFile(stat.mode)) { |
| | | // Performance consideration: storing a normal JavaScript array to a IndexedDB is much slower than storing a typed array. |
| | | // Therefore always convert the file contents to a typed array first before writing the data to IndexedDB. |
| | | node.contents = MEMFS.getFileDataAsTypedArray(node); |
| | | return callback(null, { timestamp: stat.mtime, mode: stat.mode, contents: node.contents }); |
| | | } else { |
| | | return callback(new Error('node type not supported')); |
| | | } |
| | | }, |
| | | loadRemoteEntry: function(mount, pathinfo, callback) { |
| | | if (pathinfo.type == 'file') { |
| | | mount.opts.provider.downloadFile(mount.opts.cloud, pathinfo.url, |
| | | function(data) { |
| | | callback(null, { contents: data, timestamp: pathinfo.timestamp, mode: {{{ cDefine('S_IFREG') | 0777 }}} }); |
| | | }, |
| | | function(e) { |
| | | callback(e); |
| | | }); |
| | | } else { |
| | | callback(null, { timestamp: pathinfo.timestamp, mode: {{{ cDefine('S_IFDIR') | 0777 }}} }); |
| | | } |
| | | }, |
| | | // storing local and remote files |
| | | storeLocalEntry: function(path, entry, callback) { |
| | | try { |
| | | if (FS.isDir(entry.mode)) { |
| | | FS.mkdir(path, entry.mode); |
| | | } else if (FS.isFile(entry.mode)) { |
| | | FS.writeFile(path, entry.contents, { encoding: 'binary', canOwn: true }); |
| | | } else { |
| | | return callback(new Error('node type not supported')); |
| | | } |
| | | |
| | | FS.utime(path, entry.timestamp, entry.timestamp); |
| | | } catch (e) { |
| | | return callback(e); |
| | | } |
| | | |
| | | callback(null); |
| | | }, |
| | | storeRemoteEntry: function(mount, pathinfo, entry, callback) { |
| | | if (FS.isFile(entry.mode)) { |
| | | mount.opts.provider.uploadFile(mount.opts.cloud, pathinfo.path, entry.contents, function() { |
| | | callback(null); |
| | | }, |
| | | function(e) { |
| | | callback(e); |
| | | }) |
| | | } |
| | | }, |
| | | // handling the diffing of "haves" and "have nots" |
| | | reconcile: function(mount, src, dst, callback) { |
| | | var total = 0; |
| | | |
| | | var create = []; |
| | | Object.keys(src.entries).forEach(function (key) { |
| | | var e = src.entries[key]; |
| | | var e2 = dst.entries[key]; |
| | | if (!e2 || e.timestamp > e2.timestamp) { |
| | | create.push(key); |
| | | total++; |
| | | } |
| | | }); |
| | | /* |
| | | var remove = []; |
| | | Object.keys(dst.entries).forEach(function (key) { |
| | | var e = dst.entries[key]; |
| | | var e2 = src.entries[key]; |
| | | if (!e2) { |
| | | remove.push(key); |
| | | total++; |
| | | } |
| | | }); |
| | | */ |
| | | if (!total) { |
| | | return callback(null); |
| | | } |
| | | |
| | | var completed = 0; |
| | | |
| | | function done(err) { |
| | | console.log('Done called', completed, total); |
| | | if (err) { |
| | | if (!done.errored) { |
| | | done.errored = true; |
| | | return callback(err); |
| | | } |
| | | return; |
| | | } |
| | | if (++completed >= total) { |
| | | return callback(null); |
| | | } |
| | | }; |
| | | |
| | | // sort paths in ascending order so directory entries are created |
| | | // before the files inside them |
| | | create.sort().forEach(function (path) { |
| | | var pathinfo = src.entries[path]; |
| | | if (dst.type === 'local') { |
| | | CLOUDFS.loadRemoteEntry(mount, pathinfo, function (err, entry) { |
| | | if (err) return done(err); |
| | | CLOUDFS.storeLocalEntry(path, entry, done); |
| | | }); |
| | | } else { |
| | | CLOUDFS.loadLocalEntry(path, function (err, entry) { |
| | | if (err) return done(err); |
| | | CLOUDFS.storeRemoteEntry(mount, pathinfo, entry, done); |
| | | }); |
| | | } |
| | | }); |
| | | |
| | | return; |
| | | |
| | | // sort paths in descending order so files are deleted before their |
| | | // parent directories |
| | | remove.sort().reverse().forEach(function(path) { |
| | | var info = dst.entries[path]; |
| | | if (dst.type === 'local') { |
| | | CLOUDFS.removeLocalEntry(path, info, done); |
| | | } else { |
| | | CLOUDFS.removeRemoteEntry(path, info, done); |
| | | } |
| | | }); |
| | | } |
| | | } |
| | | }; |