Audacious $Id:Doxyfile42802007-03-2104:39:00Znenolod$
|
00001 /* Audacious 00002 * Copyright (c) 2006-2007 William Pitcock 00003 * 00004 * This program is free software; you can redistribute it and/or modify 00005 * it under the terms of the GNU General Public License as published by 00006 * the Free Software Foundation; under version 3 of the License. 00007 * 00008 * This program is distributed in the hope that it will be useful, 00009 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00010 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00011 * GNU General Public License for more details. 00012 * 00013 * You should have received a copy of the GNU General Public License 00014 * along with this program. If not, see <http://www.gnu.org/licenses>. 00015 * 00016 * The Audacious team does not consider modular code linking to 00017 * Audacious or using our public API to be a derived work. 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 /* Audacious core provides us with a function that looks up a VFS transport for 00033 * a given URI scheme. Since this function will load plugins as needed, it can 00034 * only be called from the main thread. When VFS is used from parallel threads, 00035 * vfs_prepare must be called from the main thread to look up any needed 00036 * transports beforehand. */ 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 /* vfs_prepare can only be called from the main thread. vfs_fopen can only 00078 * be called from the main thread unless vfs_prepare has been called. */ 00079 if (prepare || ! node->prepared) 00080 g_return_val_if_fail (g_thread_self () == lookup_thread, NULL); 00081 00082 /* do the actual lookup if needed, but only in the main thread */ 00083 if (! node->transport && g_thread_self () == lookup_thread) 00084 { 00085 node->transport = lookup_func (scheme); 00086 /* This is normal for custom URI schemes. 00087 if (! node->transport) 00088 fprintf (stderr, "No transport plugin found for URI scheme \"%s\".\n", scheme); */ 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; /* only local files are handled */ 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 }