Audacious $Id:Doxyfile42802007-03-2104:39:00Znenolod$
vfs.c
Go to the documentation of this file.
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 static VFSConstructor * (* lookup_func) (const gchar * scheme) = NULL;
00039 
00040 void vfs_set_lookup_func (VFSConstructor * (* func) (const gchar * scheme))
00041 {
00042     lookup_func = func;
00043 }
00044 
00045 static gboolean verbose = FALSE;
00046 
00047 void vfs_set_verbose (gboolean set)
00048 {
00049     verbose = set;
00050 }
00051 
00052 static void logger (const gchar * format, ...)
00053 {
00054     static gchar last[256] = "";
00055     static gint repeated = 0;
00056 
00057     gchar buf[256];
00058 
00059     va_list args;
00060     va_start (args, format);
00061     vsnprintf (buf, sizeof buf, format, args);
00062     va_end (args);
00063 
00064     if (! strcmp (buf, last))
00065         repeated ++;
00066     else
00067     {
00068         if (repeated)
00069         {
00070             printf ("VFS: (last message repeated %d times)\n", repeated);
00071             repeated = 0;
00072         }
00073 
00074         fputs (buf, stdout);
00075         strcpy (last, buf);
00076     }
00077 }
00078 
00087 VFSFile *
00088 vfs_fopen(const gchar * path,
00089           const gchar * mode)
00090 {
00091     g_return_val_if_fail (path && mode, NULL);
00092     g_return_val_if_fail (lookup_func, NULL);
00093 
00094     VFSFile *file;
00095     VFSConstructor *vtable = NULL;
00096 
00097     const gchar * s = strstr (path, "://");
00098     g_return_val_if_fail (s, NULL);
00099     gchar scheme[s - path + 1];
00100     strncpy (scheme, path, s - path);
00101     scheme[s - path] = 0;
00102 
00103     vtable = lookup_func (scheme);
00104     if (! vtable)
00105         return NULL;
00106 
00107     file = vtable->vfs_fopen_impl(path, mode);
00108 
00109     if (verbose)
00110         logger ("VFS: <%p> open (mode %s) %s\n", file, mode, path);
00111 
00112     if (file == NULL)
00113         return NULL;
00114 
00115     file->uri = g_strdup(path);
00116     file->base = vtable;
00117     file->ref = 1;
00118     file->sig = VFS_SIG;
00119 
00120     return file;
00121 }
00122 
00129 gint
00130 vfs_fclose(VFSFile * file)
00131 {
00132     g_return_val_if_fail (file && file->sig == VFS_SIG, -1);
00133 
00134     if (verbose)
00135         printf ("VFS: <%p> close\n", file);
00136 
00137     gint ret = 0;
00138 
00139     if (--file->ref > 0)
00140         return -1;
00141 
00142     if (file->base->vfs_fclose_impl(file) != 0)
00143         ret = -1;
00144 
00145     g_free(file->uri);
00146 
00147     memset (file, 0, sizeof (VFSFile));
00148     g_free (file);
00149 
00150     return ret;
00151 }
00152 
00162 gint64 vfs_fread (void * ptr, gint64 size, gint64 nmemb, VFSFile * file)
00163 {
00164     g_return_val_if_fail (file && file->sig == VFS_SIG, 0);
00165 
00166     gint64 readed = file->base->vfs_fread_impl (ptr, size, nmemb, file);
00167 
00168     if (verbose)
00169         logger ("VFS: <%p> read %"PRId64" elements of size %"PRId64" = "
00170          "%"PRId64"\n", file, nmemb, size, readed);
00171 
00172     return readed;
00173 }
00174 
00184 gint64 vfs_fwrite (const void * ptr, gint64 size, gint64 nmemb, VFSFile * file)
00185 {
00186     g_return_val_if_fail (file && file->sig == VFS_SIG, 0);
00187 
00188     gint64 written = file->base->vfs_fwrite_impl (ptr, size, nmemb, file);
00189 
00190     if (verbose)
00191         logger ("VFS: <%p> write %"PRId64" elements of size %"PRId64" = "
00192          "%"PRId64"\n", file, nmemb, size, written);
00193 
00194     return written;
00195 }
00196 
00203 gint
00204 vfs_getc(VFSFile *file)
00205 {
00206     g_return_val_if_fail (file && file->sig == VFS_SIG, EOF);
00207 
00208     if (verbose)
00209         logger ("VFS: <%p> getc\n", file);
00210 
00211     return file->base->vfs_getc_impl(file);
00212 }
00213 
00221 gint
00222 vfs_ungetc(gint c, VFSFile *file)
00223 {
00224     g_return_val_if_fail (file && file->sig == VFS_SIG, EOF);
00225 
00226     if (verbose)
00227         logger ("VFS: <%p> ungetc\n", file);
00228 
00229     return file->base->vfs_ungetc_impl(c, file);
00230 }
00231 
00245 gint
00246 vfs_fseek(VFSFile * file,
00247           gint64 offset,
00248           gint whence)
00249 {
00250     g_return_val_if_fail (file && file->sig == VFS_SIG, -1);
00251 
00252     if (verbose)
00253         logger ("VFS: <%p> seek to %"PRId64" from %s\n", file, offset, whence ==
00254          SEEK_CUR ? "current" : whence == SEEK_SET ? "beginning" : whence ==
00255          SEEK_END ? "end" : "invalid");
00256 
00257     return file->base->vfs_fseek_impl(file, offset, whence);
00258 }
00259 
00265 void
00266 vfs_rewind(VFSFile * file)
00267 {
00268     g_return_if_fail (file && file->sig == VFS_SIG);
00269 
00270     if (verbose)
00271         logger ("VFS: <%p> rewind\n", file);
00272 
00273     file->base->vfs_rewind_impl(file);
00274 }
00275 
00282 gint64
00283 vfs_ftell(VFSFile * file)
00284 {
00285     g_return_val_if_fail (file && file->sig == VFS_SIG, -1);
00286 
00287     gint64 told = file->base->vfs_ftell_impl (file);
00288 
00289     if (verbose)
00290         logger ("VFS: <%p> tell = %"PRId64"\n", file, told);
00291 
00292     return told;
00293 }
00294 
00301 gboolean
00302 vfs_feof(VFSFile * file)
00303 {
00304     g_return_val_if_fail (file && file->sig == VFS_SIG, TRUE);
00305 
00306     gboolean eof = file->base->vfs_feof_impl (file);
00307 
00308     if (verbose)
00309         logger ("VFS: <%p> eof = %s\n", file, eof ? "yes" : "no");
00310 
00311     return eof;
00312 }
00313 
00321 gint vfs_ftruncate (VFSFile * file, gint64 length)
00322 {
00323     g_return_val_if_fail (file && file->sig == VFS_SIG, -1);
00324 
00325     if (verbose)
00326         logger ("VFS: <%p> truncate to %"PRId64"\n", file, length);
00327 
00328     return file->base->vfs_ftruncate_impl(file, length);
00329 }
00330 
00337 gint64 vfs_fsize (VFSFile * file)
00338 {
00339     g_return_val_if_fail (file && file->sig == VFS_SIG, -1);
00340 
00341     gint64 size = file->base->vfs_fsize_impl (file);
00342 
00343     if (verbose)
00344         logger ("VFS: <%p> size = %"PRId64"\n", file, size);
00345 
00346     return size;
00347 }
00348 
00356 gchar *
00357 vfs_get_metadata(VFSFile * file, const gchar * field)
00358 {
00359     if (file == NULL)
00360         return NULL;
00361 
00362     if (file->base->vfs_get_metadata_impl)
00363         return file->base->vfs_get_metadata_impl(file, field);
00364     return NULL;
00365 }
00366 
00374 gboolean
00375 vfs_file_test(const gchar * path, GFileTest test)
00376 {
00377     if (strncmp (path, "file://", 7))
00378         return FALSE; /* only local files are handled */
00379 
00380     gchar * path2 = uri_to_filename (path);
00381 
00382     if (path2 == NULL)
00383         path2 = g_strdup(path);
00384 
00385     gboolean ret = g_file_test (path2, test);
00386 
00387     g_free(path2);
00388 
00389     return ret;
00390 }
00391 
00398 gboolean
00399 vfs_is_writeable(const gchar * path)
00400 {
00401     struct stat info;
00402     gchar * realfn = uri_to_filename (path);
00403 
00404     if (stat(realfn, &info) == -1)
00405         return FALSE;
00406 
00407     g_free(realfn);
00408 
00409     return (info.st_mode & S_IWUSR);
00410 }
00411 
00421 VFSFile *
00422 vfs_dup(VFSFile *in)
00423 {
00424     g_return_val_if_fail(in != NULL, NULL);
00425 
00426     in->ref++;
00427 
00428     return in;
00429 }
00430 
00437 gboolean
00438 vfs_is_remote(const gchar * path)
00439 {
00440     return strncasecmp (path, "file://", 7) ? TRUE : FALSE;
00441 }
00442 
00449 gboolean
00450 vfs_is_streaming(VFSFile *file)
00451 {
00452     off_t size = 0;
00453 
00454     if (file == NULL)
00455         return FALSE;
00456 
00457     size = file->base->vfs_fsize_impl(file);
00458 
00459     if (size == -1)
00460         return TRUE;
00461     else
00462         return FALSE;
00463 }