2020-06-05 11:39:51 +02:00
'use strict' ;
exports = module . exports = {
upload : upload ,
download : download ,
copy : copy ,
listDir : listDir ,
remove : remove ,
removeDir : removeDir ,
testConfig : testConfig ,
removePrivateFields : removePrivateFields ,
injectPrivateFields : injectPrivateFields
} ;
var assert = require ( 'assert' ) ,
BoxError = require ( '../boxerror.js' ) ,
debug = require ( 'debug' ) ( 'box:storage/sshfs' ) ,
filesystem = require ( './filesystem.js' ) ,
mkdirp = require ( 'mkdirp' ) ,
path = require ( 'path' ) ,
safe = require ( 'safetydance' ) ,
shell = require ( '../shell.js' ) ;
// we mostly reuse the filesystem.js implementation but the config params are different
function translateConfig ( apiConfig ) {
assert . strictEqual ( typeof apiConfig , 'object' ) ;
// skip chown
apiConfig . _doNotChown = true ;
// do not preserver file attributes
apiConfig . _doNotPreserveAttributes = true ;
// resolve the actual path
apiConfig . backupFolder = path . join ( apiConfig . mountPoint , apiConfig . prefix ) ;
return apiConfig ;
}
// storage api
function upload ( apiConfig , backupFilePath , sourceStream , callback ) {
assert . strictEqual ( typeof apiConfig , 'object' ) ;
assert . strictEqual ( typeof backupFilePath , 'string' ) ;
assert . strictEqual ( typeof sourceStream , 'object' ) ;
assert . strictEqual ( typeof callback , 'function' ) ;
filesystem . upload ( translateConfig ( apiConfig ) , backupFilePath , sourceStream , callback ) ;
}
function download ( apiConfig , sourceFilePath , callback ) {
assert . strictEqual ( typeof apiConfig , 'object' ) ;
assert . strictEqual ( typeof sourceFilePath , 'string' ) ;
assert . strictEqual ( typeof callback , 'function' ) ;
filesystem . download ( translateConfig ( apiConfig ) , sourceFilePath , callback ) ;
}
function listDir ( apiConfig , dir , batchSize , iteratorCallback , callback ) {
assert . strictEqual ( typeof apiConfig , 'object' ) ;
assert . strictEqual ( typeof dir , 'string' ) ;
assert . strictEqual ( typeof batchSize , 'number' ) ;
assert . strictEqual ( typeof iteratorCallback , 'function' ) ;
assert . strictEqual ( typeof callback , 'function' ) ;
filesystem . listDir ( translateConfig ( apiConfig ) , dir , batchSize , iteratorCallback , callback ) ;
}
function copy ( apiConfig , oldFilePath , newFilePath ) {
assert . strictEqual ( typeof apiConfig , 'object' ) ;
assert . strictEqual ( typeof oldFilePath , 'string' ) ;
assert . strictEqual ( typeof newFilePath , 'string' ) ;
return filesystem . copy ( translateConfig ( apiConfig ) , oldFilePath , newFilePath ) ;
}
function remove ( apiConfig , filename , callback ) {
assert . strictEqual ( typeof apiConfig , 'object' ) ;
assert . strictEqual ( typeof filename , 'string' ) ;
assert . strictEqual ( typeof callback , 'function' ) ;
filename . remove ( translateConfig ( apiConfig ) , filename , callback ) ;
}
function removeDir ( apiConfig , pathPrefix ) {
assert . strictEqual ( typeof apiConfig , 'object' ) ;
assert . strictEqual ( typeof pathPrefix , 'string' ) ;
return filesystem . removeDir ( translateConfig ( apiConfig ) , pathPrefix ) ;
}
function testConfig ( apiConfig , callback ) {
assert . strictEqual ( typeof apiConfig , 'object' ) ;
assert . strictEqual ( typeof callback , 'function' ) ;
if ( ! apiConfig . mountPoint || typeof apiConfig . mountPoint !== 'string' ) return callback ( new BoxError ( BoxError . BAD _FIELD , 'mountPoint must be non-empty string' , { field : 'mountPoint' } ) ) ;
if ( 'noHardlinks' in apiConfig && typeof apiConfig . noHardlinks !== 'boolean' ) return callback ( new BoxError ( BoxError . BAD _FIELD , 'noHardlinks must be boolean' , { field : 'noHardLinks' } ) ) ;
if ( typeof apiConfig . prefix !== 'string' ) return callback ( new BoxError ( BoxError . BAD _FIELD , 'prefix must be a string' , { field : 'prefix' } ) ) ;
// TODO check fstab entry
// TODO check mountpoint
2020-06-05 12:43:09 +02:00
const backupPath = path . join ( apiConfig . mountPoint , apiConfig . prefix ) ;
const stat = safe . fs . statSync ( backupPath ) ;
if ( ! stat ) return callback ( new BoxError ( BoxError . BAD _FIELD , 'Directory does not exist or cannot be accessed: ' + safe . error . message ) , { field : 'prefix' } ) ;
if ( ! stat . isDirectory ( ) ) return callback ( new BoxError ( BoxError . BAD _FIELD , 'Backup location is not a directory' , { field : 'prefix' } ) ) ;
if ( ! safe . fs . mkdirSync ( path . join ( backupPath , 'snapshot' ) ) && safe . error . code !== 'EEXIST' ) {
if ( safe . error && safe . error . code === 'EACCES' ) return callback ( new BoxError ( BoxError . BAD _FIELD , ` Access denied. Run "chown yellowtent:yellowtent ${ backupPath } " on the server ` , { field : 'prefix' } ) ) ;
return callback ( new BoxError ( BoxError . BAD _FIELD , safe . error . message , { field : 'prefix' } ) ) ;
}
if ( ! safe . fs . writeFileSync ( path . join ( backupPath , 'cloudron-testfile' ) , 'testcontent' ) ) {
return callback ( new BoxError ( BoxError . BAD _FIELD , ` Unable to create test file as 'yellowtent' user in ${ backupPath } : ${ safe . error . message } . Check dir/mount permissions ` , { field : 'prefix' } ) ) ;
}
if ( ! safe . fs . unlinkSync ( path . join ( backupPath , 'cloudron-testfile' ) ) ) {
return callback ( new BoxError ( BoxError . BAD _FIELD , ` Unable to remove test file as 'yellowtent' user in ${ backupPath } : ${ safe . error . message } . Check dir/mount permissions ` , { field : 'prefix' } ) ) ;
}
2020-06-05 11:39:51 +02:00
callback ( null ) ;
}
function removePrivateFields ( apiConfig ) {
return apiConfig ;
}
function injectPrivateFields ( /* newConfig, currentConfig */ ) {
}