Postpone captive_fs_new() to the process of lufsd(8)
[captive.git] / src / client / lufs / captivefs-file.c
1 /* $Id$
2  * lufs interface module file 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 <glib/gmessages.h>
23 #include "captivefs-misc.h"
24 #include "captivefs-attr.h"
25 #include "captivefs-vfs.h"
26 #include <fcntl.h>
27
28 #include <captive/client-vfs.h>
29 #include <captive/client-file.h>
30
31 #include <lufs/fs.h>
32
33
34 /* Read a file/dir's attributes
35  * Fill all relevant data into the fattr structure.
36  * The uid/gid fields are just ownership hints hints:
37  *    != 0 => we own the file
38  *    == 0 => we don't own it
39  * The credentials structure (if applicable and saved from _init)
40  * can help determine ownership based on remote uids/gids.
41  *
42  * Notes:
43  *     If your filesysem doesn't natively support '.' or '..',
44  * don't forget to special-case them here.
45  *     It is best to assume that name is a relative path, not an
46  * absolute one.  Thus, you need to either be keeping track of the
47  * last accessed directory in readdir, or, as this code does, changing
48  * to the current directory there.
49  */
50 int captivefs_stat(struct captivefs_vfs *captivefs_vfs,const char *name,struct lufs_fattr *fattr)
51 {
52 GnomeVFSResult errvfsresult;
53 CaptiveFileObject *captive_file_object;
54 GnomeVFSFileInfo file_info;
55
56         g_return_val_if_fail(captivefs_vfs_validate(captivefs_vfs),-1);
57         g_return_val_if_fail(name!=NULL,-1);
58         g_return_val_if_fail(fattr!=NULL,-1);
59
60         if (captivefs_vfs->options.debug_messages)
61                 g_log(G_LOG_DOMAIN,G_LOG_LEVEL_DEBUG,"captivefs_stat: name=%s",name);
62
63         G_LOCK(libcaptive);
64         errvfsresult=captive_file_new_open(&captive_file_object,captivefs_vfs->captive_vfs_object,name,GNOME_VFS_OPEN_READ);
65         G_UNLOCK(libcaptive);
66         if (errvfsresult!=GNOME_VFS_OK)
67                 goto fail;
68
69         G_LOCK(libcaptive);
70         errvfsresult=captive_file_file_info_get(captive_file_object,&file_info);
71         G_UNLOCK(libcaptive);
72         if (errvfsresult!=GNOME_VFS_OK)
73                 goto fail_unref;
74
75         G_LOCK(libcaptive);
76         g_object_unref(captive_file_object);
77         G_UNLOCK(libcaptive);
78
79         if (!captivefs_GnomeVFSFileInfo_to_lufs_fattr(fattr,&file_info))
80                 return -1;
81
82         return 0;
83
84 fail_unref:
85         G_LOCK(libcaptive);
86         g_object_unref(captive_file_object);
87         G_UNLOCK(libcaptive);
88 fail:
89         return -1;
90 }
91
92
93 /* Create a file
94  */
95 int captivefs_create(struct captivefs_vfs *captivefs_vfs,const char *file,int mode)
96 {
97 GnomeVFSResult errvfsresult;
98 CaptiveFileObject *captive_file_object;
99
100         g_return_val_if_fail(captivefs_vfs_validate(captivefs_vfs),-1);
101         g_return_val_if_fail(file!=NULL,-1);
102
103         if (captivefs_vfs->options.debug_messages)
104                 g_log(G_LOG_DOMAIN,G_LOG_LEVEL_DEBUG,"captivefs_create: file=%s,mode=0x%X",file,mode);
105
106         G_LOCK(libcaptive);
107         errvfsresult=captive_file_new_create(&captive_file_object,captivefs_vfs->captive_vfs_object,file,GNOME_VFS_OPEN_WRITE,
108                         FALSE,  /* exclusive */
109                         mode);  /* perm */
110         G_UNLOCK(libcaptive);
111         if (errvfsresult!=GNOME_VFS_OK)
112                 return -1;
113
114         G_LOCK(libcaptive);
115         g_object_unref(captive_file_object);
116         G_UNLOCK(libcaptive);
117
118         return 0;
119 }
120
121
122 /* Delete a file
123  */
124 int captivefs_unlink(struct captivefs_vfs *captivefs_vfs,const char *file)
125 {
126 GnomeVFSResult errvfsresult;
127 CaptiveFileObject *captive_file_object;
128
129         g_return_val_if_fail(captivefs_vfs_validate(captivefs_vfs),-1);
130         g_return_val_if_fail(file!=NULL,-1);
131
132         if (captivefs_vfs->options.debug_messages)
133                 g_log(G_LOG_DOMAIN,G_LOG_LEVEL_DEBUG,"captivefs_unlink: file=%s",file);
134
135         G_LOCK(libcaptive);
136         errvfsresult=captive_file_new_open(&captive_file_object,captivefs_vfs->captive_vfs_object,file,GNOME_VFS_OPEN_WRITE);
137         G_UNLOCK(libcaptive);
138         if (errvfsresult!=GNOME_VFS_OK)
139                 goto fail;
140
141         G_LOCK(libcaptive);
142         errvfsresult=captive_file_remove(captive_file_object);
143         G_UNLOCK(libcaptive);
144         if (errvfsresult!=GNOME_VFS_OK)
145                 goto fail_unref;
146
147         G_LOCK(libcaptive);
148         g_object_unref(captive_file_object);
149         G_UNLOCK(libcaptive);
150
151         return 0;
152
153 fail_unref:
154         G_LOCK(libcaptive);
155         g_object_unref(captive_file_object);
156         G_UNLOCK(libcaptive);
157 fail:
158         return -1;
159 }
160
161
162 /* Rename a file/dir
163  */
164 int captivefs_rename(struct captivefs_vfs *captivefs_vfs,const char *old_name,const char *new_name)
165 {
166 GnomeVFSResult errvfsresult;
167 CaptiveFileObject *captive_file_object;
168
169         g_return_val_if_fail(captivefs_vfs_validate(captivefs_vfs),-1);
170         g_return_val_if_fail(old_name!=NULL,-1);
171         g_return_val_if_fail(new_name!=NULL,-1);
172
173         if (captivefs_vfs->options.debug_messages)
174                 g_log(G_LOG_DOMAIN,G_LOG_LEVEL_DEBUG,"captivefs_rename: old_name=%s,new_name=%s",old_name,new_name);
175
176         G_LOCK(libcaptive);
177         errvfsresult=captive_file_new_open(&captive_file_object,captivefs_vfs->captive_vfs_object,old_name,GNOME_VFS_OPEN_WRITE);
178         G_UNLOCK(libcaptive);
179         if (errvfsresult!=GNOME_VFS_OK)
180                 goto fail;
181
182         G_LOCK(libcaptive);
183         errvfsresult=captive_file_move(captive_file_object,new_name,
184                         FALSE); /* force_replace */
185         G_UNLOCK(libcaptive);
186         if (errvfsresult!=GNOME_VFS_OK)
187                 goto fail_unref;
188
189         G_LOCK(libcaptive);
190         g_object_unref(captive_file_object);
191         G_UNLOCK(libcaptive);
192
193         return 0;
194
195 fail_unref:
196         G_LOCK(libcaptive);
197         g_object_unref(captive_file_object);
198         G_UNLOCK(libcaptive);
199 fail:
200         return -1;
201 }
202
203
204 /* map: (const gchar *) -> (CaptiveFileObject *) */
205 static GHashTable *FileHandle_hash;
206
207 static void FileHandle_hash_value_destroy_func(CaptiveFileObject *captive_file_object)
208 {
209         g_return_if_fail(CAPTIVE_FILE_IS_OBJECT(captive_file_object));
210
211         g_object_unref(captive_file_object);
212 }
213
214 static void FileHandle_hash_init(void)
215 {
216         if (FileHandle_hash)
217                 return;
218         FileHandle_hash=g_hash_table_new_full(g_str_hash,g_str_equal,
219                         (GDestroyNotify)g_free, /* key_destroy_func */
220                         (GDestroyNotify)FileHandle_hash_value_destroy_func);    /* value_destroy_func */
221 }
222
223 static CaptiveFileObject *FileHandle_lookup(const char *name)
224 {
225 CaptiveFileObject *captive_file_object;
226
227         g_return_val_if_fail(name!=NULL,NULL);
228
229         FileHandle_hash_init();
230         if (!(captive_file_object=g_hash_table_lookup(FileHandle_hash,name))) {
231                 g_warning("FileHandle_lookup: FileHandle not found of: %s",name);
232                 return NULL;
233                 }
234
235         g_assert(CAPTIVE_FILE_IS_OBJECT(captive_file_object));
236
237         return captive_file_object;
238 }
239
240
241 /* Open a file
242  *
243  * Notes:
244  *     By default, LUFS has no concept of file handles.  To implement file
245  * handles, take a look at the atbl class in sshfs - it is easy to cut&paste
246  * for use, and can be easily adapted for whatever purpose you need handles
247  * for.
248  *
249  *     Unlike the POSIX open command which has both a "mode" variable and
250  * a "flags" variable, this only has a "mode" variable.  To convert to the
251  * POSIX version, ->flags=mode^O_ACCMODE and ->mode=mode&O_ACCMODE.
252  */
253 int captivefs_open(struct captivefs_vfs *captivefs_vfs,const char *file,unsigned mode)
254 {
255 CaptiveFileObject *captive_file_object;
256 GnomeVFSOpenMode gnome_vfs_open_mode;
257 GnomeVFSResult errvfsresult;
258
259         /* We may be called from the parent. */
260         g_return_val_if_fail(captivefs_vfs!=NULL,FALSE);
261         g_return_val_if_fail(file!=NULL,-1);
262
263         if (captivefs_vfs->options.debug_messages)
264                 g_log(G_LOG_DOMAIN,G_LOG_LEVEL_DEBUG,"captivefs_open: file=%s,mode=0x%X",file,mode);
265
266         if (!captivefs_vfs_validate(captivefs_vfs))
267                 return -1;
268
269         FileHandle_hash_init();
270         if ((captive_file_object=g_hash_table_lookup(FileHandle_hash,file))) {
271                 g_assert(CAPTIVE_FILE_IS_OBJECT(captive_file_object));
272                 g_warning("captivefs_open: FileHandle already exists of: %s",file);
273                 return -1;
274                 }
275
276         if (mode & (O_RDONLY|O_WRONLY|O_RDWR)) {
277                 g_warning("captivefs_open: Unrecognized 'mode' 0x%X",mode);
278                 return -1;
279                 }
280         switch (mode & (O_RDONLY|O_WRONLY|O_RDWR)) {
281                 case O_RDONLY: gnome_vfs_open_mode=GNOME_VFS_OPEN_READ;  break;
282                 case O_WRONLY: gnome_vfs_open_mode=GNOME_VFS_OPEN_WRITE; break;
283                 case O_RDWR:   gnome_vfs_open_mode=GNOME_VFS_OPEN_READ|GNOME_VFS_OPEN_WRITE; break;
284                 default:
285                         g_warning("captivefs_open: Unrecognized 'mode' 0x%X",mode);
286                         return -1;
287                 }
288
289         G_LOCK(libcaptive);
290         errvfsresult=captive_file_new_open(&captive_file_object,captivefs_vfs->captive_vfs_object,file,
291                         gnome_vfs_open_mode|GNOME_VFS_OPEN_RANDOM);
292         G_UNLOCK(libcaptive);
293         if (errvfsresult!=GNOME_VFS_OK)
294                 return -1;
295
296         g_hash_table_insert(FileHandle_hash,g_strdup(file),captive_file_object);
297
298         return 0;
299 }
300
301
302 int captivefs_release(struct captivefs_vfs *captivefs_vfs,const char *file)
303 {
304         g_return_val_if_fail(captivefs_vfs_validate(captivefs_vfs),-1);
305         g_return_val_if_fail(file!=NULL,-1);
306
307         if (captivefs_vfs->options.debug_messages)
308                 g_log(G_LOG_DOMAIN,G_LOG_LEVEL_DEBUG,"captivefs_release: file=%s",file);
309
310         FileHandle_hash_init();
311         if (!g_hash_table_remove(FileHandle_hash,file)) {
312                 g_warning("captivefs_release: FileHandle not found of: %s",file);
313                 return -1;
314                 }
315
316         return 0;
317 }
318
319
320 /* Read from a file. Changed to use the (2) routines not for efficiency,
321  * but to make it work with 64-bit offsets :-(.
322  */
323 int captivefs_read(struct captivefs_vfs *captivefs_vfs,const char *file,long long offset,unsigned long count,void *buf)
324 {
325 CaptiveFileObject *captive_file_object;
326 GnomeVFSFileSize bytes_read;
327 GnomeVFSResult errvfsresult;
328
329         g_return_val_if_fail(captivefs_vfs_validate(captivefs_vfs),-1);
330         g_return_val_if_fail(file!=NULL,-1);
331         g_return_val_if_fail(buf!=NULL || count==0,-1);
332
333         if (captivefs_vfs->options.debug_messages)
334                 g_log(G_LOG_DOMAIN,G_LOG_LEVEL_DEBUG,"captivefs_read: file=%s,offset=%" G_GINT64_FORMAT ",count=0x%lX",
335                                 file,(gint64)offset,count);
336
337         if (!(captive_file_object=FileHandle_lookup(file)))
338                 return -1;
339
340         G_LOCK(libcaptive);
341         errvfsresult=captive_file_seek(captive_file_object,GNOME_VFS_SEEK_START,offset);
342         G_UNLOCK(libcaptive);
343         if (errvfsresult!=GNOME_VFS_OK)
344                 return -1;
345
346         G_LOCK(libcaptive);
347         errvfsresult=captive_file_read(captive_file_object,buf,count,&bytes_read);
348         G_UNLOCK(libcaptive);
349         if (errvfsresult!=GNOME_VFS_OK)
350                 return -1;
351
352         if (bytes_read>INT_MAX) {
353                 g_warning("captivefs_read: Read %" G_GUINT64_FORMAT " bytes > INT_MAX=%d; dropped data",
354                                 (guint64)bytes_read,INT_MAX);
355                 bytes_read=INT_MAX;
356                 }
357
358         return bytes_read;
359 }
360
361
362 /* Write to a file
363  */
364 int captivefs_write(struct captivefs_vfs *captivefs_vfs,const char *file,long long offset,unsigned long count,const void *buf)
365 {
366 CaptiveFileObject *captive_file_object;
367 GnomeVFSFileSize bytes_written;
368 GnomeVFSResult errvfsresult;
369
370         g_return_val_if_fail(captivefs_vfs_validate(captivefs_vfs),-1);
371         g_return_val_if_fail(file!=NULL,-1);
372         g_return_val_if_fail(buf!=NULL || count==0,-1);
373
374         if (captivefs_vfs->options.debug_messages)
375                 g_log(G_LOG_DOMAIN,G_LOG_LEVEL_DEBUG,"captivefs_write: file=%s,offset=%" G_GINT64_FORMAT ",count=0x%lX",
376                                 file,(gint64)offset,count);
377
378         if (!(captive_file_object=FileHandle_lookup(file)))
379                 return -1;
380
381         G_LOCK(libcaptive);
382         errvfsresult=captive_file_seek(captive_file_object,GNOME_VFS_SEEK_START,offset);
383         G_UNLOCK(libcaptive);
384         if (errvfsresult!=GNOME_VFS_OK)
385                 return -1;
386
387         G_LOCK(libcaptive);
388         errvfsresult=captive_file_write(captive_file_object,buf,count,&bytes_written);
389         G_UNLOCK(libcaptive);
390         if (errvfsresult!=GNOME_VFS_OK)
391                 return -1;
392
393         if (bytes_written>INT_MAX) {
394                 g_warning("captivefs_written: Written %" G_GUINT64_FORMAT " bytes > INT_MAX=%d; dropped data",
395                                 (guint64)bytes_written,INT_MAX);
396                 bytes_written=INT_MAX;
397                 }
398
399         return bytes_written;
400 }
401
402
403 /* Change a file/dir's attributes
404  */
405 int captivefs_setattr(struct captivefs_vfs *captivefs_vfs,const char *file,const struct lufs_fattr *fattr)
406 {
407 GnomeVFSFileInfo file_info;
408 GnomeVFSResult errvfsresult;
409 CaptiveFileObject *captive_file_object;
410
411         g_return_val_if_fail(captivefs_vfs_validate(captivefs_vfs),-1);
412         g_return_val_if_fail(file!=NULL,-1);
413         g_return_val_if_fail(fattr!=NULL,-1);
414
415         if (captivefs_vfs->options.debug_messages)
416                 g_log(G_LOG_DOMAIN,G_LOG_LEVEL_DEBUG,"captivefs_setattr: file=%s",file);
417
418         if (!captivefs_lufs_fattr_to_GnomeVFSFileInfo(&file_info,fattr))
419                 return -1;
420
421         G_LOCK(libcaptive);
422         errvfsresult=captive_file_new_open(&captive_file_object,captivefs_vfs->captive_vfs_object,file,GNOME_VFS_OPEN_WRITE);
423         G_UNLOCK(libcaptive);
424         if (errvfsresult!=GNOME_VFS_OK)
425                 goto fail;
426
427         G_LOCK(libcaptive);
428         errvfsresult=captive_file_file_info_set(captive_file_object,&file_info,file_info.valid_fields);
429         G_UNLOCK(libcaptive);
430         if (errvfsresult!=GNOME_VFS_OK)
431                 goto fail_unref;
432
433         G_LOCK(libcaptive);
434         g_object_unref(captive_file_object);
435         G_UNLOCK(libcaptive);
436
437         return 0;
438
439 fail_unref:
440         G_LOCK(libcaptive);
441         g_object_unref(captive_file_object);
442         G_UNLOCK(libcaptive);
443 fail:
444         return -1;
445 }