summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYorhel <git@yorhel.nl>2013-06-16 12:40:59 +0200
committerYorhel <git@yorhel.nl>2013-06-16 12:40:59 +0200
commit997de91a2db054aa53b648d98bc821e0069f91c8 (patch)
tree2837c253cda94a374d288f38cdcb1ef057e166f8
parentb64c9faf52a22139ed9023466dff4807c02d0729 (diff)
share,api: Add + implement basic browse interface
-rw-r--r--doc/api.pod13
-rw-r--r--src/share/conf.c54
-rw-r--r--src/share/fl.c31
-rw-r--r--src/share/fl.h5
4 files changed, 100 insertions, 3 deletions
diff --git a/doc/api.pod b/doc/api.pod
index 47389ce..2b3f233 100644
--- a/doc/api.pod
+++ b/doc/api.pod
@@ -689,9 +689,18 @@ I<TODO:> Cookie(File|Hash)?
C</net/blicky/Globster/Share/$id> and re-usable for remote file lists.
- method List(s path) -> (a(syay))
+ method List(s path) -> (a{s(tay)} list)
-syay = name, size, hash. Directories have a '/' appended to their name.
+Returns a dictionary of files and directories, with the name as key and a
+struct containing the size and hash as value. Directories have an empty
+(zero-length) hash and have a '/' appended to their name.
+
+The I<path> argument must be absolute. An error (I<TODO:> which?) is thrown if
+the given path does not exist in the file list or if it is not a directory.
+
+I<TODO:> Specify what the size of a directory means. Giving it a meaningful
+value would be useful, since most file list browsers allow ordering by dir
+sizes.
=head2 org.freedesktop.DBus.ObjectManager (objman)
diff --git a/src/share/conf.c b/src/share/conf.c
index 6e195fe..3ceb2a0 100644
--- a/src/share/conf.c
+++ b/src/share/conf.c
@@ -260,14 +260,66 @@ static void GetManagedObjects(share_t *s, DBusMessage *msg) {
}
+static void share_List(share_t *s, DBusMessage *msg, const char *_vpath) {
+ /* To prevent a stack overflow */
+ if(*_vpath != '/' || strlen(_vpath) > 10000) {
+ dbo_sendfree(dbus_message_new_error(msg, DBUS_ERROR_INVALID_ARGS, "Invalid path"));
+ return;
+ }
+
+ char vpath[strlen(_vpath)];
+ strcpy(vpath, _vpath);
+ path_normalize(vpath);
+
+ share_fl_t *dir = share_fl_resolve(s->ss->root, vpath);
+ if(!dir) {
+ dbo_sendfree(dbus_message_new_error(msg, DBUS_ERROR_FILE_NOT_FOUND, "No directory found at the given path"));
+ return;
+ }
+
+ DBusMessage *r = dbus_message_new_method_return(msg);
+ DBusMessageIter iter[5];
+ kstring_t buf = {};
+
+ /* TODO: Unhashed files shouldn't be sent. Empty directories should
+ * probably be excluded too, because they aren't included in the public
+ * share. */
+ dbus_message_iter_init_append(r, iter);
+ dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "{s(tay)}", iter+1);
+ size_t i;
+ for(i=0; i<dir->sub.n; i++) {
+ share_fl_t *fl = dir->sub.a[i];
+ buf.l = 0;
+ casestr_orig(share_fl_name(fl), &buf);
+ if(fl->size == UINT64_MAX)
+ kputc('/', &buf);
+ const char *arr = fl->size == UINT64_MAX ? "" : fl->tth;
+
+ dbus_message_iter_open_container(iter+1, DBUS_TYPE_DICT_ENTRY, NULL, iter+2);
+ dbus_message_iter_append_basic(iter+2, DBUS_TYPE_STRING, &buf.s);
+ dbus_message_iter_open_container(iter+2, DBUS_TYPE_STRUCT, NULL, iter+3);
+ dbus_message_iter_append_basic(iter+3, DBUS_TYPE_UINT64, &fl->size);
+ dbus_message_iter_open_container(iter+3, DBUS_TYPE_ARRAY, "y", iter+4);
+ dbus_message_iter_append_fixed_array(iter+4, DBUS_TYPE_BYTE, &arr, fl->size == UINT64_MAX ? 0 : sizeof(fl->tth));
+ dbus_message_iter_close_container(iter+3, iter+4);
+ dbus_message_iter_close_container(iter+2, iter+3);
+ dbus_message_iter_close_container(iter+1, iter+2);
+ }
+ free(buf.s);
+ dbus_message_iter_close_container(iter, iter+1);
+ dbo_sendfree(r);
+}
+
+
static share_t *share_create(uint16_t id) {
static const dbo_share_vtable_t(share_t) svt = dbo_share_funcs();
+ static const dbo_browse_vtable_t(share_t) bvt = dbo_browse_funcs(share_);
static const dbo_objman_vtable_t(share_t) ovt = dbo_objman_funcs();
static const dbo_reg_t reg[] = {
{ &dbo_share_interface, (void**)&svt, offsetof(share_t, props) },
+ { &dbo_browse_interface, (void**)&bvt, 0 },
{ &dbo_objman_interface, (void**)&ovt, 0 }
};
- /* TODO: Add browse interface */
share_t *s = calloc(1, sizeof(share_t));
s->id = id;
diff --git a/src/share/fl.c b/src/share/fl.c
index 903d0b4..439832d 100644
--- a/src/share/fl.c
+++ b/src/share/fl.c
@@ -89,6 +89,37 @@ share_fl_t *share_fl_getdir(share_fl_t *root, char *path, char *pathf, kstring_t
}
+share_fl_t *share_fl_resolve(share_fl_t *root, char *path) {
+ if(*path == '/')
+ path++;
+ if(!*path)
+ return root;
+ assert(root->size == UINT64_MAX);
+ char *end = strchr(path, '/');
+ if(end)
+ *end = 0;
+
+ kstring_t buf = {};
+ casestr_create(path, &buf);
+
+ size_t r = (size_t)-1;
+ vec_search(root->sub, strcmp(share_fl_name(root->sub.a[i]), buf.s), r=i);
+
+ share_fl_t *fl = r == (size_t)-1 ? NULL : root->sub.a[r];
+ share_fl_t *ret = NULL;
+ if(fl && casestr_cmp(share_fl_name(fl), buf.s) == 0) {
+ if(!end)
+ ret = fl;
+ else if(fl->size == UINT64_MAX)
+ ret = share_fl_resolve(fl, end+1);
+ }
+ free(buf.s);
+ if(end)
+ *end = '/';
+ return ret;
+}
+
+
void share_fl_path(share_fl_t *fl, kstring_t *dest) {
vec_t(char *) lst = {};
size_t i;
diff --git a/src/share/fl.h b/src/share/fl.h
index 15697e5..ae4ec57 100644
--- a/src/share/fl.h
+++ b/src/share/fl.h
@@ -97,6 +97,11 @@ share_fl_t *share_fl_getdir(share_fl_t *root, char *path, char *pathf, kstring_t
* dest. */
void share_fl_path(share_fl_t *fl, kstring_t *dest);
+
+/* Resolve a virtual path to a share_fl_t item. Returns NULL if it doesn't
+ * exist. The given path buffer is temporarily modified in-place. */
+share_fl_t *share_fl_resolve(share_fl_t *root, char *path);
+
#endif
/* vim: set noet sw=4 ts=4: */