00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include <inttypes.h>
00021
00022 #include "vfs.h"
00023 #include "audstrings.h"
00024 #include <stdio.h>
00025 #include <unistd.h>
00026 #include <sys/stat.h>
00027 #include <sys/types.h>
00028 #include <string.h>
00029
00030 #include <mowgli.h>
00031
00032
00033
00034
00035
00036
00037
00038 typedef struct {
00039 VFSConstructor * transport;
00040 gboolean prepared;
00041 } LookupNode;
00042
00043 static GStaticMutex mutex = G_STATIC_MUTEX_INIT;
00044 static GThread * lookup_thread = NULL;
00045 static VFSConstructor * (* lookup_func) (const gchar * scheme) = NULL;
00046 static mowgli_patricia_t * lookup_table = NULL;
00047
00048 void vfs_set_lookup_func (VFSConstructor * (* func) (const gchar * scheme))
00049 {
00050 g_static_mutex_lock (& mutex);
00051
00052 lookup_thread = g_thread_self ();
00053 lookup_func = func;
00054
00055 if (! lookup_table)
00056 lookup_table = mowgli_patricia_create (NULL);
00057
00058 g_static_mutex_unlock (& mutex);
00059 }
00060
00061 static VFSConstructor * do_lookup (const gchar * scheme, gboolean prepare)
00062 {
00063 g_return_val_if_fail (lookup_thread && lookup_func && lookup_table, NULL);
00064
00065 LookupNode * node = mowgli_patricia_retrieve (lookup_table, scheme);
00066 if (! node)
00067 {
00068 node = g_slice_new (LookupNode);
00069 node->transport = NULL;
00070 node->prepared = FALSE;
00071 mowgli_patricia_add (lookup_table, scheme, node);
00072 }
00073
00074 if (prepare)
00075 node->prepared = TRUE;
00076
00077
00078
00079 if (prepare || ! node->prepared)
00080 g_return_val_if_fail (g_thread_self () == lookup_thread, NULL);
00081
00082
00083 if (! node->transport && g_thread_self () == lookup_thread)
00084 {
00085 node->transport = lookup_func (scheme);
00086
00087
00088
00089 }
00090
00091 return node->transport;
00092 }
00093
00094 void vfs_prepare (const gchar * scheme)
00095 {
00096 g_static_mutex_lock (& mutex);
00097 do_lookup (scheme, TRUE);
00098 g_static_mutex_unlock (& mutex);
00099 }
00100
00101 void vfs_prepare_filename (const gchar * path)
00102 {
00103 const gchar * s = strstr (path, "://");
00104 g_return_if_fail (s);
00105 gchar scheme[s - path + 1];
00106 strncpy (scheme, path, s - path);
00107 scheme[s - path] = 0;
00108
00109 vfs_prepare (scheme);
00110 }
00111
00112 static gboolean verbose = FALSE;
00113
00114 void vfs_set_verbose (gboolean set)
00115 {
00116 verbose = set;
00117 }
00118
00119 static void logger (const gchar * format, ...)
00120 {
00121 static gchar last[256] = "";
00122 static gint repeated = 0;
00123
00124 gchar buf[256];
00125
00126 va_list args;
00127 va_start (args, format);
00128 vsnprintf (buf, sizeof buf, format, args);
00129 va_end (args);
00130
00131 if (! strcmp (buf, last))
00132 repeated ++;
00133 else
00134 {
00135 if (repeated)
00136 {
00137 printf ("VFS: (last message repeated %d times)\n", repeated);
00138 repeated = 0;
00139 }
00140
00141 fputs (buf, stdout);
00142 strcpy (last, buf);
00143 }
00144 }
00145
00154 VFSFile *
00155 vfs_fopen(const gchar * path,
00156 const gchar * mode)
00157 {
00158 g_return_val_if_fail (path && mode, NULL);
00159 g_return_val_if_fail (lookup_func, NULL);
00160
00161 VFSFile *file;
00162 VFSConstructor *vtable = NULL;
00163
00164 const gchar * s = strstr (path, "://");
00165 g_return_val_if_fail (s, NULL);
00166 gchar scheme[s - path + 1];
00167 strncpy (scheme, path, s - path);
00168 scheme[s - path] = 0;
00169
00170 g_static_mutex_lock (& mutex);
00171 vtable = do_lookup (scheme, FALSE);
00172 g_static_mutex_unlock (& mutex);
00173
00174 if (! vtable)
00175 return NULL;
00176
00177 file = vtable->vfs_fopen_impl(path, mode);
00178
00179 if (verbose)
00180 logger ("VFS: <%p> open (mode %s) %s\n", file, mode, path);
00181
00182 if (file == NULL)
00183 return NULL;
00184
00185 file->uri = g_strdup(path);
00186 file->base = vtable;
00187 file->ref = 1;
00188 file->sig = VFS_SIG;
00189
00190 return file;
00191 }
00192
00199 gint
00200 vfs_fclose(VFSFile * file)
00201 {
00202 g_return_val_if_fail (file && file->sig == VFS_SIG, -1);
00203
00204 if (verbose)
00205 printf ("VFS: <%p> close\n", file);
00206
00207 gint ret = 0;
00208
00209 if (--file->ref > 0)
00210 return -1;
00211
00212 if (file->base->vfs_fclose_impl(file) != 0)
00213 ret = -1;
00214
00215 g_free(file->uri);
00216
00217 memset (file, 0, sizeof (VFSFile));
00218 g_free (file);
00219
00220 return ret;
00221 }
00222
00232 gint64 vfs_fread (void * ptr, gint64 size, gint64 nmemb, VFSFile * file)
00233 {
00234 g_return_val_if_fail (file && file->sig == VFS_SIG, 0);
00235
00236 gint64 readed = file->base->vfs_fread_impl (ptr, size, nmemb, file);
00237
00238 if (verbose)
00239 logger ("VFS: <%p> read %"PRId64" elements of size %"PRId64" = "
00240 "%"PRId64"\n", file, nmemb, size, readed);
00241
00242 return readed;
00243 }
00244
00254 gint64 vfs_fwrite (const void * ptr, gint64 size, gint64 nmemb, VFSFile * file)
00255 {
00256 g_return_val_if_fail (file && file->sig == VFS_SIG, 0);
00257
00258 gint64 written = file->base->vfs_fwrite_impl (ptr, size, nmemb, file);
00259
00260 if (verbose)
00261 logger ("VFS: <%p> write %"PRId64" elements of size %"PRId64" = "
00262 "%"PRId64"\n", file, nmemb, size, written);
00263
00264 return written;
00265 }
00266
00273 gint
00274 vfs_getc(VFSFile *file)
00275 {
00276 g_return_val_if_fail (file && file->sig == VFS_SIG, EOF);
00277
00278 if (verbose)
00279 logger ("VFS: <%p> getc\n", file);
00280
00281 return file->base->vfs_getc_impl(file);
00282 }
00283
00291 gint
00292 vfs_ungetc(gint c, VFSFile *file)
00293 {
00294 g_return_val_if_fail (file && file->sig == VFS_SIG, EOF);
00295
00296 if (verbose)
00297 logger ("VFS: <%p> ungetc\n", file);
00298
00299 return file->base->vfs_ungetc_impl(c, file);
00300 }
00301
00315 gint
00316 vfs_fseek(VFSFile * file,
00317 gint64 offset,
00318 gint whence)
00319 {
00320 g_return_val_if_fail (file && file->sig == VFS_SIG, -1);
00321
00322 if (verbose)
00323 logger ("VFS: <%p> seek to %"PRId64" from %s\n", file, offset, whence ==
00324 SEEK_CUR ? "current" : whence == SEEK_SET ? "beginning" : whence ==
00325 SEEK_END ? "end" : "invalid");
00326
00327 return file->base->vfs_fseek_impl(file, offset, whence);
00328 }
00329
00335 void
00336 vfs_rewind(VFSFile * file)
00337 {
00338 g_return_if_fail (file && file->sig == VFS_SIG);
00339
00340 if (verbose)
00341 logger ("VFS: <%p> rewind\n", file);
00342
00343 file->base->vfs_rewind_impl(file);
00344 }
00345
00352 gint64
00353 vfs_ftell(VFSFile * file)
00354 {
00355 g_return_val_if_fail (file && file->sig == VFS_SIG, -1);
00356
00357 gint64 told = file->base->vfs_ftell_impl (file);
00358
00359 if (verbose)
00360 logger ("VFS: <%p> tell = %"PRId64"\n", file, told);
00361
00362 return told;
00363 }
00364
00371 gboolean
00372 vfs_feof(VFSFile * file)
00373 {
00374 g_return_val_if_fail (file && file->sig == VFS_SIG, TRUE);
00375
00376 gboolean eof = file->base->vfs_feof_impl (file);
00377
00378 if (verbose)
00379 logger ("VFS: <%p> eof = %s\n", file, eof ? "yes" : "no");
00380
00381 return eof;
00382 }
00383
00391 gint vfs_ftruncate (VFSFile * file, gint64 length)
00392 {
00393 g_return_val_if_fail (file && file->sig == VFS_SIG, -1);
00394
00395 if (verbose)
00396 logger ("VFS: <%p> truncate to %"PRId64"\n", file, length);
00397
00398 return file->base->vfs_ftruncate_impl(file, length);
00399 }
00400
00407 gint64 vfs_fsize (VFSFile * file)
00408 {
00409 g_return_val_if_fail (file && file->sig == VFS_SIG, -1);
00410
00411 gint64 size = file->base->vfs_fsize_impl (file);
00412
00413 if (verbose)
00414 logger ("VFS: <%p> size = %"PRId64"\n", file, size);
00415
00416 return size;
00417 }
00418
00426 gchar *
00427 vfs_get_metadata(VFSFile * file, const gchar * field)
00428 {
00429 if (file == NULL)
00430 return NULL;
00431
00432 if (file->base->vfs_get_metadata_impl)
00433 return file->base->vfs_get_metadata_impl(file, field);
00434 return NULL;
00435 }
00436
00444 gboolean
00445 vfs_file_test(const gchar * path, GFileTest test)
00446 {
00447 if (strncmp (path, "file://", 7))
00448 return FALSE;
00449
00450 gchar * path2 = uri_to_filename (path);
00451
00452 if (path2 == NULL)
00453 path2 = g_strdup(path);
00454
00455 gboolean ret = g_file_test (path2, test);
00456
00457 g_free(path2);
00458
00459 return ret;
00460 }
00461
00468 gboolean
00469 vfs_is_writeable(const gchar * path)
00470 {
00471 struct stat info;
00472 gchar * realfn = uri_to_filename (path);
00473
00474 if (stat(realfn, &info) == -1)
00475 return FALSE;
00476
00477 g_free(realfn);
00478
00479 return (info.st_mode & S_IWUSR);
00480 }
00481
00491 VFSFile *
00492 vfs_dup(VFSFile *in)
00493 {
00494 g_return_val_if_fail(in != NULL, NULL);
00495
00496 in->ref++;
00497
00498 return in;
00499 }
00500
00507 gboolean
00508 vfs_is_remote(const gchar * path)
00509 {
00510 return strncasecmp (path, "file://", 7) ? TRUE : FALSE;
00511 }
00512
00519 gboolean
00520 vfs_is_streaming(VFSFile *file)
00521 {
00522 off_t size = 0;
00523
00524 if (file == NULL)
00525 return FALSE;
00526
00527 size = file->base->vfs_fsize_impl(file);
00528
00529 if (size == -1)
00530 return TRUE;
00531 else
00532 return FALSE;
00533 }