Implemented '--blind' write mode
[captive.git] / src / client / libcaptive-gnomevfs / giognomevfs.c
1 /* $Id$
2  * glib GIOChannel interface over gnome-vfs GnomeVFSURI for libcaptive
3  * Copyright (C) 2002 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 "captive/client.h"
27 #include "gnome-vfs-module.h"
28
29
30 /* FIXME: fill 'err' */
31
32 struct captive_gnomevfs_giognomevfs {
33         GIOChannel iochannel;
34         GnomeVFSHandle *gnomevfshandle;
35         };
36
37 G_LOCK_DEFINE_STATIC(giochannel_funcs);
38 static GIOFuncs giochannel_funcs;
39
40
41 static gboolean validate_giognomevfs(struct captive_gnomevfs_giognomevfs *giognomevfs)
42 {
43         g_return_val_if_fail(giognomevfs!=NULL,FALSE);
44         g_return_val_if_fail(giognomevfs->gnomevfshandle!=NULL,FALSE);
45
46         return TRUE;
47 }
48
49
50 static GIOStatus captive_gnomevfs_giognomevfs_io_read
51                 (GIOChannel *channel,gchar *buf,gsize count,gsize *bytes_read,GError **err)
52 {
53 struct captive_gnomevfs_giognomevfs *giognomevfs=(struct captive_gnomevfs_giognomevfs *)channel;
54 GnomeVFSResult errvfsresult;
55 GnomeVFSFileSize bytes_read_local;
56
57         g_return_val_if_fail(validate_giognomevfs(giognomevfs),G_IO_STATUS_ERROR);
58         g_return_val_if_fail(buf!=NULL,G_IO_STATUS_ERROR);
59         g_return_val_if_fail(bytes_read!=NULL,G_IO_STATUS_ERROR);
60
61         errvfsresult=gnome_vfs_read(
62                         giognomevfs->gnomevfshandle,    /* handle */
63                         buf,    /* buffer */
64                         count,  /* bytes */
65                         &bytes_read_local);     /* bytes_read */
66         g_return_val_if_fail((errvfsresult==GNOME_VFS_OK || errvfsresult==GNOME_VFS_ERROR_EOF),G_IO_STATUS_ERROR);
67
68         *bytes_read=bytes_read_local;
69         return (errvfsresult==GNOME_VFS_ERROR_EOF ? G_IO_STATUS_EOF : G_IO_STATUS_NORMAL);
70 }
71
72
73 static GIOStatus captive_gnomevfs_giognomevfs_io_write
74                 (GIOChannel *channel,const gchar *buf,gsize count,gsize *bytes_written,GError **err)
75 {
76 struct captive_gnomevfs_giognomevfs *giognomevfs=(struct captive_gnomevfs_giognomevfs *)channel;
77 GnomeVFSResult errvfsresult;
78 GnomeVFSFileSize bytes_written_local;
79
80         g_return_val_if_fail(validate_giognomevfs(giognomevfs),G_IO_STATUS_ERROR);
81         g_return_val_if_fail(buf!=NULL,G_IO_STATUS_ERROR);
82         g_return_val_if_fail(bytes_written!=NULL,G_IO_STATUS_ERROR);
83
84         errvfsresult=gnome_vfs_write(
85                         giognomevfs->gnomevfshandle,    /* handle */
86                         buf,    /* buffer */
87                         count,  /* bytes */
88                         &bytes_written_local);  /* bytes_written */
89         g_return_val_if_fail(errvfsresult==GNOME_VFS_OK,G_IO_STATUS_ERROR);
90
91         *bytes_written=bytes_written_local;
92         return G_IO_STATUS_NORMAL;
93 }
94
95
96 static GIOStatus captive_gnomevfs_giognomevfs_io_seek(GIOChannel *channel,gint64 offset,GSeekType type,GError **err)
97 {
98 struct captive_gnomevfs_giognomevfs *giognomevfs=(struct captive_gnomevfs_giognomevfs *)channel;
99 GnomeVFSSeekPosition whence;
100 GnomeVFSResult errvfsresult;
101
102         g_return_val_if_fail(validate_giognomevfs(giognomevfs),G_IO_STATUS_ERROR);
103
104         switch (type) {
105                 case G_SEEK_CUR: whence=GNOME_VFS_SEEK_CURRENT; break;
106                 case G_SEEK_SET: whence=GNOME_VFS_SEEK_START;   break;
107                 case G_SEEK_END: whence=GNOME_VFS_SEEK_END;     break;
108                 default: g_return_val_if_reached(G_IO_STATUS_ERROR);
109                 }
110         errvfsresult=gnome_vfs_seek(giognomevfs->gnomevfshandle,whence,offset);
111         g_return_val_if_fail(errvfsresult==GNOME_VFS_OK,G_IO_STATUS_ERROR);
112
113         return G_IO_STATUS_NORMAL;
114 }
115
116
117 static GIOStatus captive_gnomevfs_giognomevfs_io_close(GIOChannel *channel,GError **err)
118 {
119 struct captive_gnomevfs_giognomevfs *giognomevfs=(struct captive_gnomevfs_giognomevfs *)channel;
120 gboolean errbool;
121
122         g_return_val_if_fail(validate_giognomevfs(giognomevfs),G_IO_STATUS_ERROR);
123
124         g_assert(captive_image_iochannel!=NULL);
125         G_LOCK(libcaptive);
126         errbool=captive_shutdown();
127         G_UNLOCK(libcaptive);
128         g_assert(errbool==TRUE);
129         g_assert(captive_image_iochannel==NULL);
130
131         gnome_vfs_close(giognomevfs->gnomevfshandle);
132
133         return G_IO_STATUS_NORMAL;
134 }
135
136
137 static GSource* captive_gnomevfs_giognomevfs_io_create_watch(GIOChannel *channel,GIOCondition condition)
138 {
139 struct captive_gnomevfs_giognomevfs *giognomevfs=(struct captive_gnomevfs_giognomevfs *)channel;
140
141         g_return_val_if_fail(validate_giognomevfs(giognomevfs),NULL);
142
143         g_return_val_if_reached(NULL);  /* FIXME: NOT IMPLEMENTED YET */
144 }
145
146
147 static void captive_gnomevfs_giognomevfs_io_free(GIOChannel *channel)
148 {
149 struct captive_gnomevfs_giognomevfs *giognomevfs=(struct captive_gnomevfs_giognomevfs *)channel;
150
151         g_return_if_fail(validate_giognomevfs(giognomevfs));
152
153         g_free(giognomevfs);
154 }
155
156
157 static GIOStatus captive_gnomevfs_giognomevfs_io_set_flags(GIOChannel *channel,GIOFlags flags,GError **err)
158 {
159 struct captive_gnomevfs_giognomevfs *giognomevfs=(struct captive_gnomevfs_giognomevfs *)channel;
160
161         g_return_val_if_fail(validate_giognomevfs(giognomevfs),G_IO_STATUS_ERROR);
162
163         /* no G_IO_FLAG_APPEND and no G_IO_FLAG_NONBLOCK */
164         g_return_val_if_fail((flags&G_IO_FLAG_SET_MASK)==0,G_IO_STATUS_ERROR);
165
166         return G_IO_STATUS_NORMAL;
167 }
168
169
170 static GIOFlags captive_gnomevfs_giognomevfs_io_get_flags(GIOChannel *channel)
171 {
172 struct captive_gnomevfs_giognomevfs *giognomevfs=(struct captive_gnomevfs_giognomevfs *)channel;
173
174         g_return_val_if_fail(validate_giognomevfs(giognomevfs),0);
175
176         return 0;       /* | !G_IO_FLAG_APPEND | !G_IO_FLAG_NONBLOCK */
177 }
178
179
180 GnomeVFSResult captive_gnomevfs_giognomevfs_new(struct captive_gnomevfs_giognomevfs **giognomevfsp,
181                 const gchar *captive_args,GnomeVFSURI *uri)
182 {
183 GnomeVFSHandle *handle;
184 struct captive_gnomevfs_giognomevfs *giognomevfs;
185 GnomeVFSResult errvfsresult;
186 gboolean errbool;
187
188         g_return_val_if_fail(giognomevfsp!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
189         g_return_val_if_fail(uri!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
190
191         /* Parse 'captive_args' to get at least 'captive_option_rwmode' option value (phase 1). */
192         G_LOCK(libcaptive);
193         errbool=captive_init(
194                         captive_args,   /* captive_args */
195                         NULL);  /* image_iochannel */
196         G_UNLOCK(libcaptive);
197         g_assert(errbool==FALSE);
198
199         errvfsresult=gnome_vfs_open_uri(&handle,uri,
200                         0       /* open_mode */
201                                         | GNOME_VFS_OPEN_RANDOM /* mandatory; otherwise we will get truncation if GNOME_VFS_OPEN_WRITE */
202                                         | GNOME_VFS_OPEN_READ
203                                         | (captive_option_rwmode==CAPTIVE_OPTION_RWMODE_RW ? GNOME_VFS_OPEN_WRITE : 0));
204         g_return_val_if_fail(errvfsresult==GNOME_VFS_OK,errvfsresult);
205
206         G_LOCK(giochannel_funcs);
207         giochannel_funcs.io_read        =captive_gnomevfs_giognomevfs_io_read;
208         giochannel_funcs.io_write       =captive_gnomevfs_giognomevfs_io_write;
209         giochannel_funcs.io_seek        =captive_gnomevfs_giognomevfs_io_seek;
210         giochannel_funcs.io_close       =captive_gnomevfs_giognomevfs_io_close;
211         giochannel_funcs.io_create_watch=captive_gnomevfs_giognomevfs_io_create_watch;
212         giochannel_funcs.io_free        =captive_gnomevfs_giognomevfs_io_free;
213         giochannel_funcs.io_set_flags   =captive_gnomevfs_giognomevfs_io_set_flags;
214         giochannel_funcs.io_get_flags   =captive_gnomevfs_giognomevfs_io_get_flags;
215         G_UNLOCK(giochannel_funcs);
216
217         captive_new(giognomevfs);
218         g_assert(G_STRUCT_OFFSET(struct captive_gnomevfs_giognomevfs,iochannel)==0);    /* safely re-type-able */
219         g_io_channel_init(&giognomevfs->iochannel);
220         giognomevfs->iochannel.funcs=&giochannel_funcs;
221         giognomevfs->iochannel.is_seekable=TRUE;
222         giognomevfs->iochannel.is_readable=TRUE;
223         giognomevfs->iochannel.is_writeable=(captive_option_rwmode==CAPTIVE_OPTION_RWMODE_RW);
224         giognomevfs->iochannel.close_on_unref=TRUE;     /* run g_io_channel_shutdown() flush on last unref */
225         giognomevfs->gnomevfshandle=handle;
226
227         /* Initialization for the real this time (phase 2). */
228         g_assert(captive_image_iochannel==NULL);
229         G_LOCK(libcaptive);
230         errbool=captive_init(
231                         NULL,   /* captive_args */
232                         (GIOChannel *)giognomevfs);     /* image_iochannel */
233         G_UNLOCK(libcaptive);
234         g_assert(errbool==TRUE);
235         /* It may not be 'giognomevfs' as it may be wrapped by 'captive_giochannel_blind'. */
236         g_assert(captive_image_iochannel!=NULL);
237
238         *giognomevfsp=giognomevfs;
239         return GNOME_VFS_OK;
240 }