2 * lufs interface module file objects implementation for libcaptive
3 * Copyright (C) 2003 Jan Kratochvil <project-captive@jankratochvil.net>
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
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.
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
22 #include <glib/gmessages.h>
23 #include "captivefs-misc.h"
24 #include "captivefs-attr.h"
25 #include "captivefs-vfs.h"
28 #include <captive/client-vfs.h>
29 #include <captive/client-file.h>
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.
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.
50 int captivefs_stat(struct captivefs_vfs *captivefs_vfs,const char *name,struct lufs_fattr *fattr)
52 GnomeVFSResult errvfsresult;
53 CaptiveFileObject *captive_file_object;
54 GnomeVFSFileInfo file_info;
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);
60 if (captivefs_vfs->options.debug_messages)
61 g_log(G_LOG_DOMAIN,G_LOG_LEVEL_DEBUG,"captivefs_stat: name=%s",name);
64 errvfsresult=captive_file_new_open(&captive_file_object,captivefs_vfs->captive_vfs_object,name,GNOME_VFS_OPEN_READ);
66 if (errvfsresult!=GNOME_VFS_OK)
70 errvfsresult=captive_file_file_info_get(captive_file_object,&file_info);
72 if (errvfsresult!=GNOME_VFS_OK)
76 g_object_unref(captive_file_object);
79 if (!captivefs_GnomeVFSFileInfo_to_lufs_fattr(fattr,&file_info))
86 g_object_unref(captive_file_object);
95 int captivefs_create(struct captivefs_vfs *captivefs_vfs,const char *file,int mode)
97 GnomeVFSResult errvfsresult;
98 CaptiveFileObject *captive_file_object;
100 g_return_val_if_fail(captivefs_vfs_validate(captivefs_vfs),-1);
101 g_return_val_if_fail(file!=NULL,-1);
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);
107 errvfsresult=captive_file_new_create(&captive_file_object,captivefs_vfs->captive_vfs_object,file,GNOME_VFS_OPEN_WRITE,
108 FALSE, /* exclusive */
110 G_UNLOCK(libcaptive);
111 if (errvfsresult!=GNOME_VFS_OK)
115 g_object_unref(captive_file_object);
116 G_UNLOCK(libcaptive);
124 int captivefs_unlink(struct captivefs_vfs *captivefs_vfs,const char *file)
126 GnomeVFSResult errvfsresult;
127 CaptiveFileObject *captive_file_object;
129 g_return_val_if_fail(captivefs_vfs_validate(captivefs_vfs),-1);
130 g_return_val_if_fail(file!=NULL,-1);
132 if (captivefs_vfs->options.debug_messages)
133 g_log(G_LOG_DOMAIN,G_LOG_LEVEL_DEBUG,"captivefs_unlink: file=%s",file);
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)
142 errvfsresult=captive_file_remove(captive_file_object);
143 G_UNLOCK(libcaptive);
144 if (errvfsresult!=GNOME_VFS_OK)
148 g_object_unref(captive_file_object);
149 G_UNLOCK(libcaptive);
155 g_object_unref(captive_file_object);
156 G_UNLOCK(libcaptive);
164 int captivefs_rename(struct captivefs_vfs *captivefs_vfs,const char *old_name,const char *new_name)
166 GnomeVFSResult errvfsresult;
167 CaptiveFileObject *captive_file_object;
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);
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);
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)
183 errvfsresult=captive_file_move(captive_file_object,new_name,
184 FALSE); /* force_replace */
185 G_UNLOCK(libcaptive);
186 if (errvfsresult!=GNOME_VFS_OK)
190 g_object_unref(captive_file_object);
191 G_UNLOCK(libcaptive);
197 g_object_unref(captive_file_object);
198 G_UNLOCK(libcaptive);
204 /* map: (const gchar *) -> (CaptiveFileObject *) */
205 static GHashTable *FileHandle_hash;
206 G_LOCK_DEFINE_STATIC(FileHandle_hash);
208 static void FileHandle_hash_value_destroy_func(CaptiveFileObject *captive_file_object)
210 g_return_if_fail(CAPTIVE_FILE_IS_OBJECT(captive_file_object));
213 g_object_unref(captive_file_object);
214 G_UNLOCK(libcaptive);
217 static void FileHandle_hash_init(void)
219 G_LOCK(FileHandle_hash);
220 if (!FileHandle_hash) {
221 FileHandle_hash=g_hash_table_new_full(g_str_hash,g_str_equal,
222 (GDestroyNotify)g_free, /* key_destroy_func */
223 (GDestroyNotify)FileHandle_hash_value_destroy_func); /* value_destroy_func */
225 G_UNLOCK(FileHandle_hash);
228 /* FIXME: g_object_ref() the resulting 'CaptiveFileObject'.
229 * Currently we assume open/ops/release is done in single thread.
231 static CaptiveFileObject *FileHandle_lookup(const char *name)
233 CaptiveFileObject *captive_file_object;
235 g_return_val_if_fail(name!=NULL,NULL);
237 FileHandle_hash_init();
238 G_LOCK(FileHandle_hash);
239 captive_file_object=g_hash_table_lookup(FileHandle_hash,name);
240 G_UNLOCK(FileHandle_hash);
242 if (!captive_file_object) {
243 g_warning("FileHandle_lookup: FileHandle not found of: %s",name);
247 g_assert(CAPTIVE_FILE_IS_OBJECT(captive_file_object));
249 return captive_file_object;
256 * By default, LUFS has no concept of file handles. To implement file
257 * handles, take a look at the atbl class in sshfs - it is easy to cut&paste
258 * for use, and can be easily adapted for whatever purpose you need handles
261 * Unlike the POSIX open command which has both a "mode" variable and
262 * a "flags" variable, this only has a "mode" variable. To convert to the
263 * POSIX version, ->flags=mode^O_ACCMODE and ->mode=mode&O_ACCMODE.
265 int captivefs_open(struct captivefs_vfs *captivefs_vfs,const char *file,unsigned mode)
267 CaptiveFileObject *captive_file_object;
268 GnomeVFSOpenMode gnome_vfs_open_mode;
269 GnomeVFSResult errvfsresult;
271 /* We may be called from the parent. */
272 g_return_val_if_fail(captivefs_vfs!=NULL,FALSE);
273 g_return_val_if_fail(file!=NULL,-1);
275 if (captivefs_vfs->options.debug_messages)
276 g_log(G_LOG_DOMAIN,G_LOG_LEVEL_DEBUG,"captivefs_open: file=%s,mode=0x%X",file,mode);
278 if (!captivefs_vfs_validate(captivefs_vfs))
281 FileHandle_hash_init();
282 G_LOCK(FileHandle_hash);
283 captive_file_object=g_hash_table_lookup(FileHandle_hash,file);
284 G_UNLOCK(FileHandle_hash);
285 if (captive_file_object) {
286 g_assert(CAPTIVE_FILE_IS_OBJECT(captive_file_object));
287 g_warning("captivefs_open: FileHandle already exists of: %s",file);
291 if (mode & ~(O_RDONLY|O_WRONLY|O_RDWR)) {
292 g_warning("captivefs_open: Unrecognized 'mode' 0x%X",mode);
295 switch (mode & (O_RDONLY|O_WRONLY|O_RDWR)) {
296 case O_RDONLY: gnome_vfs_open_mode=GNOME_VFS_OPEN_READ; break;
297 case O_WRONLY: gnome_vfs_open_mode=GNOME_VFS_OPEN_WRITE; break;
298 case O_RDWR: gnome_vfs_open_mode=GNOME_VFS_OPEN_READ|GNOME_VFS_OPEN_WRITE; break;
300 g_warning("captivefs_open: Unrecognized 'mode' 0x%X",mode);
305 errvfsresult=captive_file_new_open(&captive_file_object,captivefs_vfs->captive_vfs_object,file,
306 gnome_vfs_open_mode|GNOME_VFS_OPEN_RANDOM);
307 G_UNLOCK(libcaptive);
308 if (errvfsresult!=GNOME_VFS_OK)
311 g_hash_table_insert(FileHandle_hash,g_strdup(file),captive_file_object);
317 int captivefs_release(struct captivefs_vfs *captivefs_vfs,const char *file)
321 g_return_val_if_fail(captivefs_vfs_validate(captivefs_vfs),-1);
322 g_return_val_if_fail(file!=NULL,-1);
324 if (captivefs_vfs->options.debug_messages)
325 g_log(G_LOG_DOMAIN,G_LOG_LEVEL_DEBUG,"captivefs_release: file=%s",file);
327 FileHandle_hash_init();
328 G_LOCK(FileHandle_hash);
329 errbool=g_hash_table_remove(FileHandle_hash,file);
330 G_UNLOCK(FileHandle_hash);
333 g_warning("captivefs_release: FileHandle not found of: %s",file);
341 /* Read from a file. Changed to use the (2) routines not for efficiency,
342 * but to make it work with 64-bit offsets :-(.
344 int captivefs_read(struct captivefs_vfs *captivefs_vfs,const char *file,long long offset,unsigned long count,void *buf)
346 CaptiveFileObject *captive_file_object;
347 GnomeVFSFileSize bytes_read;
348 GnomeVFSResult errvfsresult;
350 g_return_val_if_fail(captivefs_vfs_validate(captivefs_vfs),-1);
351 g_return_val_if_fail(file!=NULL,-1);
352 g_return_val_if_fail(buf!=NULL || count==0,-1);
354 if (captivefs_vfs->options.debug_messages)
355 g_log(G_LOG_DOMAIN,G_LOG_LEVEL_DEBUG,"captivefs_read: file=%s,offset=%" G_GINT64_FORMAT ",count=0x%lX",
356 file,(gint64)offset,count);
358 if (!(captive_file_object=FileHandle_lookup(file)))
362 errvfsresult=captive_file_seek(captive_file_object,GNOME_VFS_SEEK_START,offset);
363 G_UNLOCK(libcaptive);
364 if (errvfsresult!=GNOME_VFS_OK)
368 errvfsresult=captive_file_read(captive_file_object,buf,count,&bytes_read);
369 G_UNLOCK(libcaptive);
370 if (errvfsresult!=GNOME_VFS_OK)
373 if (bytes_read>INT_MAX) {
374 g_warning("captivefs_read: Read %" G_GUINT64_FORMAT " bytes > INT_MAX=%d; dropped data",
375 (guint64)bytes_read,INT_MAX);
385 int captivefs_write(struct captivefs_vfs *captivefs_vfs,const char *file,long long offset,unsigned long count,const void *buf)
387 CaptiveFileObject *captive_file_object;
388 GnomeVFSFileSize bytes_written;
389 GnomeVFSResult errvfsresult;
391 g_return_val_if_fail(captivefs_vfs_validate(captivefs_vfs),-1);
392 g_return_val_if_fail(file!=NULL,-1);
393 g_return_val_if_fail(buf!=NULL || count==0,-1);
395 if (captivefs_vfs->options.debug_messages)
396 g_log(G_LOG_DOMAIN,G_LOG_LEVEL_DEBUG,"captivefs_write: file=%s,offset=%" G_GINT64_FORMAT ",count=0x%lX",
397 file,(gint64)offset,count);
399 if (!(captive_file_object=FileHandle_lookup(file)))
403 errvfsresult=captive_file_seek(captive_file_object,GNOME_VFS_SEEK_START,offset);
404 G_UNLOCK(libcaptive);
405 if (errvfsresult!=GNOME_VFS_OK)
409 errvfsresult=captive_file_write(captive_file_object,buf,count,&bytes_written);
410 G_UNLOCK(libcaptive);
411 if (errvfsresult!=GNOME_VFS_OK)
414 if (bytes_written>INT_MAX) {
415 g_warning("captivefs_written: Written %" G_GUINT64_FORMAT " bytes > INT_MAX=%d; dropped data",
416 (guint64)bytes_written,INT_MAX);
417 bytes_written=INT_MAX;
420 return bytes_written;
424 /* Change a file/dir's attributes
426 int captivefs_setattr(struct captivefs_vfs *captivefs_vfs,const char *file,const struct lufs_fattr *fattr)
428 GnomeVFSFileInfo file_info;
429 GnomeVFSResult errvfsresult;
430 CaptiveFileObject *captive_file_object;
432 g_return_val_if_fail(captivefs_vfs_validate(captivefs_vfs),-1);
433 g_return_val_if_fail(file!=NULL,-1);
434 g_return_val_if_fail(fattr!=NULL,-1);
436 if (captivefs_vfs->options.debug_messages)
437 g_log(G_LOG_DOMAIN,G_LOG_LEVEL_DEBUG,"captivefs_setattr: file=%s",file);
439 if (!captivefs_lufs_fattr_to_GnomeVFSFileInfo(&file_info,fattr))
443 errvfsresult=captive_file_new_open(&captive_file_object,captivefs_vfs->captive_vfs_object,file,GNOME_VFS_OPEN_WRITE);
444 G_UNLOCK(libcaptive);
445 if (errvfsresult!=GNOME_VFS_OK)
449 errvfsresult=captive_file_file_info_set(captive_file_object,&file_info,
451 | 0 /* 'GNOME_VFS_SET_FILE_INFO_NAME' is never set */
452 | (!(file_info.valid_fields&GNOME_VFS_FILE_INFO_FIELDS_PERMISSIONS) ? 0 : GNOME_VFS_SET_FILE_INFO_PERMISSIONS)
453 | 0 /* 'GNOME_VFS_SET_FILE_INFO_OWNER' is never set */
454 | (!(file_info.valid_fields&(0
455 | GNOME_VFS_FILE_INFO_FIELDS_ATIME
456 | GNOME_VFS_FILE_INFO_FIELDS_MTIME
457 | GNOME_VFS_FILE_INFO_FIELDS_CTIME))
458 ? 0 : GNOME_VFS_SET_FILE_INFO_TIME));
459 G_UNLOCK(libcaptive);
460 if (errvfsresult!=GNOME_VFS_OK)
464 g_object_unref(captive_file_object);
465 G_UNLOCK(libcaptive);
471 g_object_unref(captive_file_object);
472 G_UNLOCK(libcaptive);