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