ftp://ftp.redhat.com/pub/redhat/linux/rawhide/SRPMS/SRPMS/gnome-vfs2-2.3.8-1.src.rpm
[gnome-vfs-httpcaptive.git] / libgnomevfs / gnome-vfs-open-fd.c
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
2 /* gnome-vfs-open-fd.c - convert a file descriptor to a handle
3
4    Copyright (C) 2002 Giovanni Corriga
5
6    The Gnome Library is free software; you can redistribute it and/or
7    modify it under the terms of the GNU Library General Public License as
8    published by the Free Software Foundation; either version 2 of the
9    License, or (at your option) any later version.
10
11    The Gnome Library is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14    Library General Public License for more details.
15
16    You should have received a copy of the GNU Library General Public
17    License along with the Gnome Library; see the file COPYING.LIB.  If not,
18    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19    Boston, MA 02111-1307, USA.
20
21    Author: Giovanni Corriga <valkadesh@libero.it>
22 */
23
24 #include <config.h>
25 #include <errno.h>
26
27 #include <sys/types.h>
28 #include <unistd.h>
29 #include <fcntl.h>
30
31 #include "gnome-vfs-uri.h"
32 #include "gnome-vfs-method.h"
33 #include "gnome-vfs-handle.h"
34 #include "gnome-vfs-module-shared.h"
35 #include "gnome-vfs-mime.h"
36 #include "gnome-vfs-handle-private.h"
37 #include "gnome-vfs-utils.h"
38
39 static GnomeVFSURI*
40 create_anonymous_uri (GnomeVFSMethod* method)
41 {
42         GnomeVFSToplevelURI* tl_uri;
43         GnomeVFSURI* uri;
44         
45         tl_uri = g_new0 (GnomeVFSToplevelURI, 1);
46         
47         uri = (GnomeVFSURI *) tl_uri;
48         
49         uri->ref_count = 1;
50         uri->method = method;
51         
52         return uri;
53 }
54
55 typedef struct {
56         GnomeVFSURI *uri;
57         gint fd;
58 } FileHandle;
59
60 static FileHandle *
61 file_handle_new (GnomeVFSURI *uri,
62                  gint fd)
63 {
64         FileHandle *result;
65         result = g_new (FileHandle, 1);
66
67         result->uri = gnome_vfs_uri_ref (uri);
68         result->fd = fd;
69
70         return result;
71 }
72
73 static void
74 file_handle_destroy (FileHandle *handle)
75 {
76         gnome_vfs_uri_unref (handle->uri);
77         g_free (handle);
78 }
79
80 static GnomeVFSResult
81 do_close (GnomeVFSMethod *method,
82           GnomeVFSMethodHandle *method_handle,
83           GnomeVFSContext *context)
84 {
85         FileHandle *file_handle;
86         gint close_retval;
87
88         g_return_val_if_fail (method_handle != NULL, GNOME_VFS_ERROR_INTERNAL);
89
90         file_handle = (FileHandle *) method_handle;
91
92         do {
93                 close_retval = close (file_handle->fd);
94         } while (close_retval != 0
95                  && errno == EINTR
96                  && ! gnome_vfs_context_check_cancellation (context));
97         
98         /* FIXME bugzilla.eazel.com 1163: Should do this even after a failure?  */
99         file_handle_destroy (file_handle);
100
101         if (close_retval != 0) {
102                 return gnome_vfs_result_from_errno ();
103         }
104
105         return GNOME_VFS_OK;
106 }
107
108 static GnomeVFSResult
109 do_read (GnomeVFSMethod *method,
110          GnomeVFSMethodHandle *method_handle,
111          gpointer buffer,
112          GnomeVFSFileSize num_bytes,
113          GnomeVFSFileSize *bytes_read,
114          GnomeVFSContext *context)
115 {
116         FileHandle *file_handle;
117         gint read_val;
118
119         g_return_val_if_fail (method_handle != NULL, GNOME_VFS_ERROR_INTERNAL);
120
121         file_handle = (FileHandle *) method_handle;
122
123         do {
124                 read_val = read (file_handle->fd, buffer, num_bytes);
125         } while (read_val == -1
126                  && errno == EINTR
127                  && ! gnome_vfs_context_check_cancellation (context));
128
129         if (read_val == -1) {
130                 *bytes_read = 0;
131                 return gnome_vfs_result_from_errno ();
132         } else {
133                 *bytes_read = read_val;
134
135                 /* Getting 0 from read() means EOF! */
136                 if (read_val == 0) {
137                         return GNOME_VFS_ERROR_EOF;
138                 }
139         }
140         return GNOME_VFS_OK;
141 }
142
143 static GnomeVFSResult
144 do_write (GnomeVFSMethod *method,
145           GnomeVFSMethodHandle *method_handle,
146           gconstpointer buffer,
147           GnomeVFSFileSize num_bytes,
148           GnomeVFSFileSize *bytes_written,
149           GnomeVFSContext *context)
150 {
151         FileHandle *file_handle;
152         gint write_val;
153
154         g_return_val_if_fail (method_handle != NULL, GNOME_VFS_ERROR_INTERNAL);
155
156         file_handle = (FileHandle *) method_handle;
157
158         do {
159                 write_val = write (file_handle->fd, buffer, num_bytes);
160         } while (write_val == -1
161                 && errno == EINTR
162                 && ! gnome_vfs_context_check_cancellation (context));
163
164         if (write_val == -1) {
165                 *bytes_written = 0;
166                 return gnome_vfs_result_from_errno ();
167         } else {
168                 *bytes_written = write_val;
169                 return GNOME_VFS_OK;
170         }
171 }
172
173
174 static gint
175 seek_position_to_unix (GnomeVFSSeekPosition position)
176 {
177         switch (position) {
178         case GNOME_VFS_SEEK_START:
179                 return SEEK_SET;
180         case GNOME_VFS_SEEK_CURRENT:
181                 return SEEK_CUR;
182         case GNOME_VFS_SEEK_END:
183                 return SEEK_END;
184         default:
185                 return SEEK_SET; /* bogus */
186         }
187 }
188
189 static GnomeVFSResult
190 do_seek (GnomeVFSMethod *method,
191          GnomeVFSMethodHandle *method_handle,
192          GnomeVFSSeekPosition whence,
193          GnomeVFSFileOffset offset,
194          GnomeVFSContext *context)
195 {
196         FileHandle *file_handle;
197         gint lseek_whence;
198
199         file_handle = (FileHandle *) method_handle;
200         lseek_whence = seek_position_to_unix (whence);
201
202         if (lseek (file_handle->fd, offset, lseek_whence) == -1) {
203                 if (errno == ESPIPE) {
204                         return GNOME_VFS_ERROR_NOT_SUPPORTED;
205                 } else {
206                         return gnome_vfs_result_from_errno ();
207                 }
208         }
209
210         return GNOME_VFS_OK;
211 }
212
213 static GnomeVFSResult
214 do_tell (GnomeVFSMethod *method,
215          GnomeVFSMethodHandle *method_handle,
216          GnomeVFSFileOffset *offset_return)
217 {
218         FileHandle *file_handle;
219         off_t offset;
220
221         file_handle = (FileHandle *) method_handle;
222
223         offset = lseek (file_handle->fd, 0, SEEK_CUR);
224         if (offset == -1) {
225                 if (errno == ESPIPE) {
226                         return GNOME_VFS_ERROR_NOT_SUPPORTED;
227                 } else {
228                         return gnome_vfs_result_from_errno ();
229                 }
230         }
231
232         *offset_return = offset;
233         return GNOME_VFS_OK;
234 }
235
236
237 static GnomeVFSResult
238 do_truncate_handle (GnomeVFSMethod *method,
239                     GnomeVFSMethodHandle *method_handle,
240                     GnomeVFSFileSize where,
241                     GnomeVFSContext *context)
242 {
243         FileHandle *file_handle;
244
245         g_return_val_if_fail (method_handle != NULL, GNOME_VFS_ERROR_INTERNAL);
246
247         file_handle = (FileHandle *) method_handle;
248
249         if (ftruncate (file_handle->fd, where) == 0) {
250                 return GNOME_VFS_OK;
251         } else {
252                 switch (errno) {
253                 case EBADF:
254                 case EROFS:
255                         return GNOME_VFS_ERROR_READ_ONLY;
256                 case EINVAL:
257                         return GNOME_VFS_ERROR_NOT_SUPPORTED;
258                 default:
259                         return GNOME_VFS_ERROR_GENERIC;
260                 }
261         }
262 }
263
264 static GnomeVFSResult
265 get_stat_info_from_handle (GnomeVFSFileInfo *file_info,
266                            FileHandle *handle,
267                            GnomeVFSFileInfoOptions options,
268                            struct stat *statptr)
269 {
270         struct stat statbuf;
271
272         if (statptr == NULL) {
273                 statptr = &statbuf;
274         }
275
276         if (fstat (handle->fd, statptr) != 0) {
277                 return gnome_vfs_result_from_errno ();
278         }
279         
280         gnome_vfs_stat_to_file_info (file_info, statptr);
281         GNOME_VFS_FILE_INFO_SET_LOCAL (file_info, TRUE);
282
283         return GNOME_VFS_OK;
284 }
285
286 /* MIME detection code.  */
287 static void
288 get_mime_type (GnomeVFSFileInfo *info,
289                GnomeVFSFileInfoOptions options,
290                struct stat *stat_buffer)
291 {
292         const char *mime_type;
293
294         mime_type = NULL;
295         if ((options & GNOME_VFS_FILE_INFO_FOLLOW_LINKS) == 0
296                 && (info->type == GNOME_VFS_FILE_TYPE_SYMBOLIC_LINK)) {
297                 /* we are a symlink and aren't asked to follow -
298                  * return the type for a symlink
299                  */
300                 mime_type = "x-special/symlink";
301         } else {
302                 mime_type = gnome_vfs_get_file_mime_type (NULL, stat_buffer,
303                                 (options & GNOME_VFS_FILE_INFO_FORCE_FAST_MIME_TYPE) != 0);
304         }
305
306         g_assert (mime_type);
307         info->mime_type = g_strdup (mime_type);
308         info->valid_fields |= GNOME_VFS_FILE_INFO_FIELDS_MIME_TYPE;
309 }
310
311 static GnomeVFSResult
312 do_get_file_info_from_handle (GnomeVFSMethod *method,
313                               GnomeVFSMethodHandle *method_handle,
314                               GnomeVFSFileInfo *file_info,
315                               GnomeVFSFileInfoOptions options,
316                               GnomeVFSContext *context)
317 {
318         FileHandle *file_handle;
319         struct stat statbuf;
320         GnomeVFSResult result;
321
322         file_handle = (FileHandle *) method_handle;
323
324         file_info->valid_fields = GNOME_VFS_FILE_INFO_FIELDS_NONE;
325
326         result = get_stat_info_from_handle (file_info, file_handle,
327                                             options, &statbuf);
328         if (result != GNOME_VFS_OK) {
329                 return result;
330         }
331
332         if (options & GNOME_VFS_FILE_INFO_GET_MIME_TYPE) {
333                 get_mime_type (file_info, options, &statbuf);
334         }
335
336         return GNOME_VFS_OK;
337 }
338
339 static gboolean
340 do_is_local (GnomeVFSMethod *method,
341              const GnomeVFSURI *uri)
342 {
343         return TRUE;
344 }
345
346 static GnomeVFSMethod method = {
347         sizeof (GnomeVFSMethod),
348         NULL, /* do_open */
349         NULL, /* do_create */
350         do_close,
351         do_read,
352         do_write,
353         do_seek,
354         do_tell,
355         do_truncate_handle,
356         NULL, /* do_open_directory */
357         NULL, /* do_close_directory */
358         NULL, /* do_read_directory */
359         NULL, /* do_get_file_info */
360         do_get_file_info_from_handle,
361         do_is_local,
362         NULL, /* do_make_directory */
363         NULL, /* do_remove_directory */
364         NULL, /* do_move */
365         NULL, /* do_unlink */
366         NULL, /* do_check_same_fs */
367         NULL, /* do_set_file_info */
368         NULL, /* do_truncate */
369         NULL, /* do_find_directory */
370         NULL, /* do_create_symbolic_link */
371         NULL, /* do_monitor_add */
372         NULL, /* do_monitor_cancel */
373 };
374
375 static GnomeVFSOpenMode
376 get_open_mode (gint filedes)
377 {
378         int flags;
379
380         flags = fcntl(filedes, F_GETFL);
381         if (flags & O_RDONLY) {
382                 return GNOME_VFS_OPEN_READ;
383         } else if (flags & O_WRONLY) {
384                 return GNOME_VFS_OPEN_WRITE;
385         } else if (flags & O_RDWR) {
386                 return (GNOME_VFS_OPEN_READ | GNOME_VFS_OPEN_WRITE);
387         }
388
389         return GNOME_VFS_OPEN_READ; /* bogus */
390 }
391
392 /**
393  * gnome_vfs_open_fs:
394  * @handle: A pointer to a pointer to a GnomeVFSHandle object
395  * @filedes: a UNIX file descriptor
396  * 
397  * Converts an open unix file descript into a GnomeVFSHandle that 
398  * can be used with the normal GnomeVFS file operations. When the
399  * handle is closed the file descriptor will also be closed.
400  *
401  * Return Value: %GNOME_VFS_OK if the open was ok, a suitable error otherwise.
402  *
403  * Since 2.2
404  **/
405
406 GnomeVFSResult
407 gnome_vfs_open_fd (GnomeVFSHandle **handle, int filedes)
408 {
409         GnomeVFSURI* uri;
410         FileHandle* file_handle;
411         GnomeVFSOpenMode open_mode;
412         
413         g_return_val_if_fail(handle != NULL, GNOME_VFS_ERROR_BAD_PARAMETERS);
414         
415         uri = create_anonymous_uri (&method);
416
417         open_mode = get_open_mode (filedes);
418         
419         file_handle = file_handle_new (uri, filedes);
420         
421         *handle = _gnome_vfs_handle_new (uri, (GnomeVFSMethodHandle*)file_handle, open_mode);
422         if (!handle) {
423                 return GNOME_VFS_ERROR_INTERNAL;
424         }
425         
426         return GNOME_VFS_OK;
427 }
428