Initial original import from: fuse-2.4.2-2.fc4
[captive.git] / src / client / gnomevfs / giognomevfs.c
1 /* $Id$
2  * glib GIOChannel interface over gnome-vfs GnomeVFSURI for libcaptive
3  * Copyright (C) 2002-2003 Jan Kratochvil <project-captive@jankratochvil.net>
4  * 
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; exactly version 2 of June 1991 is required
8  * 
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  * 
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17  */
18
19
20 #include "config.h"
21
22 #include "captive/macros.h"
23 #include <libgnomevfs/gnome-vfs-method.h>
24 #include <libgnomevfs/gnome-vfs-ops.h>
25 #include <glib/gmessages.h>
26 #include "gnome-vfs-module.h"
27 #include "captive/options.h"
28 #include "../../libcaptive/client/lib.h"        /* for captive_giochannel_setup(); FIXME: pathname */
29
30
31 /* FIXME: fill 'err' */
32
33 struct captive_gnomevfs_giognomevfs {
34         GIOChannel iochannel;
35         GnomeVFSHandle *gnomevfshandle;
36         };
37
38 G_LOCK_DEFINE_STATIC(giochannel_funcs);
39 static GIOFuncs giochannel_funcs;
40
41
42 static gboolean validate_giognomevfs(struct captive_gnomevfs_giognomevfs *giognomevfs)
43 {
44         g_return_val_if_fail(giognomevfs!=NULL,FALSE);
45         g_return_val_if_fail(giognomevfs->gnomevfshandle!=NULL,FALSE);
46
47         return TRUE;
48 }
49
50
51 static GIOStatus captive_gnomevfs_giognomevfs_io_read
52                 (GIOChannel *channel,gchar *buf,gsize count,gsize *bytes_read,GError **err)
53 {
54 struct captive_gnomevfs_giognomevfs *giognomevfs=(struct captive_gnomevfs_giognomevfs *)channel;
55 GnomeVFSResult errvfsresult;
56 GnomeVFSFileSize bytes_read_local;
57
58         g_return_val_if_fail(validate_giognomevfs(giognomevfs),G_IO_STATUS_ERROR);
59         g_return_val_if_fail(buf!=NULL,G_IO_STATUS_ERROR);
60         g_return_val_if_fail(bytes_read!=NULL,G_IO_STATUS_ERROR);
61
62         errvfsresult=gnome_vfs_read(
63                         giognomevfs->gnomevfshandle,    /* handle */
64                         buf,    /* buffer */
65                         count,  /* bytes */
66                         &bytes_read_local);     /* bytes_read */
67         /* During seek in block device such as on URL file:///dev/hda1#captive-fastfat.sys-ro:/
68          * we will do llseek(2) on "/dev/hda1" device from captive_giochannel_size().
69          * During read on the end boundary of Linux kernel block device we will
70          * get GNOME_VFS_ERROR_IO at least from linux-kernel-2.4.19-ac4
71          * therefore it must be accepted without complaints by us.
72          * FIXME: It would be nice to detect the state when we are called from captive_giochannel_size().
73          */
74         if (errvfsresult==GNOME_VFS_ERROR_IO) {
75                 *bytes_read=0;
76                 return G_IO_STATUS_ERROR;
77                 }
78         g_return_val_if_fail((errvfsresult==GNOME_VFS_OK || errvfsresult==GNOME_VFS_ERROR_EOF),G_IO_STATUS_ERROR);
79
80         *bytes_read=bytes_read_local;
81         return (errvfsresult==GNOME_VFS_ERROR_EOF ? G_IO_STATUS_EOF : G_IO_STATUS_NORMAL);
82 }
83
84
85 static GIOStatus captive_gnomevfs_giognomevfs_io_write
86                 (GIOChannel *channel,const gchar *buf,gsize count,gsize *bytes_written,GError **err)
87 {
88 struct captive_gnomevfs_giognomevfs *giognomevfs=(struct captive_gnomevfs_giognomevfs *)channel;
89 GnomeVFSResult errvfsresult;
90 GnomeVFSFileSize bytes_written_local;
91
92         g_return_val_if_fail(validate_giognomevfs(giognomevfs),G_IO_STATUS_ERROR);
93         g_return_val_if_fail(buf!=NULL,G_IO_STATUS_ERROR);
94         g_return_val_if_fail(bytes_written!=NULL,G_IO_STATUS_ERROR);
95
96         errvfsresult=gnome_vfs_write(
97                         giognomevfs->gnomevfshandle,    /* handle */
98                         buf,    /* buffer */
99                         count,  /* bytes */
100                         &bytes_written_local);  /* bytes_written */
101         g_return_val_if_fail(errvfsresult==GNOME_VFS_OK,G_IO_STATUS_ERROR);
102
103         *bytes_written=bytes_written_local;
104         return G_IO_STATUS_NORMAL;
105 }
106
107
108 static GIOStatus captive_gnomevfs_giognomevfs_io_seek(GIOChannel *channel,gint64 offset,GSeekType type,GError **err)
109 {
110 struct captive_gnomevfs_giognomevfs *giognomevfs=(struct captive_gnomevfs_giognomevfs *)channel;
111 GnomeVFSSeekPosition whence;
112 GnomeVFSResult errvfsresult;
113
114         g_return_val_if_fail(validate_giognomevfs(giognomevfs),G_IO_STATUS_ERROR);
115
116         switch (type) {
117                 case G_SEEK_CUR: whence=GNOME_VFS_SEEK_CURRENT; break;
118                 case G_SEEK_SET: whence=GNOME_VFS_SEEK_START;   break;
119                 case G_SEEK_END: whence=GNOME_VFS_SEEK_END;     break;
120                 default: g_return_val_if_reached(G_IO_STATUS_ERROR);
121                 }
122         errvfsresult=gnome_vfs_seek(giognomevfs->gnomevfshandle,whence,offset);
123         /* During seek in block device such as on URL file:///dev/hda1#captive-fastfat.sys-ro:/
124          * we will do llseek(2) on "/dev/hda1" device from captive_giochannel_size().
125          * Although we are allowed to seek behind EOF on regular files
126          * at least linux-kernel-2.4.19-ac4/fs/block_dev.c/block_llseek() will give
127          * EINVAL on seek behind EOF therefore it must be accepted without complaints by us.
128          */
129         if (errvfsresult!=GNOME_VFS_OK)
130                 return G_IO_STATUS_ERROR;
131
132         return G_IO_STATUS_NORMAL;
133 }
134
135
136 static GIOStatus captive_gnomevfs_giognomevfs_io_close(GIOChannel *channel,GError **err)
137 {
138 struct captive_gnomevfs_giognomevfs *giognomevfs=(struct captive_gnomevfs_giognomevfs *)channel;
139
140         g_return_val_if_fail(validate_giognomevfs(giognomevfs),G_IO_STATUS_ERROR);
141
142         gnome_vfs_close(giognomevfs->gnomevfshandle);
143
144         return G_IO_STATUS_NORMAL;
145 }
146
147
148 static GSource* captive_gnomevfs_giognomevfs_io_create_watch(GIOChannel *channel,GIOCondition condition)
149 {
150 struct captive_gnomevfs_giognomevfs *giognomevfs=(struct captive_gnomevfs_giognomevfs *)channel;
151
152         g_return_val_if_fail(validate_giognomevfs(giognomevfs),NULL);
153
154         g_return_val_if_reached(NULL);  /* FIXME: NOT IMPLEMENTED YET */
155 }
156
157
158 static void captive_gnomevfs_giognomevfs_io_free(GIOChannel *channel)
159 {
160 struct captive_gnomevfs_giognomevfs *giognomevfs=(struct captive_gnomevfs_giognomevfs *)channel;
161
162         g_return_if_fail(validate_giognomevfs(giognomevfs));
163
164         g_free(giognomevfs);
165 }
166
167
168 static GIOStatus captive_gnomevfs_giognomevfs_io_set_flags(GIOChannel *channel,GIOFlags flags,GError **err)
169 {
170 struct captive_gnomevfs_giognomevfs *giognomevfs=(struct captive_gnomevfs_giognomevfs *)channel;
171
172         g_return_val_if_fail(validate_giognomevfs(giognomevfs),G_IO_STATUS_ERROR);
173
174         /* no G_IO_FLAG_APPEND and no G_IO_FLAG_NONBLOCK */
175         g_return_val_if_fail((flags&G_IO_FLAG_SET_MASK)==0,G_IO_STATUS_ERROR);
176
177         return G_IO_STATUS_NORMAL;
178 }
179
180
181 static GIOFlags captive_gnomevfs_giognomevfs_io_get_flags(GIOChannel *channel)
182 {
183 struct captive_gnomevfs_giognomevfs *giognomevfs=(struct captive_gnomevfs_giognomevfs *)channel;
184
185         g_return_val_if_fail(validate_giognomevfs(giognomevfs),0);
186
187         return 0;       /* | !G_IO_FLAG_APPEND | !G_IO_FLAG_NONBLOCK */
188 }
189
190
191 GnomeVFSResult captive_gnomevfs_giognomevfs_new
192                 (struct captive_gnomevfs_giognomevfs **giognomevfsp,GnomeVFSURI *uri,enum captive_option_rwmode rwmode)
193 {
194 GnomeVFSHandle *handle;
195 struct captive_gnomevfs_giognomevfs *giognomevfs;
196 GnomeVFSResult errvfsresult;
197
198         g_return_val_if_fail(giognomevfsp!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
199         g_return_val_if_fail(uri!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
200
201         errvfsresult=gnome_vfs_open_uri(&handle,uri,
202                         0       /* open_mode */
203                                         | GNOME_VFS_OPEN_RANDOM /* mandatory; otherwise we will get truncation if GNOME_VFS_OPEN_WRITE */
204                                         | GNOME_VFS_OPEN_READ
205                                         | (rwmode==CAPTIVE_OPTION_RWMODE_RW ? GNOME_VFS_OPEN_WRITE : 0));
206         g_return_val_if_fail(errvfsresult==GNOME_VFS_OK,errvfsresult);
207
208         G_LOCK(giochannel_funcs);
209         giochannel_funcs.io_read        =captive_gnomevfs_giognomevfs_io_read;
210         giochannel_funcs.io_write       =captive_gnomevfs_giognomevfs_io_write;
211         giochannel_funcs.io_seek        =captive_gnomevfs_giognomevfs_io_seek;
212         giochannel_funcs.io_close       =captive_gnomevfs_giognomevfs_io_close;
213         giochannel_funcs.io_create_watch=captive_gnomevfs_giognomevfs_io_create_watch;
214         giochannel_funcs.io_free        =captive_gnomevfs_giognomevfs_io_free;
215         giochannel_funcs.io_set_flags   =captive_gnomevfs_giognomevfs_io_set_flags;
216         giochannel_funcs.io_get_flags   =captive_gnomevfs_giognomevfs_io_get_flags;
217         G_UNLOCK(giochannel_funcs);
218
219         captive_new(giognomevfs);
220         g_assert(G_STRUCT_OFFSET(struct captive_gnomevfs_giognomevfs,iochannel)==0);    /* safely re-type-able */
221         g_io_channel_init(&giognomevfs->iochannel);
222         giognomevfs->iochannel.funcs=&giochannel_funcs;
223         giognomevfs->iochannel.is_seekable=TRUE;
224         giognomevfs->iochannel.is_readable=TRUE;
225         giognomevfs->iochannel.is_writeable=(rwmode!=CAPTIVE_OPTION_RWMODE_RO);
226         giognomevfs->iochannel.close_on_unref=TRUE;     /* run g_io_channel_shutdown() flush on last unref */
227         giognomevfs->gnomevfshandle=handle;
228
229         captive_giochannel_setup(&giognomevfs->iochannel);
230
231         *giognomevfsp=giognomevfs;
232         return GNOME_VFS_OK;
233 }