Skip to content

Commit

Permalink
added sftp backend support
Browse files Browse the repository at this point in the history
  • Loading branch information
mikedeboer committed May 20, 2011
1 parent 417141e commit 64f11b9
Show file tree
Hide file tree
Showing 10 changed files with 551 additions and 16 deletions.
27 changes: 17 additions & 10 deletions lib/DAV/server.js
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -49,19 +49,26 @@ function Server(options) {
this.debugExceptions = exports.debugMode; this.debugExceptions = exports.debugMode;
if (options && typeof options.standalone == "undefined") if (options && typeof options.standalone == "undefined")
options.standalone = true; options.standalone = true;
this.options = options;


if (options && typeof options.tree == "object" && options.tree.hasFeature(jsDAV.__TREE__)) { if (options && typeof options.tree == "object" && options.tree.hasFeature(jsDAV.__TREE__)) {
this.tree = options.tree; this.tree = options.tree;
} }
else if (options && typeof options.node == "object" && options.node.hasFeature(jsDAV.__INODE__)) { else if (options && typeof options.node == "object" && options.node.hasFeature(jsDAV.__INODE__)) {
this.tree = new jsDAV_ObjectTree(options.node); this.tree = new jsDAV_ObjectTree(options.node, options);
} }
else if (options && typeof options.node == "string" && options.node.indexOf("/") > -1) { else if (options && typeof options.node == "string" && options.node.indexOf("/") > -1) {
this.tree = new jsDAV_Tree_Filesystem(options.node); this.tree = new jsDAV_Tree_Filesystem(options.node, options);
}
else if (options && typeof options.type == "string") {
if (options.type == "sftp") {
var jsDAV_Tree_Sftp = require("./tree/sftp").jsDAV_Tree_Sftp;
this.tree = new jsDAV_Tree_Sftp(options);
}
} }
else if (!options) { else if (!options) {
var root = new jsDAV_SimpleDirectory("root"); var root = new jsDAV_SimpleDirectory("root");
this.tree = new jsDAV_ObjectTree(root); this.tree = new jsDAV_ObjectTree(root, options);
} }
else { else {
throw new Exc.jsDAV_Exception("Invalid argument passed to constructor. " throw new Exc.jsDAV_Exception("Invalid argument passed to constructor. "
Expand Down Expand Up @@ -225,11 +232,11 @@ exports.createServer = function(options, port, host) {
return server; return server;
}; };


exports.mount = function(path, mountpoint, server, standalone) { exports.mount = function(options) {
return new Server({ var s = new Server(options);
node : path, s.unmount = function() {
mount : mountpoint, if (this.tree.unmount)
server : server, this.tree.unmount();
standalone: standalone };
}); return s;
}; };
129 changes: 129 additions & 0 deletions lib/DAV/sftp/directory.js
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1,129 @@
/*
* @package jsDAV
* @subpackage DAV
* @copyright Copyright (C) 2010 Mike de Boer. All rights reserved.
* @author Mike de Boer <mike AT ajax DOT org>
* @license http://github.com/mikedeboer/jsDAV/blob/master/LICENSE MIT License
*/

var jsDAV = require("./../../jsdav"),
jsDAV_SFTP_Node = require("./node").jsDAV_SFTP_Node,
jsDAV_SFTP_File = require("./file").jsDAV_SFTP_File,
jsDAV_Directory = require("./../directory").jsDAV_Directory,
jsDAV_iCollection = require("./../iCollection").jsDAV_iCollection,
jsDAV_iQuota = require("./../iQuota").jsDAV_iQuota,

Fs = require("fs"),
Async = require("./../../../support/async.js"),
Exc = require("./../exceptions");

function jsDAV_SFTP_Directory(path, sftp) {
this.path = (path || "").replace(/[\/]+$/, "");
this.sftp = sftp;
}

exports.jsDAV_SFTP_Directory = jsDAV_SFTP_Directory;

(function() {
this.implement(jsDAV_Directory, jsDAV_iCollection, jsDAV_iQuota);

/**
* Creates a new file in the directory
*
* data is a readable stream resource
*
* @param string name Name of the file
* @param resource data Initial payload
* @return void
*/
this.createFile = function(name, data, enc, cbfscreatefile) {
var newPath = (this.path + "/" + name).replace(/[\/]+$/, "");
if (data.length === 0) { //sftp lib does not support writing empty files...
data = new Buffer("empty file");
enc = "binary";
}
this.sftp.writeFile(newPath, data, enc || "utf8", cbfscreatefile);
};

/**
* Creates a new subdirectory
*
* @param string name
* @return void
*/
this.createDirectory = function(name, cbfscreatedir) {
var newPath = this.path + "/" + name.replace(/[\/]+$/, "");
this.sftp.mkdir(newPath, 0755, cbfscreatedir);
};

/**
* Returns a specific child node, referenced by its name
*
* @param string name
* @throws Sabre_DAV_Exception_FileNotFound
* @return Sabre_DAV_INode
*/
this.getChild = function(name, cbfsgetchild) {
var path = (this.path + "/" + name).replace(/[\/]+$/, ""),
_self = this;

this.sftp.stat(path, function(err, stat) {
if (err || typeof stat == "undefined") {
return cbfsgetchild(new Exc.jsDAV_Exception_FileNotFound("File with name "
+ path + " could not be located"));
}
cbfsgetchild(null, stat.isDirectory()
? new jsDAV_SFTP_Directory(path, _self.sftp)
: new jsDAV_SFTP_File(path, _self.sftp))
});
};

/**
* Returns an array with all the child nodes
*
* @return Sabre_DAV_INode[]
*/
this.getChildren = function(cbfsgetchildren) {
var nodes = [],
_self = this;
this.sftp.readdir(this.path, function(err, listing) {
if (err)
return cbfsgetchildren(null, nodes);
Async.list(listing)
.each(function(node, cbnext) {
var path = (_self.path + "/" + node).replace(/[\/]+$/, "");
_self.sftp.stat(path, function(err, stat) {
if (err)
return cbnext();
nodes.push(stat.isDirectory()
? new jsDAV_SFTP_Directory(path, _self.sftp)
: new jsDAV_SFTP_File(path, _self.sftp)
);
cbnext();
});
})
.end(function() {
cbfsgetchildren(null, nodes);
});
});
};

/**
* Deletes all files in this directory, and then itself
*
* @return void
*/
this["delete"] = function(cbfsdel) {
this.sftp.rmdir(this.path, cbfsdel);
};

/**
* Returns available diskspace information
*
* @return array
*/
this.getQuotaInfo = function(cbfsquota) {
// @todo: impl. sftp.statvfs();
return cbfsquota(null, [0, 0]);
};
}).call(jsDAV_SFTP_Directory.prototype = new jsDAV_SFTP_Node());
107 changes: 107 additions & 0 deletions lib/DAV/sftp/file.js
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1,107 @@
/*
* @package jsDAV
* @subpackage DAV
* @copyright Copyright (C) 2010 Mike de Boer. All rights reserved.
* @author Mike de Boer <mike AT ajax DOT org>
* @license http://github.com/mikedeboer/jsDAV/blob/master/LICENSE MIT License
*/

var jsDAV = require("./../../jsdav"),
jsDAV_SFTP_Node = require("./node").jsDAV_SFTP_Node,
jsDAV_Directory = require("./../directory").jsDAV_Directory,
jsDAV_iFile = require("./../iFile").jsDAV_iFile,

Fs = require("fs"),
Exc = require("./../exceptions"),
Util = require("./../util");

function jsDAV_SFTP_File(path, sftp) {
this.path = (path || "").replace(/[\/]+$/, "");
this.sftp = sftp;
}

exports.jsDAV_SFTP_File = jsDAV_SFTP_File;

(function() {
this.implement(jsDAV_iFile);

/**
* Updates the data
*
* @param {mixed} data
* @return void
*/
this.put = function(data, type, cbfsput) {
this.sftp.writeFile(this.path, data, type || "utf8", cbfsput);
};

/**
* Returns the data
*
* @return Buffer
*/
this.get = function(cbfsfileget) {
if (this.$buffer)
return cbfsfileget(null, this.$buffer);
var _self = this;
this.sftp.readFile(this.path, null, function(err, buff) {
if (err)
return cbfsfileget(err);
// Zero length buffers act funny, use a string
if (buff.length === 0)
buff = "";
//_self.$buffer = buff;
cbfsfileget(null, buff);
});
};

/**
* Delete the current file
*
* @return void
*/
this["delete"] = function(cbfsfiledel) {
this.sftp.unlink(this.path, cbfsfiledel);
};

/**
* Returns the size of the node, in bytes
*
* @return int
*/
this.getSize = function(cbfsgetsize) {
if (this.$stat)
return cbfsgetsize(null, this.$stat.size);
var _self = this;
this.sftp.stat(this.path, function(err, stat) {
if (err || !stat) {
return cbfsgetsize(new Exc.jsDAV_Exception_FileNotFound("File at location "
+ _self.path + " not found"));
}
//_self.$stat = stat;
cbfsgetsize(null, stat.size);
});
};

/**
* Returns the ETag for a file
* An ETag is a unique identifier representing the current version of the file.
* If the file changes, the ETag MUST change.
* Return null if the ETag can not effectively be determined
*
* @return mixed
*/
this.getETag = function(cbfsgetetag) {
cbfsgetetag(null, null);
};

/**
* Returns the mime-type for a file
* If null is returned, we'll assume application/octet-stream
*
* @return mixed
*/
this.getContentType = function(cbfsmime) {
return cbfsmime(null, Util.mime.type(this.path));
};
}).call(jsDAV_SFTP_File.prototype = new jsDAV_SFTP_Node());
81 changes: 81 additions & 0 deletions lib/DAV/sftp/node.js
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1,81 @@
/*
* @package jsDAV
* @subpackage DAV
* @copyright Copyright (C) 2010 Mike de Boer. All rights reserved.
* @author Mike de Boer <mike AT ajax DOT org>
* @license http://github.com/mikedeboer/jsDAV/blob/master/LICENSE MIT License
*/

var jsDAV = require("./../../jsdav"),
jsDAV_iNode = require("./../iNode").jsDAV_iNode,

Fs = require("fs"),
Path = require("path"),
Util = require("./../util"),
Exc = require("./../exceptions");

function jsDAV_SFTP_Node(path, sftp) {
this.path = (path || "").replace(/[\/]+$/, "");
this.sftp = sftp;
}

exports.jsDAV_SFTP_Node = jsDAV_SFTP_Node;

(function() {
/**
* Returns the name of the node
*
* @return {string}
*/
this.getName = function() {
return Util.splitPath(this.path)[1];
};

/**
* Renames the node
*
* @param {string} name The new name
* @return void
*/
this.setName = function(name, cbfssetname) {
var parentPath = Util.splitPath(this.path)[0],
newName = Util.splitPath(name)[1];

var newPath = parentPath + "/" + newName;
var _self = this;
this.sftp.rename(this.path, newPath, function(err) {
if (err)
return cbfssetname(err);
_self.path = newPath;
cbfssetname();
});
};

/**
* Returns the last modification time, as a unix timestamp
*
* @return {Number}
*/
this.getLastModified = function(cbfsgetlm) {
if (this.$stat)
return cbfsgetlm(null, this.$stat.mtime);
var _self = this;
this.sftp.stat(this.path, function(err, stat) {
if (err || typeof stat == "undefined")
return cbfsgetlm(err);
//_self.$stat = stat;
cbfsgetlm(null, stat.mtime);
});
};

/**
* Returns whether a node exists or not
*
* @return {Boolean}
*/
this.exists = function(cbfsexist) {
this.sftp.stat(this.path, function(err, stat) {
cbfsexist(Boolean(!err && stat))
});
};
}).call(jsDAV_SFTP_Node.prototype = new jsDAV_iNode());
Loading

0 comments on commit 64f11b9

Please sign in to comment.