Commit b3e6dbdd authored by Samuel Elliott's avatar Samuel Elliott

Initial commit

parents
{
"presets": [
["env", {
"targets": {
"node": "8.10"
}
}]
]
}
root = true
[*]
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
indent_style = space
indent_size = 4
[*.md]
trim_trailing_whitespace = false
node_modules
dist
mount
import gulp from 'gulp';
import pump from 'pump';
import babel from 'gulp-babel';
gulp.task('build', function () {
return pump([
gulp.src('src/**/*.js'),
babel(),
gulp.dest('dist')
]);
});
gulp.task('watch', gulp.series('build', function () {
return gulp.watch('src/**/*.js', gulp.series('build'));
}));
This diff is collapsed.
{
"name": "icloud-drive-fs",
"private": true,
"main": "dist/index.js",
"dependencies": {
"fuse-bindings": "^2.11.2",
"yargs": "^12.0.2"
},
"devDependencies": {
"@babel/core": "^7.1.0",
"babel-preset-env": "^1.7.0",
"eslint": "^5.6.0",
"eslint-config-google": "^0.10.0",
"gulp": "^4.0.0",
"gulp-babel": "^8.0.0",
"pump": "^3.0.0"
}
}
import fuse from 'fuse-bindings';
/**
* Promisified wrapper for fuse-bindings.
*/
function wrapHandler(handler, no_code) {
return async (...args) => {
const callback = args.pop();
try {
const result = await handler.call(undefined, ...args, fuse.context());
console.debug('Handler', handler.name, 'returned', result, '- returning', no_code ? [result] : [0, result]);
if (no_code) callback(result);
else callback(0, result);
} catch (err) {
console.error('Handler', handler.name, 'threw', err, '- returning', err);
callback(err);
}
};
}
export default {
mount(mount_path, handlers, options) {
return new Promise((resolve, reject) => {
const ops = {};
if (handlers.init) ops.init = wrapHandler(handlers.init);
if (handlers.access) ops.access = wrapHandler(handlers.access);
if (handlers.statfs) ops.statfs = wrapHandler(handlers.statfs);
if (handlers.getattr) ops.getattr = wrapHandler(handlers.getattr);
if (handlers.fgetattr) ops.fgetattr = wrapHandler(handlers.fgetattr);
if (handlers.flush) ops.flush = wrapHandler(handlers.flush);
if (handlers.fsync) ops.fsync = wrapHandler(handlers.fsync);
if (handlers.fsyncdir) ops.fsyncdir = wrapHandler(handlers.fsyncdir);
if (handlers.readdir) ops.readdir = wrapHandler(handlers.readdir);
if (handlers.truncate) ops.truncate = wrapHandler(handlers.truncate);
if (handlers.ftruncate) ops.ftruncate = wrapHandler(handlers.ftruncate);
if (handlers.readlink) ops.readlink = wrapHandler(handlers.readlink);
if (handlers.chown) ops.chown = wrapHandler(handlers.chown);
if (handlers.chmod) ops.chmod = wrapHandler(handlers.chmod);
if (handlers.mknod) ops.mknod = wrapHandler(handlers.mknod);
if (handlers.setxattr) ops.setxattr = wrapHandler(handlers.setxattr);
if (handlers.getxattr) ops.getxattr = wrapHandler(handlers.getxattr);
if (handlers.listxattr) ops.listxattr = wrapHandler(handlers.listxattr);
if (handlers.removexattr) ops.removexattr = wrapHandler(handlers.removexattr);
if (handlers.open) ops.open = wrapHandler(handlers.open);
if (handlers.opendir) ops.opendir = wrapHandler(handlers.opendir);
if (handlers.read) ops.read = wrapHandler(handlers.read, true);
if (handlers.write) ops.write = wrapHandler(handlers.write, true);
if (handlers.release) ops.release = wrapHandler(handlers.release);
if (handlers.releasedir) ops.releasedir = wrapHandler(handlers.releasedir);
if (handlers.create) ops.create = wrapHandler(handlers.create);
if (handlers.utimens) ops.utimens = wrapHandler(handlers.utimens);
if (handlers.unlink) ops.unlink = wrapHandler(handlers.unlink);
if (handlers.rename) ops.rename = wrapHandler(handlers.rename);
if (handlers.link) ops.link = wrapHandler(handlers.link);
if (handlers.symlink) ops.symlink = wrapHandler(handlers.symlink);
if (handlers.mkdir) ops.mkdir = wrapHandler(handlers.mkdir);
if (handlers.rmdir) ops.rmdir = wrapHandler(handlers.rmdir);
if (handlers.destroy) ops.destroy = wrapHandler(handlers.destroy);
ops.options = options.filter(i => i !== 'display_folder' && i !== 'force');
if (options.includes('display_folder')) ops.displayFolder = true;
if (options.includes('force')) ops.force = true;
fuse.mount(mount_path, ops, err => {
if (err) reject(err);
else resolve(mount_path);
});
});
},
unmount(mount_path) {
return new Promise((resolve, reject) => {
fuse.unmount(mount_path, err => {
if (err) reject(err);
else resolve();
});
});
},
// context() {
// return fuse.context();
// }
};
for (const key in fuse) {
if (key.startsWith('E')) {
exports.default[key] = fuse[key];
}
}
import iCloudService from '../..';
import yargs from 'yargs';
import path from 'path';
import fuse from './fuse';
const mount_path = yargs.argv.mount || process.platform !== 'win32' ? path.resolve(__dirname, '..', 'mount') : 'M:\\';
function parsePath(path) {
// What?
if (path.substr(0, 1) !== '/') path = '/';
path = path.substr(1);
if (path === '') {
return {
fullpaths: []
};
}
if (path.indexOf('/') <= -1) {
let zone = path;
if (zone === 'iCloud Drive') zone = 'com.apple.CloudDocs';
return {
zone,
paths: [],
fullpaths: [zone]
};
}
let zone = path.substr(0, path.indexOf('/'));
if (zone === 'iCloud Drive') zone = 'com.apple.CloudDocs';
path = path.substr(path.indexOf('/') + 1);
return {
zone,
path,
paths: path.split('/'),
fullpaths: [zone].concat(path)
};
}
(async () => {
const icloud = new iCloudService('apple-id', 'password');
await icloud.authenticate();
const root = await icloud.drive['com.apple.CloudDocs'];
const libraries = await icloud.drive.getAppLibraries();
const cache = new Map();
await fuse.mount(mount_path, {
async readdir(path, cb) {
if (path === '/.info' || path.substr(0, 7) === '/.info/') {
return [];
}
console.log('readdir(%s)', path);
path = parsePath(path);
console.log('Zone/path:', path);
// List zones
if (!path.zone) {
// return cb(0, libraries.concat(['com.apple.CloudDocs']));
return libraries.map(l => l.zone).concat(['com.apple.CloudDocs']);
}
try {
const item = await icloud.drive.getItemByPath(...path.fullpaths);
return await item.dir();
} catch (err) {
throw fuse.ENOENT;
}
},
async getattr(path, cb) {
if (path === '/.info' || path.substr(0, 7) === '/.info/' && path.substr(-5, 5) !== '.info') {
return {
mtime: new Date(),
atime: new Date(),
ctime: new Date(),
nlink: 1,
size: 100,
mode: 16877,
uid: process.getuid ? process.getuid() : 0,
gid: process.getgid ? process.getgid() : 0
};
}
if (path.substr(0, 7) === '/.info/' && path.substr(-5, 5) === '.info') {
const data = JSON.stringify(await icloud.drive.getItemByPath(...path.substr(7, path.length - 7 - 5).split('/')), null, 4) + '\n';
return {
mtime: new Date(),
atime: new Date(),
ctime: new Date(),
nlink: 1,
size: data.length,
mode: 33188,
uid: process.getuid ? process.getuid() : 0,
gid: process.getgid ? process.getgid() : 0
};
}
console.log('getattr(%s)', path);
path = parsePath(path);
console.log('Zone/path:', path);
if (path.zone && path.zone !== 'com.apple.CloudDocs' && !libraries.find(l => l.zone === path.zone)) {
throw fuse.ENOENT;
}
if (!path.zone || !path.path) {
return {
mtime: new Date(),
atime: new Date(),
ctime: new Date(),
nlink: 1,
size: 100,
mode: 16877,
uid: process.getuid ? process.getuid() : 0,
gid: process.getgid ? process.getgid() : 0
};
}
try {
const item = await icloud.drive.getItemByPath(...path.fullpaths);
return {
mtime: item.date_modified,
atime: item.date_accessed,
ctime: new Date(),
nlink: 1,
size: item.type === 'FILE' ? item.size : 100,
mode: item.type === 'FILE' ? 33188 : item instanceof icloud.drive.constructor.Directory ? 16877 : 0,
uid: process.getuid ? process.getuid() : 0,
gid: process.getgid ? process.getgid() : 0
};
} catch (err) {
throw fuse.ENOENT;
}
if (path === '/test') {
return {
mtime: new Date(),
atime: new Date(),
ctime: new Date(),
nlink: 1,
size: 12,
mode: 33188,
uid: process.getuid ? process.getuid() : 0,
gid: process.getgid ? process.getgid() : 0
};
}
throw fuse.ENOENT;
},
open(path, flags, cb) {
console.log('open(%s, %d)', path, flags);
return 42;
},
async read(path, fd, buffer, length, position, cb) {
if (path.substr(0, 7) === '/.info/' && path.substr(-5, 5) === '.info') {
const data = JSON.stringify(await icloud.drive.getItemByPath(...path.substr(7, path.length - 7 - 5).split('/')), null, 4) + '\n';
const selected = data.substr(position, position + length);
buffer.write(selected);
return selected.length;
}
console.log('read(%s, %d, %d, %d)', path, fd, length, position);
const str = 'hello world\n'.slice(position, position + length);
if (!str) return 0;
buffer.write(str);
return str.length;
}
}, [
'force',
'noappledouble',
'volname=iCloud Drive',
'fsname=icloud#' + icloud.apple_id
]);
console.log('Filesystem mounted at ' + mount_path);
process.on('SIGINT', async () => {
try {
await fuse.unmount(mount_path);
console.log('Filesystem at ' + mount_path + ' unmounted');
} catch (err) {
console.log('Filesystem at ' + mount_path + ' not unmounted', err);
process.exit(1);
}
});
})();
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment