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