2313
|
1 /* Audacious
|
|
2 * Copyright (c) 2006-2007 William Pitcock
|
|
3 *
|
|
4 * This program is free software; you can redistribute it and/or modify
|
|
5 * it under the terms of the GNU General Public License as published by
|
|
6 * the Free Software Foundation; under version 2 of the License.
|
|
7 *
|
|
8 * This program is distributed in the hope that it will be useful,
|
|
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
11 * GNU General Public License for more details.
|
|
12 *
|
|
13 * You should have received a copy of the GNU General Public License
|
|
14 * along with this program; if not, write to the Free Software
|
|
15 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
16 */
|
|
17
|
|
18 #include "vfs.h"
|
|
19 #include <stdio.h>
|
|
20
|
|
21 #include <unistd.h>
|
|
22 #include <sys/stat.h>
|
|
23 #include <sys/types.h>
|
|
24
|
|
25 #include "libaudacious/urldecode.h"
|
|
26
|
|
27 static GList *vfs_transports = NULL;
|
|
28
|
|
29 #ifdef VFS_DEBUG
|
|
30 # define DBG(x, args...) g_print(x, ## args);
|
|
31 #else
|
|
32 # define DBG(x, args...)
|
|
33 #endif
|
|
34
|
|
35 /**
|
|
36 * vfs_register_transport:
|
|
37 * @vtable: The #VFSConstructor vtable to register.
|
|
38 *
|
|
39 * Registers a #VFSConstructor vtable with the VFS system.
|
|
40 *
|
|
41 * Return value: TRUE on success, FALSE on failure.
|
|
42 **/
|
|
43 gboolean
|
|
44 vfs_register_transport(VFSConstructor *vtable)
|
|
45 {
|
|
46 vfs_transports = g_list_append(vfs_transports, vtable);
|
|
47
|
|
48 return TRUE;
|
|
49 }
|
|
50
|
|
51 /**
|
|
52 * vfs_fopen:
|
|
53 * @path: The path or URI to open.
|
|
54 * @mode: The preferred access privileges (not guaranteed).
|
|
55 *
|
|
56 * Opens a stream from a VFS transport using a #VFSConstructor.
|
|
57 *
|
|
58 * Return value: On success, a #VFSFile object representing the stream.
|
|
59 **/
|
|
60 VFSFile *
|
|
61 vfs_fopen(const gchar * path,
|
|
62 const gchar * mode)
|
|
63 {
|
|
64 VFSFile *file;
|
|
65 gchar **vec;
|
|
66 VFSConstructor *vtable = NULL;
|
|
67 GList *node;
|
|
68 gchar *decpath;
|
|
69
|
|
70 if (!path || !mode)
|
|
71 return NULL;
|
|
72
|
|
73 decpath = xmms_urldecode_plain(path);
|
|
74
|
|
75 vec = g_strsplit(decpath, "://", 2);
|
|
76
|
|
77 /* special case: no transport specified, look for the "/" transport */
|
|
78 if (vec[1] == NULL)
|
|
79 {
|
|
80 for (node = vfs_transports; node != NULL; node = g_list_next(node))
|
|
81 {
|
|
82 vtable = (VFSConstructor *) node->data;
|
|
83
|
|
84 if (*vtable->uri_id == '/')
|
|
85 break;
|
|
86 }
|
|
87 }
|
|
88 else
|
|
89 {
|
|
90 for (node = vfs_transports; node != NULL; node = g_list_next(node))
|
|
91 {
|
|
92 vtable = (VFSConstructor *) node->data;
|
|
93
|
|
94 if (!g_strcasecmp(vec[0], vtable->uri_id))
|
|
95 break;
|
|
96 }
|
|
97 }
|
|
98
|
|
99 /* no transport vtable has been registered, bail. */
|
|
100 if (vtable == NULL)
|
|
101 {
|
|
102 g_strfreev(vec);
|
|
103 return NULL;
|
|
104 }
|
|
105
|
|
106 file = vtable->vfs_fopen_impl(vec[1] ? vec[1] : vec[0], mode);
|
|
107
|
|
108 if (file == NULL)
|
|
109 {
|
|
110 g_strfreev(vec);
|
|
111 return NULL;
|
|
112 }
|
|
113
|
|
114 file->uri = g_strdup(path);
|
|
115 file->base = vtable;
|
|
116
|
|
117 g_strfreev(vec);
|
|
118 g_free(decpath);
|
|
119
|
|
120 return file;
|
|
121 }
|
|
122
|
|
123 /**
|
|
124 * vfs_fclose:
|
|
125 * @file: A #VFSFile object to destroy.
|
|
126 *
|
|
127 * Closes a VFS stream and destroys a #VFSFile object.
|
|
128 *
|
|
129 * Return value: -1 on failure, 0 on success.
|
|
130 **/
|
|
131 gint
|
|
132 vfs_fclose(VFSFile * file)
|
|
133 {
|
|
134 gint ret = 0;
|
|
135
|
|
136 if (file == NULL)
|
|
137 return -1;
|
|
138
|
|
139 if (file->base->vfs_fclose_impl(file) != 0)
|
|
140 ret = -1;
|
|
141
|
|
142 if (file->uri != NULL)
|
|
143 g_free(file->uri);
|
|
144
|
|
145 g_free(file);
|
|
146
|
|
147 return ret;
|
|
148 }
|
|
149
|
|
150 /**
|
|
151 * vfs_fread:
|
|
152 * @ptr: A pointer to the destination buffer.
|
|
153 * @size: The size of each element to read.
|
|
154 * @nmemb: The number of elements to read.
|
|
155 * @file: #VFSFile object that represents the VFS stream.
|
|
156 *
|
|
157 * Reads from a VFS stream.
|
|
158 *
|
|
159 * Return value: The amount of elements succesfully read.
|
|
160 **/
|
|
161 size_t
|
|
162 vfs_fread(gpointer ptr,
|
|
163 size_t size,
|
|
164 size_t nmemb,
|
|
165 VFSFile * file)
|
|
166 {
|
|
167 if (file == NULL)
|
|
168 return 0;
|
|
169
|
|
170 return file->base->vfs_fread_impl(ptr, size, nmemb, file);
|
|
171 }
|
|
172
|
|
173 /**
|
|
174 * vfs_fwrite:
|
|
175 * @ptr: A const pointer to the source buffer.
|
|
176 * @size: The size of each element to write.
|
|
177 * @nmemb: The number of elements to write.
|
|
178 * @file: #VFSFile object that represents the VFS stream.
|
|
179 *
|
|
180 * Writes to a VFS stream.
|
|
181 *
|
|
182 * Return value: The amount of elements succesfully written.
|
|
183 **/
|
|
184 size_t
|
|
185 vfs_fwrite(gconstpointer ptr,
|
|
186 size_t size,
|
|
187 size_t nmemb,
|
|
188 VFSFile * file)
|
|
189 {
|
|
190 if (file == NULL)
|
|
191 return 0;
|
|
192
|
|
193 return file->base->vfs_fwrite_impl(ptr, size, nmemb, file);
|
|
194 }
|
|
195
|
|
196 /**
|
|
197 * vfs_getc:
|
|
198 * @stream: #VFSFile object that represents the VFS stream.
|
|
199 *
|
|
200 * Reads a character from a VFS stream.
|
|
201 *
|
|
202 * Return value: On success, a character. Otherwise, -1.
|
|
203 **/
|
|
204 gint
|
|
205 vfs_getc(VFSFile *stream)
|
|
206 {
|
|
207 if (stream == NULL)
|
|
208 return -1;
|
|
209
|
|
210 return stream->base->vfs_getc_impl(stream);
|
|
211 }
|
|
212
|
|
213 /**
|
|
214 * vfs_ungetc:
|
|
215 * @c: The character to push back.
|
|
216 * @stream: #VFSFile object that represents the VFS stream.
|
|
217 *
|
|
218 * Pushes a character back to the VFS stream.
|
|
219 *
|
|
220 * Return value: On success, 0. Otherwise, -1.
|
|
221 **/
|
|
222 gint
|
|
223 vfs_ungetc(gint c, VFSFile *stream)
|
|
224 {
|
|
225 if (stream == NULL)
|
|
226 return -1;
|
|
227
|
|
228 return stream->base->vfs_ungetc_impl(c, stream);
|
|
229 }
|
|
230
|
|
231 /**
|
|
232 * vfs_fseek:
|
|
233 * @file: #VFSFile object that represents the VFS stream.
|
|
234 * @offset: The offset to seek to.
|
|
235 * @whence: Whether or not the seek is absolute or not.
|
|
236 *
|
|
237 * Seeks through a VFS stream.
|
|
238 *
|
|
239 * Return value: On success, 1. Otherwise, 0.
|
|
240 **/
|
|
241 gint
|
|
242 vfs_fseek(VFSFile * file,
|
|
243 glong offset,
|
|
244 gint whence)
|
|
245 {
|
|
246 if (file == NULL)
|
|
247 return 0;
|
|
248
|
|
249 return file->base->vfs_fseek_impl(file, offset, whence);
|
|
250 }
|
|
251
|
|
252 /**
|
|
253 * vfs_rewind:
|
|
254 * @file: #VFSFile object that represents the VFS stream.
|
|
255 *
|
|
256 * Rewinds a VFS stream.
|
|
257 **/
|
|
258 void
|
|
259 vfs_rewind(VFSFile * file)
|
|
260 {
|
|
261 if (file == NULL)
|
|
262 return;
|
|
263
|
|
264 file->base->vfs_rewind_impl(file);
|
|
265 }
|
|
266
|
|
267 /**
|
|
268 * vfs_ftell:
|
|
269 * @file: #VFSFile object that represents the VFS stream.
|
|
270 *
|
|
271 * Returns the current position in the VFS stream's buffer.
|
|
272 *
|
|
273 * Return value: On success, the current position. Otherwise, -1.
|
|
274 **/
|
|
275 glong
|
|
276 vfs_ftell(VFSFile * file)
|
|
277 {
|
|
278 if (file == NULL)
|
|
279 return -1;
|
|
280
|
|
281 return file->base->vfs_ftell_impl(file);
|
|
282 }
|
|
283
|
|
284 /**
|
|
285 * vfs_feof:
|
|
286 * @file: #VFSFile object that represents the VFS stream.
|
|
287 *
|
|
288 * Returns whether or not the VFS stream has reached EOF.
|
|
289 *
|
|
290 * Return value: On success, whether or not the VFS stream is at EOF. Otherwise, FALSE.
|
|
291 **/
|
|
292 gboolean
|
|
293 vfs_feof(VFSFile * file)
|
|
294 {
|
|
295 if (file == NULL)
|
|
296 return FALSE;
|
|
297
|
|
298 return (gboolean) file->base->vfs_feof_impl(file);
|
|
299 }
|
|
300
|
|
301 /**
|
|
302 * vfs_truncate:
|
|
303 * @file: #VFSFile object that represents the VFS stream.
|
|
304 * @length: The length to truncate at.
|
|
305 *
|
|
306 * Truncates a VFS stream to a certain size.
|
|
307 *
|
|
308 * Return value: On success, 0. Otherwise, -1.
|
|
309 **/
|
|
310 gint
|
|
311 vfs_truncate(VFSFile * file, glong length)
|
|
312 {
|
|
313 if (file == NULL)
|
|
314 return -1;
|
|
315
|
|
316 return file->base->vfs_truncate_impl(file, length);
|
|
317 }
|
|
318
|
|
319 /**
|
|
320 * vfs_file_test:
|
|
321 * @path: A path to test.
|
|
322 * @test: A GFileTest to run.
|
|
323 *
|
|
324 * Wrapper for g_file_test().
|
|
325 *
|
|
326 * Return value: The result of g_file_test().
|
|
327 **/
|
|
328 gboolean
|
|
329 vfs_file_test(const gchar * path, GFileTest test)
|
|
330 {
|
|
331 return g_file_test(path, test);
|
|
332 }
|
|
333
|
|
334 /**
|
|
335 * vfs_is_writeable:
|
|
336 * @path: A path to test.
|
|
337 *
|
|
338 * Tests if a file is writeable.
|
|
339 *
|
|
340 * Return value: TRUE if the file is writeable, otherwise FALSE.
|
|
341 **/
|
|
342 gboolean
|
|
343 vfs_is_writeable(const gchar * path)
|
|
344 {
|
|
345 struct stat info;
|
|
346
|
|
347 if (stat(path, &info) == -1)
|
|
348 return FALSE;
|
|
349
|
|
350 return (info.st_mode & S_IWUSR);
|
|
351 }
|