Audacious  $Id:Doxyfile42802007-03-2104:39:00Znenolod$
vfs.c
Go to the documentation of this file.
1 /*
2  * vfs.c
3  * Copyright 2006-2011 William Pitcock, Daniel Barkalow, Ralf Ertzinger,
4  * Yoshiki Yazawa, Matti Hämäläinen, and John Lindgren
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; under version 3 of the License.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program. If not, see <http://www.gnu.org/licenses>.
17  *
18  * The Audacious team does not consider modular code linking to
19  * Audacious or using our public API to be a derived work.
20  */
21 
22 #include <glib.h>
23 #include <inttypes.h>
24 
25 #include "vfs.h"
26 #include "audstrings.h"
27 #include <stdio.h>
28 #include <unistd.h>
29 #include <sys/stat.h>
30 #include <sys/types.h>
31 #include <string.h>
32 
33 #include "config.h"
34 
35 #define VFS_SIG ('V' | ('F' << 8) | ('S' << 16))
36 
42 struct _VFSFile {
43  char * uri;
45  void * handle;
46  int sig;
47 };
48 
49 /* Audacious core provides us with a function that looks up a VFS transport for
50  * a given URI scheme. Since this function will load plugins as needed, it can
51  * only be called from the main thread. When VFS is used from parallel threads,
52  * vfs_prepare must be called from the main thread to look up any needed
53  * transports beforehand. */
54 
55 static VFSConstructor * (* lookup_func) (const char * scheme) = NULL;
56 
57 EXPORT void vfs_set_lookup_func (VFSConstructor * (* func) (const char * scheme))
58 {
59  lookup_func = func;
60 }
61 
62 static bool_t verbose = FALSE;
63 
64 EXPORT void vfs_set_verbose (bool_t set)
65 {
66  verbose = set;
67 }
68 
69 static void logger (const char * format, ...)
70 {
71  static char last[256] = "";
72  static int repeated = 0;
73 
74  char buf[256];
75 
76  va_list args;
77  va_start (args, format);
78  vsnprintf (buf, sizeof buf, format, args);
79  va_end (args);
80 
81  if (! strcmp (buf, last))
82  repeated ++;
83  else
84  {
85  if (repeated)
86  {
87  printf ("VFS: (last message repeated %d times)\n", repeated);
88  repeated = 0;
89  }
90 
91  fputs (buf, stdout);
92  strcpy (last, buf);
93  }
94 }
95 
96 EXPORT VFSFile * vfs_new (const char * path, VFSConstructor * vtable, void * handle)
97 {
98  VFSFile * file = g_slice_new (VFSFile);
99  file->uri = str_get (path);
100  file->base = vtable;
101  file->handle = handle;
102  file->sig = VFS_SIG;
103  return file;
104 }
105 
106 EXPORT const char * vfs_get_filename (VFSFile * file)
107 {
108  return file->uri;
109 }
110 
111 EXPORT void * vfs_get_handle (VFSFile * file)
112 {
113  return file->handle;
114 }
115 
124 EXPORT VFSFile *
125 vfs_fopen(const char * path,
126  const char * mode)
127 {
128  g_return_val_if_fail (path && mode, NULL);
129  g_return_val_if_fail (lookup_func, NULL);
130 
131  const char * s = strstr (path, "://");
132  g_return_val_if_fail (s, NULL);
133  char scheme[s - path + 1];
134  strncpy (scheme, path, s - path);
135  scheme[s - path] = 0;
136 
137  VFSConstructor * vtable = lookup_func (scheme);
138  if (! vtable)
139  return NULL;
140 
141  const gchar * sub;
142  uri_parse (path, NULL, NULL, & sub, NULL);
143 
144  gchar buf[sub - path + 1];
145  memcpy (buf, path, sub - path);
146  buf[sub - path] = 0;
147 
148  void * handle = vtable->vfs_fopen_impl (buf, mode);
149  if (! handle)
150  return NULL;
151 
152  VFSFile * file = vfs_new (path, vtable, handle);
153 
154  if (verbose)
155  logger ("VFS: <%p> open (mode %s) %s\n", file, mode, path);
156 
157  return file;
158 }
159 
166 EXPORT int
168 {
169  g_return_val_if_fail (file && file->sig == VFS_SIG, -1);
170 
171  if (verbose)
172  logger ("VFS: <%p> close\n", file);
173 
174  int ret = 0;
175 
176  if (file->base->vfs_fclose_impl(file) != 0)
177  ret = -1;
178 
179  str_unref (file->uri);
180 
181  memset (file, 0, sizeof (VFSFile));
182  g_slice_free (VFSFile, file);
183 
184  return ret;
185 }
186 
196 EXPORT int64_t vfs_fread (void * ptr, int64_t size, int64_t nmemb, VFSFile * file)
197 {
198  g_return_val_if_fail (file && file->sig == VFS_SIG, 0);
199 
200  int64_t readed = file->base->vfs_fread_impl (ptr, size, nmemb, file);
201 
202 /* if (verbose)
203  logger ("VFS: <%p> read %"PRId64" elements of size %"PRId64" = "
204  "%"PRId64"\n", file, nmemb, size, readed); */
205 
206  return readed;
207 }
208 
218 EXPORT int64_t vfs_fwrite (const void * ptr, int64_t size, int64_t nmemb, VFSFile * file)
219 {
220  g_return_val_if_fail (file && file->sig == VFS_SIG, 0);
221 
222  int64_t written = file->base->vfs_fwrite_impl (ptr, size, nmemb, file);
223 
224  if (verbose)
225  logger ("VFS: <%p> write %"PRId64" elements of size %"PRId64" = "
226  "%"PRId64"\n", file, nmemb, size, written);
227 
228  return written;
229 }
230 
237 EXPORT int
239 {
240  g_return_val_if_fail (file && file->sig == VFS_SIG, EOF);
241 
242  if (verbose)
243  logger ("VFS: <%p> getc\n", file);
244 
245  return file->base->vfs_getc_impl(file);
246 }
247 
255 EXPORT int
256 vfs_ungetc(int c, VFSFile *file)
257 {
258  g_return_val_if_fail (file && file->sig == VFS_SIG, EOF);
259 
260  if (verbose)
261  logger ("VFS: <%p> ungetc\n", file);
262 
263  return file->base->vfs_ungetc_impl(c, file);
264 }
265 
279 EXPORT int
281  int64_t offset,
282  int whence)
283 {
284  g_return_val_if_fail (file && file->sig == VFS_SIG, -1);
285 
286  if (verbose)
287  logger ("VFS: <%p> seek to %"PRId64" from %s\n", file, offset, whence ==
288  SEEK_CUR ? "current" : whence == SEEK_SET ? "beginning" : whence ==
289  SEEK_END ? "end" : "invalid");
290 
291  return file->base->vfs_fseek_impl(file, offset, whence);
292 }
293 
299 EXPORT void
301 {
302  g_return_if_fail (file && file->sig == VFS_SIG);
303 
304  if (verbose)
305  logger ("VFS: <%p> rewind\n", file);
306 
307  file->base->vfs_rewind_impl(file);
308 }
309 
316 EXPORT int64_t
318 {
319  g_return_val_if_fail (file && file->sig == VFS_SIG, -1);
320 
321  int64_t told = file->base->vfs_ftell_impl (file);
322 
323  if (verbose)
324  logger ("VFS: <%p> tell = %"PRId64"\n", file, told);
325 
326  return told;
327 }
328 
335 EXPORT bool_t
337 {
338  g_return_val_if_fail (file && file->sig == VFS_SIG, TRUE);
339 
340  bool_t eof = file->base->vfs_feof_impl (file);
341 
342  if (verbose)
343  logger ("VFS: <%p> eof = %s\n", file, eof ? "yes" : "no");
344 
345  return eof;
346 }
347 
355 EXPORT int vfs_ftruncate (VFSFile * file, int64_t length)
356 {
357  g_return_val_if_fail (file && file->sig == VFS_SIG, -1);
358 
359  if (verbose)
360  logger ("VFS: <%p> truncate to %"PRId64"\n", file, length);
361 
362  return file->base->vfs_ftruncate_impl(file, length);
363 }
364 
371 EXPORT int64_t vfs_fsize (VFSFile * file)
372 {
373  g_return_val_if_fail (file && file->sig == VFS_SIG, -1);
374 
375  int64_t size = file->base->vfs_fsize_impl (file);
376 
377  if (verbose)
378  logger ("VFS: <%p> size = %"PRId64"\n", file, size);
379 
380  return size;
381 }
382 
390 EXPORT char *
391 vfs_get_metadata(VFSFile * file, const char * field)
392 {
393  if (file == NULL)
394  return NULL;
395 
396  if (file->base->vfs_get_metadata_impl)
397  return file->base->vfs_get_metadata_impl(file, field);
398  return NULL;
399 }
400 
408 EXPORT bool_t
409 vfs_file_test(const char * path, int test)
410 {
411  if (strncmp (path, "file://", 7))
412  return FALSE; /* only local files are handled */
413 
414  char * path2 = uri_to_filename (path);
415 
416  if (path2 == NULL)
417  path2 = g_strdup(path);
418 
419  bool_t ret = g_file_test (path2, test);
420 
421  g_free(path2);
422 
423  return ret;
424 }
425 
432 EXPORT bool_t
433 vfs_is_writeable(const char * path)
434 {
435  struct stat info;
436  char * realfn = uri_to_filename (path);
437 
438  if (stat(realfn, &info) == -1)
439  return FALSE;
440 
441  g_free(realfn);
442 
443  return (info.st_mode & S_IWUSR);
444 }
445 
452 EXPORT bool_t vfs_is_remote (const char * path)
453 {
454  return strncmp (path, "file://", 7) ? TRUE : FALSE;
455 }
456 
464 {
465  return (vfs_fsize (file) < 0);
466 }