Audacious
$Id:Doxyfile42802007-03-2104:39:00Znenolod$
|
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 }