/* GIO - GLib Input, Output and Streaming Library * * Copyright (C) 2006-2007 Red Hat, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General * Public License along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. * * Author: Alexander Larsson */ #include #include #include #include #include typedef struct _GVfsUriMapperSmb GVfsUriMapperSmb; typedef struct _GVfsUriMapperSmbClass GVfsUriMapperSmbClass; struct _GVfsUriMapperSmb { GVfsUriMapper parent; }; struct _GVfsUriMapperSmbClass { GVfsUriMapperClass parent_class; }; GType g_vfs_uri_mapper_smb_get_type (void); void g_vfs_uri_mapper_smb_register (GIOModule *module); G_DEFINE_DYNAMIC_TYPE (GVfsUriMapperSmb, g_vfs_uri_mapper_smb, G_VFS_TYPE_URI_MAPPER) static void g_vfs_uri_mapper_smb_init (GVfsUriMapperSmb *vfs) { } static char * normalize_smb_name (const char *name, gssize len) { gboolean valid_utf8; valid_utf8 = g_utf8_validate (name, len, NULL); if (valid_utf8) return g_utf8_casefold (name, len); else return g_ascii_strdown (name, len); } static const char * const * smb_get_handled_schemes (GVfsUriMapper *mapper) { static const char *schemes[] = { "smb", NULL }; return schemes; } static GVfsUriMountInfo * smb_from_uri (GVfsUriMapper *mapper, const char *uri_str) { char *tmp; const char *p; const char *share, *share_end; GDecodedUri *uri; GVfsUriMountInfo *info; uri = g_vfs_decode_uri (uri_str); if (uri == NULL) return NULL; if (uri->host == NULL || strlen (uri->host) == 0) { /* uri form: smb:/// or smb:///$path */ info = g_vfs_uri_mount_info_new ("smb-network"); if (uri->path == NULL || *uri->path == 0) info->path = g_strdup ("/"); else info->path = g_strdup (uri->path); } else { /* host set */ p = uri->path; while (p && *p == '/') p++; if (p == NULL || *p == 0) { /* uri form: smb://$host/ */ info = g_vfs_uri_mount_info_new ("smb-server"); tmp = normalize_smb_name (uri->host, -1); g_vfs_uri_mount_info_set (info, "server", tmp); g_free (tmp); info->path = g_strdup ("/"); } else { share = p; share_end = strchr (share, '/'); if (share_end == NULL) share_end = share + strlen (share); p = share_end; while (*p == '/') p++; if (*p == 0) { /* uri form: smb://$host/$share/ * Here we special case smb-server files by adding "._" to the names in the uri */ if (share[0] == '.' && share[1] == '_') { info = g_vfs_uri_mount_info_new ("smb-server"); tmp = normalize_smb_name (uri->host, -1); g_vfs_uri_mount_info_set (info, "server", tmp); g_free (tmp); tmp = normalize_smb_name (share + 2, share_end - (share + 2)); info->path = g_strconcat ("/", tmp, NULL); g_free (tmp); } else { info = g_vfs_uri_mount_info_new ("smb-share"); tmp = normalize_smb_name (uri->host, -1); g_vfs_uri_mount_info_set (info, "server", tmp); g_free (tmp); tmp = normalize_smb_name (share, share_end - share); g_vfs_uri_mount_info_set (info, "share", tmp); g_free (tmp); info->path = g_strdup ("/"); } } else { info = g_vfs_uri_mount_info_new ("smb-share"); tmp = normalize_smb_name (uri->host, -1); g_vfs_uri_mount_info_set (info, "server", tmp); g_free (tmp); tmp = normalize_smb_name (share, share_end - share); g_vfs_uri_mount_info_set (info, "share", tmp); g_free (tmp); info->path = g_strconcat ("/", p, NULL); } } } if (uri->userinfo) { const char *user = uri->userinfo; p = strchr (uri->userinfo, ';'); if (p) { if (p != user) g_vfs_uri_mount_info_set_with_len (info, "domain", user, p - user); user = p + 1; } if (*user != 0) g_vfs_uri_mount_info_set (info, "user", user); } g_vfs_decoded_uri_free (uri); return info; } static const char * const * smb_get_handled_mount_types (GVfsUriMapper *mapper) { static const char *types[] = { "smb-network", "smb-server", "smb-share", NULL }; return types; } static char * smb_to_uri (GVfsUriMapper *mapper, GVfsUriMountInfo *info, gboolean allow_utf8) { const char *type; const char *server; const char *share; const char *user; const char *domain; char *s; GDecodedUri *uri; uri = g_new0 (GDecodedUri, 1); type = g_vfs_uri_mount_info_get (info, "type"); uri->scheme = g_strdup ("smb"); uri->port = -1; if (strcmp (type, "smb-network") == 0) { uri->path = g_strdup (info->path); } else if (strcmp (type, "smb-server") == 0) { server = g_vfs_uri_mount_info_get (info, "server"); uri->host = g_strdup (server); /* Map the mountables in server to ._share because the actual share mount maps to smb://server/share */ if (info->path && info->path[0] == '/' && info->path[1] != 0) uri->path = g_strconcat ("/._", info->path + 1, NULL); else uri->path = g_strdup ("/"); } else if (strcmp (type, "smb-share") == 0) { server = g_vfs_uri_mount_info_get (info, "server"); uri->host = g_strdup (server); share = g_vfs_uri_mount_info_get (info, "share"); if (info->path[0] == '/') uri->path = g_strconcat ("/", share, info->path, NULL); else uri->path = g_strconcat ("/", share, "/", info->path, NULL); user = g_vfs_uri_mount_info_get (info, "user"); domain = g_vfs_uri_mount_info_get (info, "domain"); if (user) { if (domain) uri->userinfo = g_strconcat (domain, ";", user, NULL); else uri->userinfo = g_strdup (user); } } s = g_vfs_encode_uri (uri, allow_utf8); g_vfs_decoded_uri_free (uri); return s; } static const char * smb_to_uri_scheme (GVfsUriMapper *mapper, GVfsUriMountInfo *info) { const gchar *type = g_vfs_uri_mount_info_get (info, "type"); if (strcmp ("smb-network", type) == 0 || strcmp ("smb-server", type) == 0 || strcmp ("smb-share", type) == 0) return "smb"; else return NULL; } static void g_vfs_uri_mapper_smb_class_finalize (GVfsUriMapperSmbClass *klass) { } static void g_vfs_uri_mapper_smb_class_init (GVfsUriMapperSmbClass *class) { GVfsUriMapperClass *mapper_class; mapper_class = G_VFS_URI_MAPPER_CLASS (class); mapper_class->get_handled_schemes = smb_get_handled_schemes; mapper_class->from_uri = smb_from_uri; mapper_class->get_handled_mount_types = smb_get_handled_mount_types; mapper_class->to_uri = smb_to_uri; mapper_class->to_uri_scheme = smb_to_uri_scheme; } void g_vfs_uri_mapper_smb_register (GIOModule *module) { g_vfs_uri_mapper_smb_register_type (G_TYPE_MODULE (module)); }