Audacious  $Id:Doxyfile42802007-03-2104:39:00Znenolod$
vfs.c
Go to the documentation of this file.
00001 /*
00002  *  vfs.c
00003  *  Copyright 2006-2011 William Pitcock, Daniel Barkalow, Ralf Ertzinger,
00004  *                      Yoshiki Yazawa, Matti Hämäläinen, and John Lindgren
00005  *
00006  *  This program is free software; you can redistribute it and/or modify
00007  *  it under the terms of the GNU General Public License as published by
00008  *  the Free Software Foundation; under version 3 of the License.
00009  *
00010  *  This program is distributed in the hope that it will be useful,
00011  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  *  GNU General Public License for more details.
00014  *
00015  *  You should have received a copy of the GNU General Public License
00016  *  along with this program.  If not, see <http://www.gnu.org/licenses>.
00017  *
00018  *  The Audacious team does not consider modular code linking to
00019  *  Audacious or using our public API to be a derived work.
00020  */
00021 
00022 #include <glib.h>
00023 #include <inttypes.h>
00024 
00025 #include "vfs.h"
00026 #include "audstrings.h"
00027 #include <stdio.h>
00028 #include <unistd.h>
00029 #include <sys/stat.h>
00030 #include <sys/types.h>
00031 #include <string.h>
00032 
00033 #include "config.h"
00034 
00035 #define VFS_SIG ('V' | ('F' << 8) | ('S' << 16))
00036 
00042 struct _VFSFile {
00043     char * uri;               
00044     VFSConstructor * base;    
00045     void * handle;            
00046     int sig;                  
00047 };
00048 
00049 /* Audacious core provides us with a function that looks up a VFS transport for
00050  * a given URI scheme.  Since this function will load plugins as needed, it can
00051  * only be called from the main thread.  When VFS is used from parallel threads,
00052  * vfs_prepare must be called from the main thread to look up any needed
00053  * transports beforehand. */
00054 
00055 static VFSConstructor * (* lookup_func) (const char * scheme) = NULL;
00056 
00057 EXPORT void vfs_set_lookup_func (VFSConstructor * (* func) (const char * scheme))
00058 {
00059     lookup_func = func;
00060 }
00061 
00062 static bool_t verbose = FALSE;
00063 
00064 EXPORT void vfs_set_verbose (bool_t set)
00065 {
00066     verbose = set;
00067 }
00068 
00069 static void logger (const char * format, ...)
00070 {
00071     static char last[256] = "";
00072     static int repeated = 0;
00073 
00074     char buf[256];
00075 
00076     va_list args;
00077     va_start (args, format);
00078     vsnprintf (buf, sizeof buf, format, args);
00079     va_end (args);
00080 
00081     if (! strcmp (buf, last))
00082         repeated ++;
00083     else
00084     {
00085         if (repeated)
00086         {
00087             printf ("VFS: (last message repeated %d times)\n", repeated);
00088             repeated = 0;
00089         }
00090 
00091         fputs (buf, stdout);
00092         strcpy (last, buf);
00093     }
00094 }
00095 
00096 EXPORT VFSFile * vfs_new (const char * path, VFSConstructor * vtable, void * handle)
00097 {
00098     VFSFile * file = g_slice_new (VFSFile);
00099     file->uri = str_get (path);
00100     file->base = vtable;
00101     file->handle = handle;
00102     file->sig = VFS_SIG;
00103     return file;
00104 }
00105 
00106 EXPORT const char * vfs_get_filename (VFSFile * file)
00107 {
00108     return file->uri;
00109 }
00110 
00111 EXPORT void * vfs_get_handle (VFSFile * file)
00112 {
00113     return file->handle;
00114 }
00115 
00124 EXPORT VFSFile *
00125 vfs_fopen(const char * path,
00126           const char * mode)
00127 {
00128     g_return_val_if_fail (path && mode, NULL);
00129     g_return_val_if_fail (lookup_func, NULL);
00130 
00131     const char * s = strstr (path, "://");
00132     g_return_val_if_fail (s, NULL);
00133     char scheme[s - path + 1];
00134     strncpy (scheme, path, s - path);
00135     scheme[s - path] = 0;
00136 
00137     VFSConstructor * vtable = lookup_func (scheme);
00138     if (! vtable)
00139         return NULL;
00140 
00141     const gchar * sub;
00142     uri_parse (path, NULL, NULL, & sub, NULL);
00143 
00144     gchar buf[sub - path + 1];
00145     memcpy (buf, path, sub - path);
00146     buf[sub - path] = 0;
00147 
00148     void * handle = vtable->vfs_fopen_impl (buf, mode);
00149     if (! handle)
00150         return NULL;
00151 
00152     VFSFile * file = vfs_new (path, vtable, handle);
00153 
00154     if (verbose)
00155         logger ("VFS: <%p> open (mode %s) %s\n", file, mode, path);
00156 
00157     return file;
00158 }
00159 
00166 EXPORT int
00167 vfs_fclose(VFSFile * file)
00168 {
00169     g_return_val_if_fail (file && file->sig == VFS_SIG, -1);
00170 
00171     if (verbose)
00172         logger ("VFS: <%p> close\n", file);
00173 
00174     int ret = 0;
00175 
00176     if (file->base->vfs_fclose_impl(file) != 0)
00177         ret = -1;
00178 
00179     str_unref (file->uri);
00180 
00181     memset (file, 0, sizeof (VFSFile));
00182     g_slice_free (VFSFile, file);
00183 
00184     return ret;
00185 }
00186 
00196 EXPORT int64_t vfs_fread (void * ptr, int64_t size, int64_t nmemb, VFSFile * file)
00197 {
00198     g_return_val_if_fail (file && file->sig == VFS_SIG, 0);
00199 
00200     int64_t readed = file->base->vfs_fread_impl (ptr, size, nmemb, file);
00201 
00202 /*    if (verbose)
00203         logger ("VFS: <%p> read %"PRId64" elements of size %"PRId64" = "
00204          "%"PRId64"\n", file, nmemb, size, readed); */
00205 
00206     return readed;
00207 }
00208 
00218 EXPORT int64_t vfs_fwrite (const void * ptr, int64_t size, int64_t nmemb, VFSFile * file)
00219 {
00220     g_return_val_if_fail (file && file->sig == VFS_SIG, 0);
00221 
00222     int64_t written = file->base->vfs_fwrite_impl (ptr, size, nmemb, file);
00223 
00224     if (verbose)
00225         logger ("VFS: <%p> write %"PRId64" elements of size %"PRId64" = "
00226          "%"PRId64"\n", file, nmemb, size, written);
00227 
00228     return written;
00229 }
00230 
00237 EXPORT int
00238 vfs_getc(VFSFile *file)
00239 {
00240     g_return_val_if_fail (file && file->sig == VFS_SIG, EOF);
00241 
00242     if (verbose)
00243         logger ("VFS: <%p> getc\n", file);
00244 
00245     return file->base->vfs_getc_impl(file);
00246 }
00247 
00255 EXPORT int
00256 vfs_ungetc(int c, VFSFile *file)
00257 {
00258     g_return_val_if_fail (file && file->sig == VFS_SIG, EOF);
00259 
00260     if (verbose)
00261         logger ("VFS: <%p> ungetc\n", file);
00262 
00263     return file->base->vfs_ungetc_impl(c, file);
00264 }
00265 
00279 EXPORT int
00280 vfs_fseek(VFSFile * file,
00281           int64_t offset,
00282           int whence)
00283 {
00284     g_return_val_if_fail (file && file->sig == VFS_SIG, -1);
00285 
00286     if (verbose)
00287         logger ("VFS: <%p> seek to %"PRId64" from %s\n", file, offset, whence ==
00288          SEEK_CUR ? "current" : whence == SEEK_SET ? "beginning" : whence ==
00289          SEEK_END ? "end" : "invalid");
00290 
00291     return file->base->vfs_fseek_impl(file, offset, whence);
00292 }
00293 
00299 EXPORT void
00300 vfs_rewind(VFSFile * file)
00301 {
00302     g_return_if_fail (file && file->sig == VFS_SIG);
00303 
00304     if (verbose)
00305         logger ("VFS: <%p> rewind\n", file);
00306 
00307     file->base->vfs_rewind_impl(file);
00308 }
00309 
00316 EXPORT int64_t
00317 vfs_ftell(VFSFile * file)
00318 {
00319     g_return_val_if_fail (file && file->sig == VFS_SIG, -1);
00320 
00321     int64_t told = file->base->vfs_ftell_impl (file);
00322 
00323     if (verbose)
00324         logger ("VFS: <%p> tell = %"PRId64"\n", file, told);
00325 
00326     return told;
00327 }
00328 
00335 EXPORT bool_t
00336 vfs_feof(VFSFile * file)
00337 {
00338     g_return_val_if_fail (file && file->sig == VFS_SIG, TRUE);
00339 
00340     bool_t eof = file->base->vfs_feof_impl (file);
00341 
00342     if (verbose)
00343         logger ("VFS: <%p> eof = %s\n", file, eof ? "yes" : "no");
00344 
00345     return eof;
00346 }
00347 
00355 EXPORT int vfs_ftruncate (VFSFile * file, int64_t length)
00356 {
00357     g_return_val_if_fail (file && file->sig == VFS_SIG, -1);
00358 
00359     if (verbose)
00360         logger ("VFS: <%p> truncate to %"PRId64"\n", file, length);
00361 
00362     return file->base->vfs_ftruncate_impl(file, length);
00363 }
00364 
00371 EXPORT int64_t vfs_fsize (VFSFile * file)
00372 {
00373     g_return_val_if_fail (file && file->sig == VFS_SIG, -1);
00374 
00375     int64_t size = file->base->vfs_fsize_impl (file);
00376 
00377     if (verbose)
00378         logger ("VFS: <%p> size = %"PRId64"\n", file, size);
00379 
00380     return size;
00381 }
00382 
00390 EXPORT char *
00391 vfs_get_metadata(VFSFile * file, const char * field)
00392 {
00393     if (file == NULL)
00394         return NULL;
00395 
00396     if (file->base->vfs_get_metadata_impl)
00397         return file->base->vfs_get_metadata_impl(file, field);
00398     return NULL;
00399 }
00400 
00408 EXPORT bool_t
00409 vfs_file_test(const char * path, int test)
00410 {
00411     if (strncmp (path, "file://", 7))
00412         return FALSE; /* only local files are handled */
00413 
00414     char * path2 = uri_to_filename (path);
00415 
00416     if (path2 == NULL)
00417         path2 = g_strdup(path);
00418 
00419     bool_t ret = g_file_test (path2, test);
00420 
00421     g_free(path2);
00422 
00423     return ret;
00424 }
00425 
00432 EXPORT bool_t
00433 vfs_is_writeable(const char * path)
00434 {
00435     struct stat info;
00436     char * realfn = uri_to_filename (path);
00437 
00438     if (stat(realfn, &info) == -1)
00439         return FALSE;
00440 
00441     g_free(realfn);
00442 
00443     return (info.st_mode & S_IWUSR);
00444 }
00445 
00452 EXPORT bool_t vfs_is_remote (const char * path)
00453 {
00454     return strncmp (path, "file://", 7) ? TRUE : FALSE;
00455 }
00456 
00463 EXPORT bool_t vfs_is_streaming (VFSFile * file)
00464 {
00465     return (vfs_fsize (file) < 0);
00466 }