90c7b3acdc4771b63d04c856245d97ff77858086
[captive.git] / src / client / lufs / captivefs-vfs.c
1 /* $Id$
2  * lufs interface module vfs objects implementation for libcaptive
3  * Copyright (C) 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 "captivefs-vfs.h"      /* self */
23 #include <glib/gmessages.h>
24 #include "captivefs-misc.h"
25 #include <unistd.h>
26 #include <locale.h>
27
28 #include <captive/client-vfs.h>
29 #include <captive/options.h>
30 #include <captive/macros.h>
31
32 #include <lufs/fs.h>
33 #include <lufs/proto.h>
34
35
36 gboolean captivefs_vfs_validate(struct captivefs_vfs *captivefs_vfs)
37 {
38         g_return_val_if_fail(captivefs_vfs!=NULL,FALSE);
39
40         G_LOCK(libcaptive);
41         g_assert(captivefs_vfs->inits>0);
42         g_assert(captivefs_vfs->mounts>=0);
43         g_assert(captivefs_vfs->mounts<=captivefs_vfs->inits);
44         if (!captivefs_vfs->captive_vfs_object) {
45 GnomeVFSResult errvfsresult;
46
47                 if (captivefs_vfs->parent_pid==getpid()) {
48                         G_UNLOCK(libcaptive);
49                         return FALSE;
50                         }
51
52                 errvfsresult=captive_vfs_new(&captivefs_vfs->captive_vfs_object,&captivefs_vfs->options);
53
54                 if (errvfsresult!=GNOME_VFS_OK) {
55                         G_UNLOCK(libcaptive);
56                         g_return_val_if_reached(FALSE);
57                         }
58                 }
59         if (!CAPTIVE_VFS_IS_OBJECT(captivefs_vfs->captive_vfs_object)) {
60                 G_UNLOCK(libcaptive);
61                 g_return_val_if_reached(FALSE);
62                 }
63         G_UNLOCK(libcaptive);
64
65         return TRUE;
66 }
67
68
69 /* Initialization
70  * Here we allocate a structure to hold all the file system local info 
71  * (localfs_local). This structure will then be passed as a parameter to 
72  * the other functions.
73  * global_ctx holds info about another structure that can be shared between all
74  * instances of the filesystem. If the pointer is NULL, then this is the
75  * first instance and the structure should be allocated.
76  * ! You must implement  locking/usage-count/deallocation logic when using
77  *   a global context. (locking is omited here)
78  * ! Most filesystems don't need a global context so you can safely ignore the
79  *   global_ctx parameter.  
80  */
81 struct captivefs_vfs *captivefs_init
82                 (struct list_head *cfg,struct dir_cache *cache,const struct credentials *cred,struct captivefs_vfs **global_ctx)
83 {
84 struct captivefs_vfs *captivefs_vfs;
85 const gchar *cgs;
86 gchar *gs,*captive_options_string;
87
88         g_return_val_if_fail(global_ctx!=NULL,NULL);
89
90         /* Do not: g_log(G_LOG_DOMAIN,G_LOG_LEVEL_DEBUG,"captivefs_init");
91          * as we do not yet have 'VFS_DEBUG_MESSAGES(captive_vfs_object)' set.
92          * Generally we make all g_log() conditional here as we do not want to mess
93          * with overriden GLog handlers of libcaptive itself.
94          */
95
96         G_LOCK(libcaptive);
97         if ((captivefs_vfs=*global_ctx)) {
98                 g_assert(captivefs_vfs->inits>0);
99                 /* We do not support multiple LUFS threads if they could not be cross-locked. */
100                 g_return_val_if_fail(g_thread_supported(),NULL);
101                 captivefs_vfs->inits++;
102                 G_UNLOCK(libcaptive);
103                 if (captivefs_vfs->options.debug_messages)
104                         g_log(G_LOG_DOMAIN,G_LOG_LEVEL_DEBUG,"captivefs_init");
105                 return captivefs_vfs;
106                 }
107         G_UNLOCK(libcaptive);
108
109         /* Initialize i18n for proper nl_langinfo(CODESET) for _g_locale_charset_raw() for g_filename_from_utf8(). */
110         setlocale(LC_ALL,"");
111
112         if (!g_thread_supported())
113                 g_thread_init(NULL);    /* g_thread_init() fails on second initialization */
114
115         /* Initialize GObject subsystem of GLib. */
116         g_type_init();
117
118         captive_new(captivefs_vfs);
119         captivefs_vfs->captive_vfs_object=NULL;
120         captivefs_vfs->private=FALSE;
121         captivefs_vfs->parent_pid=getpid();
122         captivefs_vfs->global_ctx=global_ctx;
123         *global_ctx=captivefs_vfs;
124         captivefs_vfs->inits=1;
125         captivefs_vfs->mounts=0;
126
127         captive_options_init(&captivefs_vfs->options);
128
129         if ((cgs=lu_opt_getchar(cfg,"MOUNT","captive_options"))) {
130                 captive_options_string=(/* de-const */gchar *)captive_strdup_alloca(cgs);
131                 /* Convert ';' to ' ' to prevent its parsing by LUFS to keep its ordering
132                  * to let the options be overridable by user (such as 'ro').
133                  */
134                 for (gs=captive_options_string;(gs=strchr(gs,';'));gs++)
135                         *gs=' ';
136                 if (!captive_options_parse(
137                                 &captivefs_vfs->options,        /* options */
138                                 captive_options_string))        /* captive_args */
139                         goto fail_free_options;
140                 }
141         if (lu_opt_getchar(cfg,"MOUNT","private"))
142                 captivefs_vfs->private=TRUE;
143
144         if (captivefs_vfs->options.debug_messages)
145                 g_log(G_LOG_DOMAIN,G_LOG_LEVEL_DEBUG,"captivefs_init");
146
147         /* image_iochannel */
148         if ((cgs=lu_opt_getchar(cfg,"MOUNT","image"))) {
149                 g_assert(captivefs_vfs->options.image_iochannel==NULL);
150                 if (!(captivefs_vfs->options.image_iochannel=g_io_channel_new_file(
151                                 cgs,    /* filename */
152                                 (captivefs_vfs->options.rwmode==CAPTIVE_OPTION_RWMODE_RW ? "r+" : "r"), /* mode */
153                                 NULL))) {       /* error */
154                         g_warning(_("%s: image_iochannel open failed"),"captivefs_init");
155                         goto fail_free_options;
156                         }
157                 }
158
159         return captivefs_vfs;
160
161 fail_free_options:
162         captive_options_free(&captivefs_vfs->options);
163 /* fail: */
164         return NULL;
165 }
166
167
168 /* Cleanup
169  * Check the global context count and free it if necessary.
170  * Deallocate memory and free all resources.
171  */
172 void captivefs_free(struct captivefs_vfs *captivefs_vfs)
173 {
174         g_return_if_fail(captivefs_vfs_validate(captivefs_vfs));
175         g_return_if_fail(captivefs_vfs->inits>0);
176
177         if (captivefs_vfs->options.debug_messages)
178                 g_log(G_LOG_DOMAIN,G_LOG_LEVEL_DEBUG,"captivefs_free");
179         
180         if (--captivefs_vfs->inits>0) {
181                 g_assert(captivefs_vfs_validate(captivefs_vfs));
182                 return;
183                 }
184         g_assert(captivefs_vfs->mounts==0);
185         G_LOCK(libcaptive);
186         *captivefs_vfs->global_ctx=NULL;
187         G_UNLOCK(libcaptive);
188
189         g_assert(G_OBJECT(captivefs_vfs->captive_vfs_object)->ref_count==1);
190
191         G_LOCK(libcaptive);
192         g_object_unref(captivefs_vfs->captive_vfs_object);
193         G_UNLOCK(libcaptive);
194
195         /* Do not: g_io_channel_unref(captivefs_vfs->options.image_iochannel);
196          * as it will be unreferenced by captive_options_free().
197          */
198         captive_options_free(&captivefs_vfs->options);
199         g_free(captivefs_vfs);
200 }
201
202
203 /* Mount the file system.
204  * Called when a mount operation is performed.
205  * Initialize specific connections, login, etc.
206  *
207  * Notes:
208  *     By default, LUFS may attempt multiple connections at once.  If your
209  * filesystem doesn't support this, you need to specificy -c 1 on the
210  * lufsmount command line or connections=1 in the mount options.
211  *     See ftpfs for an example of how to read configuration options
212  * from a configuration file if you want to, for example, be able to set
213  * default values.
214  */
215 int captivefs_mount(struct captivefs_vfs *captivefs_vfs)
216 {
217         /* We may be called from the parent. */
218         g_return_val_if_fail(captivefs_vfs!=NULL,FALSE);
219         captivefs_vfs_validate(captivefs_vfs);  /* It may return FALSE. */
220
221         if (captivefs_vfs->options.debug_messages)
222                 g_log(G_LOG_DOMAIN,G_LOG_LEVEL_DEBUG,"captivefs_mount");
223
224         captivefs_vfs->mounts++;
225
226         captivefs_vfs_validate(captivefs_vfs);  /* It may return FALSE. */
227
228         return 1;       /* NEVER return 0 */
229 }
230
231
232 /* Unmount the  file system
233  * Called when the file system is unmounted.
234  */
235 void captivefs_umount(struct captivefs_vfs *captivefs_vfs)
236 {
237         g_return_if_fail(captivefs_vfs_validate(captivefs_vfs));
238         g_return_if_fail(captivefs_vfs->mounts>0);
239
240         if (captivefs_vfs->options.debug_messages)
241                 g_log(G_LOG_DOMAIN,G_LOG_LEVEL_DEBUG,"captivefs_umount");
242
243         captivefs_vfs->mounts--;
244
245         g_assert(captivefs_vfs_validate(captivefs_vfs));
246 }
247
248
249 #ifdef HAVE_STRUCT_LUFS_SBATTR
250 int captivefs_statfs(struct captivefs_vfs *captivefs_vfs,struct lufs_sbattr *sbattr)
251 {
252 CaptiveVfsVolumeInfo captive_volume_info;
253 GnomeVFSResult errvfsresult;
254
255         g_return_val_if_fail(captivefs_vfs_validate(captivefs_vfs),-1);
256         g_return_val_if_fail(sbattr!=NULL,-1);
257
258         if (captivefs_vfs->options.debug_messages)
259                 g_log(G_LOG_DOMAIN,G_LOG_LEVEL_DEBUG,"captivefs_statfs");
260
261         G_LOCK(libcaptive);
262         errvfsresult=captive_vfs_volume_info_get(captivefs_vfs->captive_vfs_object,&captive_volume_info);
263         G_UNLOCK(libcaptive);
264         if (errvfsresult!=GNOME_VFS_OK)
265                 return -1;
266
267         sbattr->sb_bytes=captive_volume_info.bytes;
268         sbattr->sb_bytes_free=captive_volume_info.bytes_free;
269         sbattr->sb_bytes_available=captive_volume_info.bytes_available;
270         /* 'sbattr->sb_files' not known - left unchanged. */
271         /* 'sbattr->sb_ffree' not known - left unchanged. */
272
273         return 0;
274 }
275 #endif /* HAVE_STRUCT_LUFS_SBATTR */