From a4d3df2ea53a2d9c5669a03708071a6fcbbeec9c Mon Sep 17 00:00:00 2001 From: Luiz Augusto von Dentz Date: Tue, 3 Nov 2009 10:51:53 -0300 Subject: [PATCH] obexd: Add initial implementation of mimetype driver and filesystem plugin. Mimetype driver handles object access if there is no driver for the given mimetype the default one (NULL) is used, which is file driver for instance. --- obexd/plugins/filesystem.c | 394 +++++++++++++++++++++++++++++++++++++ obexd/src/ftp.c | 202 +------------------ obexd/src/mimetype.c | 88 +++++++++ obexd/src/mimetype.h | 39 ++++ obexd/src/obex.c | 119 ++++++----- obexd/src/obex.h | 13 +- obexd/src/opp.c | 2 +- obexd/src/plugin.c | 1 + 8 files changed, 611 insertions(+), 247 deletions(-) create mode 100644 obexd/plugins/filesystem.c create mode 100644 obexd/src/mimetype.c create mode 100644 obexd/src/mimetype.h diff --git a/obexd/plugins/filesystem.c b/obexd/plugins/filesystem.c new file mode 100644 index 000000000..e275bf2ad --- /dev/null +++ b/obexd/plugins/filesystem.c @@ -0,0 +1,394 @@ +/* + * + * OBEX Server + * + * Copyright (C) 2009 Intel Corporation + * Copyright (C) 2007-2009 Marcel Holtmann + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include "plugin.h" +#include "logging.h" +#include "mimetype.h" +#include "obex.h" + +#define EOL_CHARS "\n" + +#define FL_VERSION "" EOL_CHARS + +#define FL_TYPE "" EOL_CHARS + +#define FL_TYPE_PCSUITE " ]>" EOL_CHARS + +#define FL_BODY_BEGIN "" EOL_CHARS + +#define FL_BODY_END "" EOL_CHARS + +#define FL_PARENT_FOLDER_ELEMENT "" EOL_CHARS + +#define FL_FILE_ELEMENT "" EOL_CHARS + +#define FL_FOLDER_ELEMENT "" EOL_CHARS + +#define FL_FOLDER_ELEMENT_PCSUITE "" EOL_CHARS + +static const guint8 FTP_TARGET[TARGET_SIZE] = { + 0xF9, 0xEC, 0x7B, 0xC4, 0x95, 0x3C, 0x11, 0xD2, + 0x98, 0x4E, 0x52, 0x54, 0x00, 0xDC, 0x9E, 0x09 }; + +static gchar *file_stat_line(gchar *filename, struct stat *fstat, + struct stat *dstat, gboolean root, + gboolean pcsuite) +{ + gchar perm[51], atime[18], ctime[18], mtime[18]; + gchar *escaped, *ret = NULL; + + snprintf(perm, 50, "user-perm=\"%s%s%s\" group-perm=\"%s%s%s\" " + "other-perm=\"%s%s%s\"", + (fstat->st_mode & S_IRUSR ? "R" : ""), + (fstat->st_mode & S_IWUSR ? "W" : ""), + (dstat->st_mode & S_IWUSR ? "D" : ""), + (fstat->st_mode & S_IRGRP ? "R" : ""), + (fstat->st_mode & S_IWGRP ? "W" : ""), + (dstat->st_mode & S_IWGRP ? "D" : ""), + (fstat->st_mode & S_IROTH ? "R" : ""), + (fstat->st_mode & S_IWOTH ? "W" : ""), + (dstat->st_mode & S_IWOTH ? "D" : "")); + + strftime(atime, 17, "%Y%m%dT%H%M%SZ", gmtime(&fstat->st_atime)); + strftime(ctime, 17, "%Y%m%dT%H%M%SZ", gmtime(&fstat->st_ctime)); + strftime(mtime, 17, "%Y%m%dT%H%M%SZ", gmtime(&fstat->st_mtime)); + + escaped = g_markup_escape_text(filename, -1); + + if (S_ISDIR(fstat->st_mode)) { + if (pcsuite && root && g_str_equal(filename, "Data")) + ret = g_strdup_printf(FL_FOLDER_ELEMENT_PCSUITE, + escaped, perm, atime, + mtime, ctime); + else + ret = g_strdup_printf(FL_FOLDER_ELEMENT, escaped, perm, + atime, mtime, ctime); + } else if (S_ISREG(fstat->st_mode)) + ret = g_strdup_printf(FL_FILE_ELEMENT, escaped, fstat->st_size, + perm, atime, mtime, ctime); + + g_free(escaped); + + return ret; +} + +static gpointer filesystem_open(const char *name, int oflag, mode_t mode, + size_t *size) +{ + struct stat stats; + struct statvfs buf; + int fd = open(name, oflag, mode); + + if (fd < 0) + return NULL; + + if (fstat(fd, &stats) < 0) { + error("fstat(fd=%d): %s (%d)", fd, strerror(errno), errno); + goto failed; + } + + if (oflag == O_RDONLY) { + *size = stats.st_size; + return GINT_TO_POINTER(fd); + } + + if (fstatvfs(fd, &buf) < 0) + goto failed; + + if (buf.f_bsize * buf.f_bavail < *size) { + debug("Not enough free space on disk"); + errno = -ENOSPC; + goto failed; + } + + return GINT_TO_POINTER(fd); + +failed: + close(fd); + return NULL; +} + +static int filesystem_close(gpointer object) +{ + return close(GPOINTER_TO_INT(object)); +} + +static ssize_t filesystem_read(gpointer object, void *buf, size_t count) +{ + return read(GPOINTER_TO_INT(object), buf, count); +} + +static ssize_t filesystem_write(gpointer object, const void *buf, size_t count) +{ + return write(GPOINTER_TO_INT(object), buf, count); +} + +static gpointer capability_open(const char *name, int oflag, mode_t mode, + size_t *size) +{ + GError *gerr = NULL; + gchar *buf; + gint exit; + gboolean ret; + + if (oflag != O_RDONLY) + goto fail; + + if (name[0] != '!') { + ret = g_file_get_contents(name, &buf, NULL, &gerr); + if (ret == FALSE) { + error("%s", gerr->message); + goto fail; + } + + goto done; + } + + ret = g_spawn_command_line_sync(name + 1, &buf, NULL, &exit, &gerr); + if (ret == FALSE) { + error("%s", gerr->message); + goto fail; + } + + if (WEXITSTATUS(exit) != EXIT_SUCCESS) { + error("%s failed", name + 1); + g_free(buf); + goto fail; + } + +done: + if (size) + *size = strlen(buf); + + return buf; + +fail: + if (gerr) + g_error_free(gerr); + + errno = EPERM; + return NULL; +} + +static int capability_close(gpointer object) +{ + g_free(object); + return 0; +} + +static ssize_t capability_read(gpointer object, void *buf, size_t count) +{ + strncpy(buf, object, count); + return strlen(buf); +} + +static gpointer folder_open(const char *name, int oflag, mode_t mode, + size_t *size) +{ + DIR *dir = opendir(name); + + if (dir == NULL) + return NULL; + + if (size) + *size = 1; + + return dir; +} + +static int folder_close(gpointer object) +{ + DIR *dir = (DIR *) object; + + return closedir(dir); +} + +static ssize_t folder_read(gpointer object, void *buf, size_t count) +{ + struct obex_session *os; + struct stat fstat, dstat; + struct dirent *ep; + DIR *dp = (DIR *) object; + GString *listing; + gboolean root, pcsuite; + gint err, len; + + os = obex_get_session(object); + if (os->finished) + return 0; + + pcsuite = os->server->services & OBEX_PCSUITE ? TRUE : FALSE; + + listing = g_string_new(FL_VERSION); + listing = g_string_append(listing, pcsuite ? FL_TYPE_PCSUITE : FL_TYPE); + + listing = g_string_append(listing, FL_BODY_BEGIN); + + root = g_str_equal(os->current_folder, os->server->folder); + + if (root && os->server->symlinks) + err = stat(os->current_folder, &dstat); + else { + listing = g_string_append(listing, FL_PARENT_FOLDER_ELEMENT); + err = lstat(os->current_folder, &dstat); + } + + if (err < 0) { + err = -errno; + error("%s: %s(%d)", root ? "stat" : "lstat", + strerror(errno), errno); + goto failed; + } + + while ((ep = readdir(dp))) { + gchar *name; + gchar *fullname; + gchar *line; + + if (ep->d_name[0] == '.') + continue; + + name = g_filename_to_utf8(ep->d_name, -1, NULL, NULL, NULL); + if (name == NULL) { + error("g_filename_to_utf8: invalid filename"); + continue; + } + + fullname = g_build_filename(os->current_folder, ep->d_name, NULL); + + if (root && os->server->symlinks) + err = stat(fullname, &fstat); + else + err = lstat(fullname, &fstat); + + if (err < 0) { + debug("%s: %s(%d)", root ? "stat" : "lstat", + strerror(errno), errno); + g_free(name); + g_free(fullname); + continue; + } + + g_free(fullname); + + line = file_stat_line(name, &fstat, &dstat, root, pcsuite); + if (line == NULL) { + g_free(name); + continue; + } + + g_free(name); + + listing = g_string_append(listing, line); + g_free(line); + } + + listing = g_string_append(listing, FL_BODY_END); + len = listing->len; + memcpy(buf, listing->str, len); + g_string_free(listing, TRUE); + os->finished = TRUE; + + return len; + +failed: + g_string_free(listing, TRUE); + return err; +} + +struct obex_mime_type_driver file = { + .open = filesystem_open, + .close = filesystem_close, + .read = filesystem_read, + .write = filesystem_write, + .remove = remove, +}; + +struct obex_mime_type_driver capability = { + .target = FTP_TARGET, + .mimetype = "x-obex/capability", + .open = capability_open, + .close = capability_close, + .read = capability_read, +}; + +struct obex_mime_type_driver folder = { + .target = FTP_TARGET, + .mimetype = "x-obex/folder-listing", + .open = folder_open, + .close = folder_close, + .read = folder_read, +}; + +static int filesystem_init(void) +{ + int err; + + err = obex_mime_type_driver_register(&folder); + if (err < 0) + return err; + + err = obex_mime_type_driver_register(&capability); + if (err < 0) + return err; + + return obex_mime_type_driver_register(&file); +} + +static void filesystem_exit(void) +{ + obex_mime_type_driver_unregister(&folder); + obex_mime_type_driver_unregister(&capability); + obex_mime_type_driver_unregister(&file); +} + +OBEX_PLUGIN_DEFINE("filesystem", filesystem_init, filesystem_exit) diff --git a/obexd/src/ftp.c b/obexd/src/ftp.c index a53e43f1b..ffbcf73aa 100644 --- a/obexd/src/ftp.c +++ b/obexd/src/ftp.c @@ -48,206 +48,22 @@ #include "logging.h" #include "obex.h" #include "dbus.h" +#include "mimetype.h" #define LST_TYPE "x-obex/folder-listing" #define CAP_TYPE "x-obex/capability" -#define EOL_CHARS "\n" - -#define FL_VERSION "" EOL_CHARS - -#define FL_TYPE "" EOL_CHARS - -#define FL_TYPE_PCSUITE " ]>" EOL_CHARS - -#define FL_BODY_BEGIN "" EOL_CHARS - -#define FL_BODY_END "" EOL_CHARS - -#define FL_PARENT_FOLDER_ELEMENT "" EOL_CHARS - -#define FL_FILE_ELEMENT "" EOL_CHARS - -#define FL_FOLDER_ELEMENT "" EOL_CHARS - -#define FL_FOLDER_ELEMENT_PCSUITE "" EOL_CHARS - -static gchar *file_stat_line(gchar *filename, struct stat *fstat, - struct stat *dstat, gboolean root, - gboolean pcsuite) -{ - gchar perm[51], atime[18], ctime[18], mtime[18]; - gchar *escaped, *ret = NULL; - - snprintf(perm, 50, "user-perm=\"%s%s%s\" group-perm=\"%s%s%s\" " - "other-perm=\"%s%s%s\"", - (fstat->st_mode & S_IRUSR ? "R" : ""), - (fstat->st_mode & S_IWUSR ? "W" : ""), - (dstat->st_mode & S_IWUSR ? "D" : ""), - (fstat->st_mode & S_IRGRP ? "R" : ""), - (fstat->st_mode & S_IWGRP ? "W" : ""), - (dstat->st_mode & S_IWGRP ? "D" : ""), - (fstat->st_mode & S_IROTH ? "R" : ""), - (fstat->st_mode & S_IWOTH ? "W" : ""), - (dstat->st_mode & S_IWOTH ? "D" : "")); - - strftime(atime, 17, "%Y%m%dT%H%M%SZ", gmtime(&fstat->st_atime)); - strftime(ctime, 17, "%Y%m%dT%H%M%SZ", gmtime(&fstat->st_ctime)); - strftime(mtime, 17, "%Y%m%dT%H%M%SZ", gmtime(&fstat->st_mtime)); - - escaped = g_markup_escape_text(filename, -1); - - if (S_ISDIR(fstat->st_mode)) { - if (pcsuite && root && g_str_equal(filename, "Data")) - ret = g_strdup_printf(FL_FOLDER_ELEMENT_PCSUITE, - escaped, perm, atime, - mtime, ctime); - else - ret = g_strdup_printf(FL_FOLDER_ELEMENT, escaped, perm, - atime, mtime, ctime); - } else if (S_ISREG(fstat->st_mode)) - ret = g_strdup_printf(FL_FILE_ELEMENT, escaped, fstat->st_size, - perm, atime, mtime, ctime); - - g_free(escaped); - - return ret; -} - -static gint folder_listing(struct obex_session *os, guint32 *size) +static gint folder_listing(struct obex_session *os, size_t *size) { - struct stat fstat, dstat; - struct dirent *ep; - DIR *dp; - GString *listing; - gboolean root, pcsuite; - gint err; - - pcsuite = os->server->services & OBEX_PCSUITE ? TRUE : FALSE; - - listing = g_string_new(FL_VERSION); - listing = g_string_append(listing, pcsuite ? FL_TYPE_PCSUITE : FL_TYPE); - - listing = g_string_append(listing, FL_BODY_BEGIN); - - root = g_str_equal(os->current_folder, os->server->folder); - - if (root && os->server->symlinks) - err = stat(os->current_folder, &dstat); - else { - listing = g_string_append(listing, FL_PARENT_FOLDER_ELEMENT); - err = lstat(os->current_folder, &dstat); - } - - if (err < 0) { - err = -errno; - error("%s: %s(%d)", root ? "stat" : "lstat", - strerror(errno), errno); - goto failed; - } - - dp = opendir(os->current_folder); - if (dp == NULL) { - err = -errno; - error("opendir: failed to access %s", os->current_folder); - goto failed; - } - - while ((ep = readdir(dp))) { - gchar *name; - gchar *fullname; - gchar *line; - - if (ep->d_name[0] == '.') - continue; - - name = g_filename_to_utf8(ep->d_name, -1, NULL, NULL, NULL); - if (name == NULL) { - error("g_filename_to_utf8: invalid filename"); - continue; - } - - fullname = g_build_filename(os->current_folder, ep->d_name, NULL); - - if (root && os->server->symlinks) - err = stat(fullname, &fstat); - else - err = lstat(fullname, &fstat); - - if (err < 0) { - debug("%s: %s(%d)", root ? "stat" : "lstat", - strerror(errno), errno); - g_free(name); - g_free(fullname); - continue; - } - - g_free(fullname); - - line = file_stat_line(name, &fstat, &dstat, root, pcsuite); - if (line == NULL) { - g_free(name); - continue; - } - - g_free(name); - - listing = g_string_append(listing, line); - g_free(line); - } - - closedir(dp); - - listing = g_string_append(listing, FL_BODY_END); - *size = listing->len + 1; - os->buf = (guint8*) g_string_free(listing, FALSE); - - return 0; - -failed: - g_string_free(listing, TRUE); - return err; + return os_prepare_get(os, os->current_folder, size); } -static gint get_capability(struct obex_session *os, guint32 *size) +static gint get_capability(struct obex_session *os, size_t *size) { - GError *gerr = NULL; - gchar *buf; - gint exit; - gboolean ret; - - if (os->server->capability == NULL) - return -ENOENT; - - if (os->server->capability[0] != '!') - return os_prepare_get(os, os->server->capability, size); - - ret = g_spawn_command_line_sync(os->server->capability + 1, - &buf, NULL, &exit, &gerr); - if (ret == FALSE) { - error("g_spawn_command_line_sync: %s", gerr->message); - g_error_free(gerr); - return -EPERM; - } - - if (WEXITSTATUS(exit) != EXIT_SUCCESS) { - g_free(buf); - return -EPERM; - } - - os->buf = (guint8 *) buf; - *size = strlen(buf); - - return 0; + return os_prepare_get(os, os->server->capability, size); } -static gint get_by_type(struct obex_session *os, gchar *type, guint32 *size) +static gint get_by_type(struct obex_session *os, gchar *type, size_t *size) { if (type == NULL) return -ENOENT; @@ -262,7 +78,7 @@ static gint get_by_type(struct obex_session *os, gchar *type, guint32 *size) } static gint ftp_prepare_get(struct obex_session *os, gchar *file, - guint32 *size) + size_t *size) { gboolean root; @@ -289,7 +105,7 @@ void ftp_get(obex_t *obex, obex_object_t *obj) { obex_headerdata_t hv; struct obex_session *os; - guint32 size; + size_t size; gint err; gchar *path; @@ -355,7 +171,7 @@ static gint ftp_delete(struct obex_session *os) path = g_build_filename(os->current_folder, os->name, NULL); - if (remove(path) < 0) + if (os->driver->remove(path) < 0) ret = -errno; g_free(path); diff --git a/obexd/src/mimetype.c b/obexd/src/mimetype.c new file mode 100644 index 000000000..b8e68c75e --- /dev/null +++ b/obexd/src/mimetype.c @@ -0,0 +1,88 @@ +/* + * + * OBEX Server + * + * Copyright (C) 2007-2009 Marcel Holtmann + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#include +#include + +#include "logging.h" +#include "mimetype.h" +#include "obex.h" + +static GSList *drivers = NULL; + +struct obex_mime_type_driver *obex_mime_type_driver_find(const guint8 *target, const char *mimetype) +{ + GSList *l; + + for (l = drivers; l; l = l->next) { + struct obex_mime_type_driver *driver = l->data; + + if (driver->target && target && + memcmp(target, driver->target, TARGET_SIZE)) + continue; + + if (g_strcmp0(mimetype, driver->mimetype) == 0) + return driver; + } + + return NULL; +} + +int obex_mime_type_driver_register(struct obex_mime_type_driver *driver) +{ + if (!driver) { + error("Invalid driver"); + return -EINVAL; + } + + if (obex_mime_type_driver_find(driver->target, driver->mimetype)) { + error("Permission denied: %s could not be registered", driver->mimetype); + return -EPERM; + } + + debug("driver %p mimetype %s registered", driver, driver->mimetype); + + drivers = g_slist_append(drivers, driver); + + return 0; +} + +void obex_mime_type_driver_unregister(struct obex_mime_type_driver *driver) +{ + if (!g_slist_find(drivers, driver)) { + error("Unable to unregister: No such driver %p", driver); + return; + } + + debug("driver %p mimetype %s unregistered", driver, driver->mimetype); + + drivers = g_slist_remove(drivers, driver); +} diff --git a/obexd/src/mimetype.h b/obexd/src/mimetype.h new file mode 100644 index 000000000..8e2990e66 --- /dev/null +++ b/obexd/src/mimetype.h @@ -0,0 +1,39 @@ +/* + * + * OBEX Server + * + * Copyright (C) 2007-2009 Marcel Holtmann + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#define TARGET_SIZE 16 + +struct obex_mime_type_driver { + const guint8 *target; + const char *mimetype; + gpointer (*open) (const char *name, int oflag, mode_t mode, size_t *size); + int (*close) (gpointer object); + ssize_t (*read) (gpointer object, void *buf, size_t count); + ssize_t (*write) (gpointer object, const void *buf, size_t count); + int (*remove) (const char *name); +}; + +int obex_mime_type_driver_register(struct obex_mime_type_driver *driver); +void obex_mime_type_driver_unregister(struct obex_mime_type_driver *driver); +struct obex_mime_type_driver *obex_mime_type_driver_find(const guint8 *target, + const char *mimetype); diff --git a/obexd/src/obex.c b/obexd/src/obex.c index 9ec9c5b66..212c3699a 100644 --- a/obexd/src/obex.c +++ b/obexd/src/obex.c @@ -47,6 +47,7 @@ #include "logging.h" #include "obex.h" #include "dbus.h" +#include "mimetype.h" /* Default MTU's */ #define DEFAULT_RX_MTU 32767 @@ -93,16 +94,17 @@ struct obex_commands pbap = { static void os_reset_session(struct obex_session *os) { - if (os->fd > 0) { - close(os->fd); - os->fd = -1; + if (os->object) { + os->driver->close(os->object); + os->object = NULL; if (os->aborted && os->cmd == OBEX_CMD_PUT && os->current_folder) { gchar *path; path = g_build_filename(os->current_folder, os->name, NULL); - unlink(path); + os->driver->remove(path); g_free(path); } } + if (os->name) { g_free(os->name); os->name = NULL; @@ -115,6 +117,7 @@ static void os_reset_session(struct obex_session *os) g_free(os->buf); os->buf = NULL; } + os->driver = NULL; os->aborted = FALSE; os->offset = 0; os->size = OBJECT_SIZE_DELETE; @@ -234,6 +237,7 @@ static void cmd_connect(struct obex_session *os, os->server->services & (OBEX_FTP | OBEX_PCSUITE)) { os->target = FTP_TARGET; + os->services = OBEX_FTP | OBEX_PCSUITE; os->cmds = &ftp; break; } @@ -241,6 +245,7 @@ static void cmd_connect(struct obex_session *os, if (memcmp(hd.bs, PBAP_TARGET, TARGET_SIZE) == 0 && os->server->services & OBEX_PBAP) { os->target = PBAP_TARGET; + os->services = OBEX_PBAP; os->cmds = &pbap; pbap_phonebook_context_create(os); break; @@ -379,10 +384,21 @@ static void cmd_get(struct obex_session *os, obex_t *obex, obex_object_t *obj) os->type = g_strndup((const gchar *) hd.bs, hlen); debug("OBEX_HDR_TYPE: %s", os->type); + os->driver = obex_mime_type_driver_find(os->target, os->type); break; } } + if (!os->driver) { + os->driver = obex_mime_type_driver_find(os->target, NULL); + if (!os->driver) { + error("No driver found"); + OBEX_ObjectSetRsp(obj, OBEX_RSP_NOT_IMPLEMENTED, + OBEX_RSP_NOT_IMPLEMENTED); + return; + } + } + os->cmds->get(obex, obj); } @@ -435,38 +451,34 @@ static void cmd_setpath(struct obex_session *os, os->cmds->setpath(obex, obj); } -int os_prepare_get(struct obex_session *os, gchar *file, guint32 *size) +int os_prepare_get(struct obex_session *os, gchar *filename, size_t *size) { - gint fd, err; - struct stat stats; + gint err; + gpointer object; - fd = open(file, O_RDONLY); - if (fd < 0) { - err = -errno; - error("open(%s): %s (%d)", file, strerror(errno), errno); - goto fail; + if (!os->driver) { + error("No driver to handle %s", os->type); + return -ENOENT; } - if (fstat(fd, &stats) < 0) { + object = os->driver->open(filename, O_RDONLY, 0, size); + if (object == NULL) { err = -errno; - error("fstat(fd=%d (%s)): %s (%d)", fd, file, - strerror(errno), errno); + error("open(%s): %s (%d)", filename, strerror(errno), errno); goto fail; } - os->fd = fd; + os->object = object; os->offset = 0; - if (stats.st_size > 0) + if (*size > 0) os->buf = g_malloc0(os->tx_mtu); - *size = stats.st_size; - return 0; fail: - if (fd >= 0) - close(fd); + if (object) + os->driver->close(object); return err; } @@ -477,14 +489,15 @@ static gint obex_write_stream(struct obex_session *os, gint32 len; guint8 *ptr; - debug("obex_write_stream: name=%s type=%s tx_mtu=%d fd=%d", + debug("obex_write_stream: name=%s type=%s tx_mtu=%d file=%p", os->name ? os->name : "", os->type ? os->type : "", - os->tx_mtu, os->fd); + os->tx_mtu, os->object); if (os->aborted) return -EPERM; - if (os->fd < 0) { + + if (os->object == NULL) { if (os->buf == NULL && os->finished == FALSE) return -EIO; @@ -493,7 +506,7 @@ static gint obex_write_stream(struct obex_session *os, goto add_header; } - len = read(os->fd, os->buf, os->tx_mtu); + len = os->driver->read(os->object, os->buf, os->tx_mtu); if (len < 0) { gint err = errno; error("read(): %s (%d)", strerror(err), err); @@ -535,8 +548,9 @@ gint os_prepare_put(struct obex_session *os) path = g_build_filename(os->current_folder, os->name, NULL); - os->fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0600); - if (os->fd < 0) { + os->object = os->driver->open(path, O_WRONLY | O_CREAT | O_TRUNC, 0600, + (size_t *) &os->size); + if (os->object == NULL) { error("open(%s): %s (%d)", path, strerror(errno), errno); g_free(path); return -EPERM; @@ -556,7 +570,7 @@ gint os_prepare_put(struct obex_session *os) while (len < os->offset) { gint w; - w = write(os->fd, os->buf + len, os->offset - len); + w = os->driver->write(os->object, os->buf + len, os->offset - len); if (w < 0) { gint err = errno; error("write(%s): %s (%d)", path, strerror(errno), @@ -598,7 +612,7 @@ static gint obex_read_stream(struct obex_session *os, obex_t *obex, return -EIO; } - if (os->fd < 0 && size > 0) { + if (os->object == NULL && size > 0) { if (os->buf) { error("Got more data but there is still a pending buffer"); return -EIO; @@ -616,7 +630,7 @@ static gint obex_read_stream(struct obex_session *os, obex_t *obex, while (len < size) { gint w; - w = write(os->fd, buffer + len, size - len); + w = os->driver->write(os->object, buffer + len, size - len); if (w < 0) { gint err = errno; if (err == EINTR) @@ -636,11 +650,9 @@ static gint obex_read_stream(struct obex_session *os, obex_t *obex, static gboolean check_put(obex_t *obex, obex_object_t *obj) { struct obex_session *os; - struct statvfs buf; obex_headerdata_t hd; guint hlen; guint8 hi; - long long unsigned int free; int ret; os = OBEX_GetUserData(obex); @@ -691,6 +703,7 @@ static gboolean check_put(obex_t *obex, obex_object_t *obj) os->type = g_strndup((const gchar *) hd.bs, hlen); debug("OBEX_HDR_TYPE: %s", os->type); + os->driver = obex_mime_type_driver_find(os->target, os->type); break; case OBEX_HDR_BODY: @@ -718,6 +731,16 @@ static gboolean check_put(obex_t *obex, obex_object_t *obj) return FALSE; } + if (!os->driver) { + os->driver = obex_mime_type_driver_find(os->target, NULL); + if (!os->driver) { + error("No driver found"); + OBEX_ObjectSetRsp(obj, OBEX_RSP_NOT_IMPLEMENTED, + OBEX_RSP_NOT_IMPLEMENTED); + return FALSE; + } + } + if (!os->cmds || !os->cmds->chkput) goto done; @@ -744,21 +767,6 @@ static gboolean check_put(obex_t *obex, obex_object_t *obj) goto done; } - if (fstatvfs(os->fd, &buf) < 0) { - int err = errno; - error("fstatvfs(): %s(%d)", strerror(err), err); - OBEX_ObjectSetRsp(obj, OBEX_RSP_FORBIDDEN, OBEX_RSP_FORBIDDEN); - return FALSE; - } - - free = (unsigned long long) buf.f_bsize * buf.f_bavail; - debug("Free space in disk: %llu", free); - if ((guint64) os->size > free) { - debug("Free disk space not available"); - OBEX_ObjectSetRsp(obj, OBEX_RSP_FORBIDDEN, OBEX_RSP_FORBIDDEN); - return FALSE; - } - done: os->checked = TRUE; @@ -926,7 +934,7 @@ static void obex_handle_destroy(gpointer user_data) if (os->target == NULL) { /* Got an error during a transfer. */ - if (os->fd >= 0) + if (os->object) emit_transfer_completed(os->cid, os->offset == os->size); unregister_transfer(os->cid); @@ -1001,7 +1009,6 @@ gint obex_session_start(GIOChannel *io, struct server *server) os->server = server; os->rx_mtu = server->rx_mtu ? server->rx_mtu : DEFAULT_RX_MTU; os->tx_mtu = server->tx_mtu ? server->tx_mtu : DEFAULT_TX_MTU; - os->fd = -1; os->size = OBJECT_SIZE_DELETE; obex = OBEX_Init(OBEX_TRANS_FD, obex_event, 0); @@ -1047,3 +1054,17 @@ gint obex_tty_session_stop(void) return 0; } + +struct obex_session *obex_get_session(gpointer object) +{ + GSList *l; + + for (l = sessions; l; l = l->next) { + struct obex_session *os = l->data; + + if (os->object == object) + return os; + } + + return NULL; +} diff --git a/obexd/src/obex.h b/obexd/src/obex.h index 94a273eab..13ecf81dd 100644 --- a/obexd/src/obex.h +++ b/obexd/src/obex.h @@ -31,14 +31,16 @@ #include "phonebook.h" +#define OBJECT_SIZE_UNKNOWN -1 +#define OBJECT_SIZE_DELETE -2 + #define OBEX_OPP (1 << 0) #define OBEX_FTP (1 << 2) #define OBEX_BIP (1 << 3) #define OBEX_PBAP (1 << 4) #define OBEX_PCSUITE (1 << 5) -#define OBJECT_SIZE_UNKNOWN -1 -#define OBJECT_SIZE_DELETE -2 +struct obex_mime_type_driver; struct obex_commands { void (*get) (obex_t *obex, obex_object_t *obj); @@ -67,6 +69,7 @@ struct server { struct obex_session { GIOChannel *io; guint32 cid; + guint16 services; guint16 tx_mtu; guint16 rx_mtu; uint8_t cmd; @@ -77,7 +80,7 @@ struct obex_session { guint8 *buf; gint32 offset; gint32 size; - gint fd; + gpointer object; gboolean aborted; const guint8 *target; struct obex_commands *cmds; @@ -85,10 +88,12 @@ struct obex_session { gboolean checked; obex_t *obex; struct phonebook_context *pbctx; + struct obex_mime_type_driver *driver; gboolean finished; }; gint obex_session_start(GIOChannel *io, struct server *server); +struct obex_session *obex_get_session(gpointer object); gint obex_tty_session_stop(void); void opp_get(obex_t *obex, obex_object_t *obj); @@ -106,7 +111,7 @@ gboolean pbap_phonebook_context_create(struct obex_session *session); void pbap_phonebook_context_destroy(struct obex_session *session); struct obex_session *pbap_get_session(struct phonebook_context *context); -gint os_prepare_get(struct obex_session *os, gchar *file, guint32 *size); +gint os_prepare_get(struct obex_session *os, gchar *file, size_t *size); gint os_prepare_put(struct obex_session *os); void server_free(struct server *server); diff --git a/obexd/src/opp.c b/obexd/src/opp.c index 9a50d6823..a8dce1361 100644 --- a/obexd/src/opp.c +++ b/obexd/src/opp.c @@ -107,7 +107,7 @@ void opp_get(obex_t *obex, obex_object_t *obj) { struct obex_session *os; obex_headerdata_t hv; - guint32 size; + size_t size; os = OBEX_GetUserData(obex); if (os == NULL) diff --git a/obexd/src/plugin.c b/obexd/src/plugin.c index 628008589..b4c4a11cc 100644 --- a/obexd/src/plugin.c +++ b/obexd/src/plugin.c @@ -74,6 +74,7 @@ static gboolean add_plugin(void *handle, struct obex_plugin_desc *desc) } plugins = g_slist_append(plugins, plugin); + debug("Plugin %s loaded", desc->name); return TRUE; } -- 2.47.3