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  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright notice,
10  * this list of conditions, and the following disclaimer.
11  *
12  * 2. Redistributions in binary form must reproduce the above copyright notice,
13  * this list of conditions, and the following disclaimer in the documentation
14  * provided with the distribution.
15  *
16  * This software is provided "as is" and without any warranty, express or
17  * implied. In no event shall the authors be liable for any damages arising from
18  * the use of this software.
19  */
20 
21 #include <glib.h>
22 #include <inttypes.h>
23 
24 #include "vfs.h"
25 #include "audstrings.h"
26 #include <stdio.h>
27 #include <unistd.h>
28 #include <sys/stat.h>
29 #include <sys/types.h>
30 #include <string.h>
31 
32 #include "config.h"
33 
34 #define VFS_SIG ('V' | ('F' << 8) | ('S' << 16))
35 
41 struct _VFSFile {
42  char * uri;
44  void * handle;
45  int sig;
46 };
47 
48 /* Audacious core provides us with a function that looks up a VFS transport for
49  * a given URI scheme. Since this function will load plugins as needed, it can
50  * only be called from the main thread. When VFS is used from parallel threads,
51  * vfs_prepare must be called from the main thread to look up any needed
52  * transports beforehand. */
53 
54 static VFSConstructor * (* lookup_func) (const char * scheme) = NULL;
55 
56 EXPORT void vfs_set_lookup_func (VFSConstructor * (* func) (const char * scheme))
57 {
58  lookup_func = func;
59 }
60 
61 static bool_t verbose = FALSE;
62 
63 EXPORT void vfs_set_verbose (bool_t set)
64 {
65  verbose = set;
66 }
67 
68 static void logger (const char * format, ...)
69 {
70  static char last[256] = "";
71  static int repeated = 0;
72 
73  char buf[256];
74 
75  va_list args;
76  va_start (args, format);
77  vsnprintf (buf, sizeof buf, format, args);
78  va_end (args);
79 
80  if (! strcmp (buf, last))
81  repeated ++;
82  else
83  {
84  if (repeated)
85  {
86  printf ("VFS: (last message repeated %d times)\n", repeated);
87  repeated = 0;
88  }
89 
90  fputs (buf, stdout);
91  strcpy (last, buf);
92  }
93 }
94 
95 EXPORT VFSFile * vfs_new (const char * path, VFSConstructor * vtable, void * handle)
96 {
97  VFSFile * file = g_slice_new (VFSFile);
98  file->uri = str_get (path);
99  file->base = vtable;
100  file->handle = handle;
101  file->sig = VFS_SIG;
102  return file;
103 }
104 
105 EXPORT const char * vfs_get_filename (VFSFile * file)
106 {
107  return file->uri;
108 }
109 
110 EXPORT void * vfs_get_handle (VFSFile * file)
111 {
112  return file->handle;
113 }
114 
123 EXPORT VFSFile *
124 vfs_fopen(const char * path,
125  const char * mode)
126 {
127  g_return_val_if_fail (path && mode, NULL);
128  g_return_val_if_fail (lookup_func, NULL);
129 
130  const char * s = strstr (path, "://");
131  g_return_val_if_fail (s, NULL);
132  char scheme[s - path + 1];
133  strncpy (scheme, path, s - path);
134  scheme[s - path] = 0;
135 
136  VFSConstructor * vtable = lookup_func (scheme);
137  if (! vtable)
138  return NULL;
139 
140  const gchar * sub;
141  uri_parse (path, NULL, NULL, & sub, NULL);
142 
143  gchar buf[sub - path + 1];
144  memcpy (buf, path, sub - path);
145  buf[sub - path] = 0;
146 
147  void * handle = vtable->vfs_fopen_impl (buf, mode);
148  if (! handle)
149  return NULL;
150 
151  VFSFile * file = vfs_new (path, vtable, handle);
152 
153  if (verbose)
154  logger ("VFS: <%p> open (mode %s) %s\n", file, mode, path);
155 
156  return file;
157 }
158 
165 EXPORT int
167 {
168  g_return_val_if_fail (file && file->sig == VFS_SIG, -1);
169 
170  if (verbose)
171  logger ("VFS: <%p> close\n", file);
172 
173  int ret = 0;
174 
175  if (file->base->vfs_fclose_impl(file) != 0)
176  ret = -1;
177 
178  str_unref (file->uri);
179 
180  memset (file, 0, sizeof (VFSFile));
181  g_slice_free (VFSFile, file);
182 
183  return ret;
184 }
185 
195 EXPORT int64_t vfs_fread (void * ptr, int64_t size, int64_t nmemb, VFSFile * file)
196 {
197  g_return_val_if_fail (file && file->sig == VFS_SIG, 0);
198 
199  int64_t readed = file->base->vfs_fread_impl (ptr, size, nmemb, file);
200 
201 /* if (verbose)
202  logger ("VFS: <%p> read %"PRId64" elements of size %"PRId64" = "
203  "%"PRId64"\n", file, nmemb, size, readed); */
204 
205  return readed;
206 }
207 
217 EXPORT int64_t vfs_fwrite (const void * ptr, int64_t size, int64_t nmemb, VFSFile * file)
218 {
219  g_return_val_if_fail (file && file->sig == VFS_SIG, 0);
220 
221  int64_t written = file->base->vfs_fwrite_impl (ptr, size, nmemb, file);
222 
223  if (verbose)
224  logger ("VFS: <%p> write %"PRId64" elements of size %"PRId64" = "
225  "%"PRId64"\n", file, nmemb, size, written);
226 
227  return written;
228 }
229 
236 EXPORT int
238 {
239  g_return_val_if_fail (file && file->sig == VFS_SIG, EOF);
240 
241  if (verbose)
242  logger ("VFS: <%p> getc\n", file);
243 
244  return file->base->vfs_getc_impl(file);
245 }
246 
254 EXPORT int
255 vfs_ungetc(int c, VFSFile *file)
256 {
257  g_return_val_if_fail (file && file->sig == VFS_SIG, EOF);
258 
259  if (verbose)
260  logger ("VFS: <%p> ungetc\n", file);
261 
262  return file->base->vfs_ungetc_impl(c, file);
263 }
264 
278 EXPORT int
280  int64_t offset,
281  int whence)
282 {
283  g_return_val_if_fail (file && file->sig == VFS_SIG, -1);
284 
285  if (verbose)
286  logger ("VFS: <%p> seek to %"PRId64" from %s\n", file, offset, whence ==
287  SEEK_CUR ? "current" : whence == SEEK_SET ? "beginning" : whence ==
288  SEEK_END ? "end" : "invalid");
289 
290  return file->base->vfs_fseek_impl(file, offset, whence);
291 }
292 
298 EXPORT void
300 {
301  g_return_if_fail (file && file->sig == VFS_SIG);
302 
303  if (verbose)
304  logger ("VFS: <%p> rewind\n", file);
305 
306  file->base->vfs_rewind_impl(file);
307 }
308 
315 EXPORT int64_t
317 {
318  g_return_val_if_fail (file && file->sig == VFS_SIG, -1);
319 
320  int64_t told = file->base->vfs_ftell_impl (file);
321 
322  if (verbose)
323  logger ("VFS: <%p> tell = %"PRId64"\n", file, told);
324 
325  return told;
326 }
327 
334 EXPORT bool_t
336 {
337  g_return_val_if_fail (file && file->sig == VFS_SIG, TRUE);
338 
339  bool_t eof = file->base->vfs_feof_impl (file);
340 
341  if (verbose)
342  logger ("VFS: <%p> eof = %s\n", file, eof ? "yes" : "no");
343 
344  return eof;
345 }
346 
354 EXPORT int vfs_ftruncate (VFSFile * file, int64_t length)
355 {
356  g_return_val_if_fail (file && file->sig == VFS_SIG, -1);
357 
358  if (verbose)
359  logger ("VFS: <%p> truncate to %"PRId64"\n", file, length);
360 
361  return file->base->vfs_ftruncate_impl(file, length);
362 }
363 
370 EXPORT int64_t vfs_fsize (VFSFile * file)
371 {
372  g_return_val_if_fail (file && file->sig == VFS_SIG, -1);
373 
374  int64_t size = file->base->vfs_fsize_impl (file);
375 
376  if (verbose)
377  logger ("VFS: <%p> size = %"PRId64"\n", file, size);
378 
379  return size;
380 }
381 
389 EXPORT char *
390 vfs_get_metadata(VFSFile * file, const char * field)
391 {
392  if (file == NULL)
393  return NULL;
394 
395  if (file->base->vfs_get_metadata_impl)
396  return file->base->vfs_get_metadata_impl(file, field);
397  return NULL;
398 }
399 
407 EXPORT bool_t
408 vfs_file_test(const char * path, int test)
409 {
410  if (strncmp (path, "file://", 7))
411  return FALSE; /* only local files are handled */
412 
413  char * path2 = uri_to_filename (path);
414  if (! path2)
415  return FALSE;
416 
417 #ifdef S_ISLNK
418  if (test & VFS_IS_SYMLINK)
419  {
420  struct stat st;
421  if (lstat (path2, & st) < 0)
422  return FALSE;
423 
424  if (S_ISLNK (st.st_mode))
425  test &= ~VFS_IS_SYMLINK;
426  }
427 #endif
428 
430  {
431  struct stat st;
432  if (stat (path2, & st) < 0)
433  return FALSE;
434 
435  if (S_ISREG (st.st_mode))
436  test &= ~VFS_IS_REGULAR;
437  if (S_ISDIR (st.st_mode))
438  test &= ~VFS_IS_DIR;
439  if (st.st_mode & S_IXUSR)
440  test &= ~VFS_IS_EXECUTABLE;
441 
442  test &= ~VFS_EXISTS;
443  }
444 
445  g_free (path2);
446 
447  return ! test;
448 }
449 
456 EXPORT bool_t
457 vfs_is_writeable(const char * path)
458 {
459  struct stat info;
460  char * realfn = uri_to_filename (path);
461 
462  if (stat(realfn, &info) == -1)
463  return FALSE;
464 
465  g_free(realfn);
466 
467  return (info.st_mode & S_IWUSR);
468 }
469 
476 EXPORT bool_t vfs_is_remote (const char * path)
477 {
478  return strncmp (path, "file://", 7) ? TRUE : FALSE;
479 }
480 
488 {
489  return (vfs_fsize (file) < 0);
490 }