/* sitecopy gnome-vfs driver module Copyright (C) 2004, David A Knight the ftp driver module was used as a skeleton for implementation 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include #include #include #include #include #include #include "protocol.h" #include "frontend.h" typedef struct { struct site *site; const gchar *error; } vfs_session; static gboolean vfs_mkdir( const gchar *path, GnomeVFSFilePermissions perms, GnomeVFSResult *result ); static int init(void **session, struct site *site) { vfs_session *sess = g_new0( vfs_session, 1 ); int ret = SITE_OK; GnomeVFSURI *uri; GnomeVFSResult result; *session = sess; sess->site = site; uri = gnome_vfs_uri_new( site->remote_root_user ); if( ! uri ) { ret = SITE_FAILED; sess->error = _( "Invalid URL for upload location" ); } else { fe_connection( fe_connecting, NULL ); if( ! gnome_vfs_uri_exists( uri ) && ! vfs_mkdir( site->remote_root_user, GNOME_VFS_PERM_USER_ALL | GNOME_VFS_PERM_GROUP_READ | GNOME_VFS_PERM_GROUP_EXEC | GNOME_VFS_PERM_OTHER_READ | GNOME_VFS_PERM_OTHER_EXEC, &result ) ) { if( ! site->keep_going ) { ret = SITE_FAILED; sess->error = gnome_vfs_result_to_string( result ); } } gnome_vfs_uri_unref( uri ); } if( ret == SITE_OK ) { fe_connection( fe_connected, NULL ); } return ret; } static void finish(void *session) { vfs_session *sess = session; g_free( sess ); } static gint progress_cb( GnomeVFSXferProgressInfo *info, gpointer data ) { fe_transfer_progress( info->bytes_copied, info->file_size ); return TRUE; } static int file_upload(void *session, const char *local, const char *remote, int ascii) { GnomeVFSURI *src; GnomeVFSURI *dest; GnomeVFSResult result; int ret = SITE_OK; vfs_session *sess = (vfs_session*)session; src = gnome_vfs_uri_new( local ); if( ! src ) { sess->error = _( "Invalid source uri" ); return SITE_FAILED; } dest = gnome_vfs_uri_new( remote ); if( ! dest ) { sess->error = _( "Invalid destination uri" ); gnome_vfs_uri_unref( src ); return SITE_FAILED; } result = gnome_vfs_xfer_uri( src, dest, GNOME_VFS_XFER_DEFAULT, GNOME_VFS_XFER_ERROR_MODE_ABORT, GNOME_VFS_XFER_OVERWRITE_MODE_REPLACE, progress_cb, session ); if( result != GNOME_VFS_OK ) { ret = SITE_FAILED; } gnome_vfs_uri_unref( src ); gnome_vfs_uri_unref( dest ); sess->error = gnome_vfs_result_to_string( result ); return ret; } static int file_get_modtime(void *session, const char *remote, time_t *modtime ) { GnomeVFSURI *src; GnomeVFSFileInfo *info; GnomeVFSFileInfoOptions options; GnomeVFSResult result; int ret = SITE_OK; vfs_session *sess = (vfs_session*)session; src = gnome_vfs_uri_new( remote ); options = GNOME_VFS_FILE_INFO_FOLLOW_LINKS; info = gnome_vfs_file_info_new(); result = gnome_vfs_get_file_info_uri( src, info, options ); if( result == GNOME_VFS_OK ) { *modtime = info->mtime; } else { ret = SITE_FAILED; } gnome_vfs_uri_unref( src ); gnome_vfs_file_info_unref( info ); sess->error = gnome_vfs_result_to_string( result ); return ret; } static int file_upload_cond(void *session, const char *local, const char *remote, int ascii, time_t time) { /* get modtime */ vfs_session *sess = (vfs_session*)session; time_t mtime; int ret; ret = file_get_modtime(session, remote, &mtime); if( ret != SITE_OK ) { ret = SITE_FAILED; } else if( mtime != time ) { ret = SITE_FAILED; sess->error = "Is this an error? Will it occur?"; } else { ret = file_upload(session, local, remote, ascii); } return ret; } static int file_download(void *session, const char *local, const char *remote, int ascii) { /* reverse local/remote and call file_upload */ return file_upload(session, remote, local, ascii); } static int file_read(void *session, const char *remote, block_reader reader, void *userdata) { GnomeVFSURI *src; GnomeVFSHandle *shandle; GnomeVFSOpenMode mode; GnomeVFSResult result; GnomeVFSFileSize fsize; GnomeVFSFileSize rsize; GnomeVFSFileInfo *info; GnomeVFSFileInfoOptions options; gchar buffer[BUFSIZ]; int ret = SITE_OK; vfs_session *sess = (vfs_session*)session; src = gnome_vfs_uri_new( remote ); /* get perms etc */ options = GNOME_VFS_FILE_INFO_FOLLOW_LINKS; info = gnome_vfs_file_info_new(); result = gnome_vfs_get_file_info_uri( src, info, options ); if( result == GNOME_VFS_OK ) { mode = GNOME_VFS_OPEN_READ; result = gnome_vfs_open_uri( &shandle, src, mode ); } fsize = 0; while( result == GNOME_VFS_OK ) { result = gnome_vfs_read( shandle, buffer, BUFSIZ, &rsize ); buffer[ rsize ] = '\0'; if( result == GNOME_VFS_OK ) { fsize += rsize; fe_transfer_progress( fsize, info->size ); (*reader)(userdata, buffer, ret); } } if( result == GNOME_VFS_ERROR_EOF ) { result = GNOME_VFS_OK; } gnome_vfs_close( shandle ); gnome_vfs_file_info_unref( info ); if( result != GNOME_VFS_OK ) { ret = SITE_FAILED; } gnome_vfs_uri_unref( src ); sess->error = gnome_vfs_result_to_string( result ); return ret; } static int file_delete(void *session, const char *filename) { vfs_session *sess = (vfs_session*)session; int ret = SITE_OK; GnomeVFSResult res; res = gnome_vfs_unlink( filename ); if( res != GNOME_VFS_OK ) { ret = SITE_FAILED; sess->error = gnome_vfs_result_to_string( res ); g_print( "DELETE %s FAILED\n", filename ); } return ret; } static int file_move(void *session, const char *from, const char *to) { int ret; /* move the file: copy then remove */ ret = file_upload(session, from, to, 0); if( ret == SITE_OK ) { ret = file_delete(session, from); } return ret; } static int file_chmod(void *session, const char *filename, mode_t mode) { vfs_session *sess = (vfs_session*)session; GnomeVFSFileInfo *info; GnomeVFSSetFileInfoMask mask; GnomeVFSResult result; int ret; ret = SITE_OK; info = gnome_vfs_file_info_new(); result = gnome_vfs_get_file_info( filename, info, GNOME_VFS_FILE_INFO_FOLLOW_LINKS ); mask = GNOME_VFS_SET_FILE_INFO_PERMISSIONS; if( result == GNOME_VFS_OK ) { info->permissions = mode; result = gnome_vfs_set_file_info( filename, info, mask ); } if( result != GNOME_VFS_OK ) { ret = SITE_FAILED; } gnome_vfs_file_info_unref( info ); sess->error = gnome_vfs_result_to_string( result ); /* DAV doesn't support this, we will allow this as a * success state */ if( result == GNOME_VFS_ERROR_NOT_SUPPORTED ) { ret = SITE_OK; } return ret; } /* recusivley makes directories (if needed), starting at current path, * this is a copy of mkdir_recursive from fileops.c in screem, * copied into here so the driver doesn't depend on being run * from screem itself */ static gboolean vfs_mkdir( const gchar *path, GnomeVFSFilePermissions perms, GnomeVFSResult *result ) { GnomeVFSURI *uri; gboolean ret = FALSE; gboolean exists; uri = gnome_vfs_uri_new( path ); if( uri ) { ret = TRUE; exists = gnome_vfs_uri_exists( uri ); if( ( ! exists ) && gnome_vfs_uri_has_parent( uri ) ) { GnomeVFSURI *parent; gchar *parentname; parent = gnome_vfs_uri_get_parent( uri ); parentname = gnome_vfs_uri_to_string( parent, GNOME_VFS_URI_HIDE_NONE ); gnome_vfs_uri_unref( parent ); ret = vfs_mkdir( parentname, perms, result ); g_free( parentname ); } if( ret && ! exists ) { *result = gnome_vfs_make_directory_for_uri( uri, perms ); if( *result == GNOME_VFS_ERROR_FILE_EXISTS ) { /* ensure it is a directory */ GnomeVFSFileInfo *info; GnomeVFSFileInfoOptions options; info = gnome_vfs_file_info_new(); options = GNOME_VFS_FILE_INFO_DEFAULT; if( gnome_vfs_get_file_info_uri( uri, info, options ) == GNOME_VFS_OK && ( info->type ==GNOME_VFS_FILE_TYPE_DIRECTORY) ) { *result = GNOME_VFS_OK; } gnome_vfs_file_info_unref( info ); } ret = ( *result == GNOME_VFS_OK ); } gnome_vfs_uri_unref( uri ); } else { *result = GNOME_VFS_ERROR_GENERIC; } return ret; } static int dir_create(void *session, const char *dirname ) { vfs_session *sess = (vfs_session*)session; int ret; GnomeVFSResult result; ret = SITE_OK; if( ! vfs_mkdir( dirname, 0x1e4, &result ) ) { ret = SITE_FAILED; sess->error = gnome_vfs_result_to_string( result ); g_print( "hmmm\n" ); } return ret; } static int dir_remove(void *session, const char *dirname) { vfs_session *sess = (vfs_session*)session; int ret = SITE_OK; GnomeVFSResult res; res = gnome_vfs_remove_directory( dirname ); if( res != GNOME_VFS_OK ) { ret = SITE_FAILED; sess->error = gnome_vfs_result_to_string( res ); g_print( "DIR REMOVE %s FAILED\n", dirname ); } return ret; } static int fetch_list(void *session, const char *dirname, int need_modtimes, struct proto_file **files) { return SITE_UNSUPPORTED; } static int create_link(void *session, const char *l, const char *target ) { vfs_session *sess = (vfs_session*)session; int ret = SITE_OK; GnomeVFSURI *uri; GnomeVFSResult res; uri = gnome_vfs_uri_new( l ); res = gnome_vfs_create_symbolic_link( uri, target ); if( res != GNOME_VFS_OK ) { ret = SITE_FAILED; sess->error = gnome_vfs_result_to_string( res ); } gnome_vfs_uri_unref( uri ); return ret; } static int delete_link(void *session, const char *l) { vfs_session *sess = (vfs_session*)session; int ret = SITE_OK; GnomeVFSResult res; res = gnome_vfs_unlink( l ); if( res != GNOME_VFS_OK ) { ret = SITE_FAILED; sess->error = gnome_vfs_result_to_string( res ); } return ret; } static int change_link(void *session, const char *l, const char *target ) { int ret; ret = delete_link(session, l); if( ret == SITE_OK ) { ret = create_link(session, l, target); } return ret; } static const char *error(void *session) { return ((vfs_session*)session)->error; } static int get_dummy_port(struct site *site) { return 0; } /* The protocol drivers */ const struct proto_driver vfs_driver = { init, finish, file_move, file_upload, file_upload_cond, file_get_modtime, file_download, file_read, file_delete, file_chmod, dir_create, dir_remove, create_link, /* create link */ change_link, /* change link target */ delete_link, /* delete link */ fetch_list, error, get_dummy_port, get_dummy_port, "vfs" };