Bootstrap.
[ntfsprogs-gnomevfs.git] / src / gnome-vfs-method.c
1 /* $Id$
2  * gnome-vfs init/shutdown implementation of interface to libntfs
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 #undef FALSE
23 #undef TRUE
24 #include <ntfs/types.h> /* for 'FALSE'/'TRUE' libntfs definition */
25 #define FALSE FALSE
26 #define TRUE TRUE
27
28 #include "gnome-vfs-method.h"   /* self */
29 #include <libgnomevfs/gnome-vfs-method.h>
30 #include <glib/gmessages.h>
31 #include "gnome-vfs-module.h"
32 #include <glib/ghash.h>
33 #include <string.h>
34
35 #include <ntfs/volume.h>
36 #include <ntfs/dir.h>
37
38
39 static GnomeVFSMethod GnomeVFSMethod_static;
40 G_LOCK_DEFINE_STATIC(GnomeVFSMethod_static);
41
42
43 /* map: (gchar *)method_name -> (struct method_name_info *) */
44 static GHashTable *method_name_hash;
45 G_LOCK_DEFINE_STATIC(method_name_hash);
46
47 struct method_name_info {
48         gchar *args;
49         };
50
51 static void method_name_hash_key_destroy_func(gchar *key)
52 {
53         g_return_if_fail(key!=NULL);
54
55         g_free(key);
56 }
57
58 static void method_name_hash_value_destroy_func(struct method_name_info *value)
59 {
60         g_return_if_fail(value!=NULL);
61
62         g_free(value->args);
63         g_free(value);
64 }
65
66 static void method_name_hash_init(void)
67 {
68         G_LOCK(method_name_hash);
69         if (!method_name_hash) {
70                 method_name_hash=g_hash_table_new_full(
71                                 g_str_hash,     /* hash_func */
72                                 g_str_equal,    /* key_equal_func */
73                                 (GDestroyNotify)method_name_hash_key_destroy_func,      /* key_destroy_func */
74                                 (GDestroyNotify)method_name_hash_value_destroy_func);   /* value_destroy_func */
75                 }
76         G_UNLOCK(method_name_hash);
77 }
78
79
80 /* map: (gchar *)uri_parent_string "method_name:uri_parent" -> (ntfs_volume *) */
81 static GHashTable *uri_parent_string_hash;
82 G_LOCK_DEFINE_STATIC(uri_parent_string_hash);
83
84 static void uri_parent_string_hash_key_destroy_func(gchar *key)
85 {
86         g_return_if_fail(key!=NULL);
87
88         g_free(key);
89 }
90
91 static void uri_parent_string_hash_value_destroy_func(ntfs_volume *value)
92 {
93         g_return_if_fail(value!=NULL);
94
95         ntfs_umount(    /* errors ignored */
96                         value,  /* vol */
97                         TRUE);  /* force; possibly loose modifications */
98 }
99
100 static void uri_parent_string_hash_init(void)
101 {
102         G_LOCK(uri_parent_string_hash);
103         if (!uri_parent_string_hash) {
104                 uri_parent_string_hash=g_hash_table_new_full(
105                                 g_str_hash,     /* hash_func */
106                                 g_str_equal,    /* key_equal_func */
107                                 (GDestroyNotify)uri_parent_string_hash_key_destroy_func,        /* key_destroy_func */
108                                 (GDestroyNotify)uri_parent_string_hash_value_destroy_func);     /* value_destroy_func */
109                 }
110         G_UNLOCK(uri_parent_string_hash);
111 }
112
113
114 static GnomeVFSResult libntfs_gnomevfs_uri_parent_init(ntfs_volume **volume_return,GnomeVFSURI *uri)
115 {
116 gchar *uri_parent_string;
117 gchar *uri_parent_string_parent;
118 ntfs_volume *volume;
119
120         g_return_val_if_fail(uri!=NULL,GNOME_VFS_ERROR_INVALID_URI);
121         g_return_val_if_fail(volume_return!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
122
123         uri_parent_string_hash_init();
124
125         if (!uri->parent)
126                 return GNOME_VFS_ERROR_INVALID_URI;
127         if (!uri->text) /* not needed here but we don't permit non-specific fs-image reference */
128                 return GNOME_VFS_ERROR_INVALID_URI;
129         uri_parent_string_parent=gnome_vfs_uri_to_string(uri->parent,GNOME_VFS_URI_HIDE_NONE);
130         g_assert(uri_parent_string_parent!=NULL);
131
132         uri_parent_string=g_strdup_printf("%s:%s",uri->method_string,uri_parent_string_parent);
133         g_assert(uri_parent_string!=NULL);
134
135         G_LOCK(uri_parent_string_hash);
136         volume=g_hash_table_lookup(uri_parent_string_hash,uri_parent_string);
137         G_UNLOCK(uri_parent_string_hash);
138         if (!volume) {
139 struct method_name_info *method_name_info;
140
141                 G_LOCK(method_name_hash);
142                 method_name_info=g_hash_table_lookup(method_name_hash,uri->method_string);
143                 G_UNLOCK(method_name_hash);
144                 if (!method_name_info)
145                         g_return_val_if_reached(GNOME_VFS_ERROR_INVALID_URI);   /* should not happend */
146
147                 if (strcmp(uri->parent->method_string,"file")) {        /* TODO: Generic GnomeVFS filter. */
148                         g_free(uri_parent_string);
149                         return GNOME_VFS_ERROR_INVALID_URI;
150                         }
151
152                 if (!(volume=ntfs_mount(uri->parent->text,MS_RDONLY))) {
153                         g_free(uri_parent_string);
154                         return GNOME_VFS_ERROR_WRONG_FORMAT;
155                         }
156
157                 G_LOCK(uri_parent_string_hash);
158                 g_hash_table_insert(uri_parent_string_hash,g_strdup(uri_parent_string),volume);
159                 G_UNLOCK(uri_parent_string_hash);
160                 }
161         g_free(uri_parent_string);
162
163         *volume_return=volume;
164         return GNOME_VFS_OK;
165 }
166
167
168 static GnomeVFSResult inode_open_by_pathname(ntfs_inode **inode_return,ntfs_volume *volume,const gchar *pathname)
169 {
170 MFT_REF mref;
171 ntfs_inode *inode;
172 gchar *pathname_parse,*pathname_next;
173 int errint;
174
175         g_return_val_if_fail(inode_return!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
176         g_return_val_if_fail(volume!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
177         g_return_val_if_fail(pathname!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
178
179         pathname=g_path_skip_root(pathname);
180         pathname_parse=g_alloca(strlen(pathname)+1);
181         strcpy(pathname_parse,pathname);
182         mref=FILE_root;
183         for (;;) {
184 uchar_t *pathname_parse_ucs2;
185 int i;
186
187                 G_LOCK(libntfs);
188                 inode=ntfs_inode_open(volume,mref);
189                 G_UNLOCK(libntfs);
190                 if (!inode)
191                         return GNOME_VFS_ERROR_NOT_FOUND;
192                 if (!*pathname_parse) {
193                         *inode_return=inode;
194                         return GNOME_VFS_OK;
195                         }
196                 for (pathname_next=pathname_parse;*pathname_next && *pathname_next!=G_DIR_SEPARATOR;pathname_next++);
197                 if (*pathname_next)
198                         *pathname_next++='\0';  /* terminate current path element */
199                 while (*pathname_next==G_DIR_SEPARATOR)
200                         pathname_next++;
201                 /* FIXME: Is 'pathname' utf8? */
202                 libntfs_newn(pathname_parse_ucs2,strlen(pathname_parse)+1);
203                 for (i=0;pathname_parse[i];i++)
204                         pathname_parse_ucs2[i]=pathname_parse[i];
205                 pathname_parse_ucs2[i]=0;
206                 G_LOCK(libntfs);
207                 mref=ntfs_inode_lookup_by_name(inode,pathname_parse_ucs2,i);
208                 G_UNLOCK(libntfs);
209                 g_free(pathname_parse_ucs2);
210                 if ((MFT_REF)-1==mref)
211                         return GNOME_VFS_ERROR_NOT_FOUND;
212                 G_LOCK(libntfs);
213                 errint=ntfs_inode_close(inode);
214                 G_UNLOCK(libntfs);
215                 if (errint)
216                         g_return_val_if_reached(GNOME_VFS_ERROR_INTERNAL);
217                 pathname_parse=pathname_next;
218                 }
219         /* NOTREACHED */
220 }
221
222
223 struct libntfs_directory {
224         ntfs_inode *inode;
225         GList *file_info_list;  /* of (GnomeVFSFileInfo *); last item has ->data==NULL */
226         };
227
228 static GnomeVFSResult libntfs_gnomevfs_open_directory(GnomeVFSMethod *method,
229                 GnomeVFSMethodHandle **method_handle,GnomeVFSURI *uri,GnomeVFSFileInfoOptions options,GnomeVFSContext *context)
230 {
231 GnomeVFSResult errvfsresult;
232 ntfs_volume *volume;
233 ntfs_inode *inode;
234 struct libntfs_directory *libntfs_directory;
235
236         g_return_val_if_fail(method==&GnomeVFSMethod_static,GNOME_VFS_ERROR_BAD_PARAMETERS);
237         g_return_val_if_fail(method_handle!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
238
239         errvfsresult=libntfs_gnomevfs_uri_parent_init(&volume,uri);
240         g_return_val_if_fail(errvfsresult==GNOME_VFS_OK,errvfsresult);
241
242         if (GNOME_VFS_OK!=(errvfsresult=inode_open_by_pathname(&inode,volume,uri->text)))
243                 return errvfsresult;
244
245         libntfs_new(libntfs_directory);
246         libntfs_directory->inode=inode;
247         libntfs_directory->file_info_list=NULL;
248
249         *method_handle=(GnomeVFSMethodHandle *)libntfs_directory;
250         return errvfsresult;
251 }
252
253
254 static GnomeVFSResult libntfs_gnomevfs_close_directory(GnomeVFSMethod *method,
255                 GnomeVFSMethodHandle *method_handle,GnomeVFSContext *context)
256 {
257 struct libntfs_directory *libntfs_directory;
258 int errint;
259
260         g_return_val_if_fail(method==&GnomeVFSMethod_static,GNOME_VFS_ERROR_BAD_PARAMETERS);
261         libntfs_directory=(struct libntfs_directory *)method_handle;
262         g_return_val_if_fail(libntfs_directory!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
263
264         G_LOCK(libntfs);
265         errint=ntfs_inode_close(libntfs_directory->inode);
266         G_UNLOCK(libntfs);
267         if (errint)
268                 g_return_val_if_reached(GNOME_VFS_ERROR_INTERNAL);
269
270         gnome_vfs_file_info_list_free(libntfs_directory->file_info_list);
271
272         g_free(libntfs_directory);
273
274         return GNOME_VFS_OK;
275 }
276
277
278 static gchar *libntfs_uchar_to_utf8(const uchar_t *name,const int name_len)
279 {
280 GString *gstring;
281 int i;
282
283         gstring=g_string_sized_new(name_len);
284         for (i=0;i<name_len;i++)
285                 gstring=g_string_append_unichar(gstring,name[i]);
286         return g_string_free(gstring,   /* returns utf8-formatted string */
287                         FALSE); /* free_segment */
288 }
289
290 static int libntfs_gnomevfs_read_directory_filldir(struct libntfs_directory *libntfs_directory /* dirent */,
291                 const uchar_t *name,const int name_len,const int name_type,const s64 pos,const MFT_REF mref,const unsigned dt_type)
292 {
293 GnomeVFSFileInfo *file_info;
294
295         g_return_val_if_fail(libntfs_directory!=NULL,-1);
296         g_return_val_if_fail(name!=NULL,-1);
297         g_return_val_if_fail(name_len>=0,-1);
298         g_return_val_if_fail(pos>=0,-1);
299
300         file_info=gnome_vfs_file_info_new();
301         file_info->name=libntfs_uchar_to_utf8(name,name_len);
302         file_info->valid_fields=0;
303
304         switch (dt_type) {
305                 case NTFS_DT_FIFO: file_info->type=GNOME_VFS_FILE_TYPE_FIFO;             break;
306                 case NTFS_DT_CHR:  file_info->type=GNOME_VFS_FILE_TYPE_CHARACTER_DEVICE; break;
307                 case NTFS_DT_DIR:  file_info->type=GNOME_VFS_FILE_TYPE_DIRECTORY;        break;
308                 case NTFS_DT_BLK:  file_info->type=GNOME_VFS_FILE_TYPE_BLOCK_DEVICE;     break;
309                 case NTFS_DT_REG:  file_info->type=GNOME_VFS_FILE_TYPE_REGULAR;          break;
310                 case NTFS_DT_LNK:  file_info->type=GNOME_VFS_FILE_TYPE_SYMBOLIC_LINK;    break;
311                 case NTFS_DT_SOCK: file_info->type=GNOME_VFS_FILE_TYPE_SOCKET;           break;
312                 /* FIXME: What is 'NTFS_DT_WHT'? */
313                 default: file_info->type=GNOME_VFS_FILE_TYPE_UNKNOWN;
314                 }
315         if (file_info->type!=GNOME_VFS_FILE_TYPE_UNKNOWN)
316                 file_info->valid_fields|=GNOME_VFS_FILE_INFO_FIELDS_TYPE;
317
318         libntfs_directory->file_info_list=g_list_prepend(libntfs_directory->file_info_list,file_info);
319
320         return 0;       /* continue traversal */
321 }
322
323
324 static GnomeVFSResult libntfs_gnomevfs_read_directory(GnomeVFSMethod *method,
325                 GnomeVFSMethodHandle *method_handle,GnomeVFSFileInfo *file_info,GnomeVFSContext *context)
326 {
327 GnomeVFSResult errvfsresult;
328 struct libntfs_directory *libntfs_directory;
329
330         g_return_val_if_fail(method==&GnomeVFSMethod_static,GNOME_VFS_ERROR_BAD_PARAMETERS);
331         libntfs_directory=(struct libntfs_directory *)method_handle;
332         g_return_val_if_fail(libntfs_directory!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
333         g_return_val_if_fail(file_info!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
334
335         if (!libntfs_directory->file_info_list) {
336 int errint;
337 s64 pos;
338
339                 pos=0;  /* read from the start; incl. "." and ".." entries */
340                 G_LOCK(libntfs);
341                 errint=ntfs_readdir(
342                                 libntfs_directory->inode,       /* dir_ni */
343                                 &pos,   /* pos */
344                                 libntfs_directory,      /* dirent */
345                                 (ntfs_filldir_t)libntfs_gnomevfs_read_directory_filldir);       /* filldir */
346                 G_UNLOCK(libntfs);
347                 if (errint)
348                         return GNOME_VFS_ERROR_INTERNAL;
349
350                 libntfs_directory->file_info_list=g_list_prepend(libntfs_directory->file_info_list,NULL);       /* EOF */
351                 libntfs_directory->file_info_list=g_list_reverse(libntfs_directory->file_info_list);
352                 }
353
354         if (!libntfs_directory->file_info_list->data) {
355                 g_assert(libntfs_directory->file_info_list->next==NULL);
356                 errvfsresult=GNOME_VFS_ERROR_EOF;
357                 }
358         else {
359                 /* Cut first list item. */
360                 gnome_vfs_file_info_copy(
361                                 file_info,      /* dest */
362                                 libntfs_directory->file_info_list->data);       /* src */
363                 gnome_vfs_file_info_unref(libntfs_directory->file_info_list->data);
364                 errvfsresult=GNOME_VFS_OK;
365                 }
366         libntfs_directory->file_info_list=g_list_delete_link(
367                         libntfs_directory->file_info_list,libntfs_directory->file_info_list);
368         return errvfsresult;
369 }
370
371
372 struct libntfs_file {
373         ntfs_inode *inode;
374         ntfs_attr *attr;
375         s64 pos;
376         };
377
378 static GnomeVFSResult libntfs_open_attr(struct libntfs_file *libntfs_file)
379 {
380         g_return_val_if_fail(libntfs_file!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
381         g_return_val_if_fail(libntfs_file->inode!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
382
383         if (!libntfs_file->attr) {
384                 G_LOCK(libntfs);
385                 libntfs_file->attr=ntfs_attr_open(
386                                 libntfs_file->inode,    /* ni */
387                                 AT_DATA,        /* type */
388                                 NULL,   /* name */
389                                 0);     /* name_len */
390                 G_UNLOCK(libntfs);
391                 if (!libntfs_file->attr)
392                         return GNOME_VFS_ERROR_BAD_FILE;
393                 libntfs_file->pos=0;
394                 }
395
396         return GNOME_VFS_OK;
397 }
398
399 static GnomeVFSResult libntfs_gnomevfs_open(GnomeVFSMethod *method,
400                 GnomeVFSMethodHandle **method_handle_return,GnomeVFSURI *uri,GnomeVFSOpenMode mode,GnomeVFSContext *context)
401 {
402 GnomeVFSResult errvfsresult;
403 ntfs_volume *volume;
404 ntfs_inode *inode;
405 struct libntfs_file *libntfs_file;
406
407         g_return_val_if_fail(method==&GnomeVFSMethod_static,GNOME_VFS_ERROR_BAD_PARAMETERS);
408         g_return_val_if_fail(method_handle_return!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
409
410         errvfsresult=libntfs_gnomevfs_uri_parent_init(&volume,uri);
411         g_return_val_if_fail(errvfsresult==GNOME_VFS_OK,errvfsresult);
412
413         if (mode & GNOME_VFS_OPEN_WRITE)
414                 return GNOME_VFS_ERROR_READ_ONLY_FILE_SYSTEM;
415
416         if (GNOME_VFS_OK!=(errvfsresult=inode_open_by_pathname(&inode,volume,uri->text)))
417                 return errvfsresult;
418
419         libntfs_new(libntfs_file);
420         libntfs_file->inode=inode;
421         libntfs_file->attr=NULL;
422
423         *method_handle_return=(GnomeVFSMethodHandle *)libntfs_file;
424         return errvfsresult;
425 }
426
427
428 static GnomeVFSResult libntfs_gnomevfs_create(GnomeVFSMethod *method,
429                 GnomeVFSMethodHandle **method_handle_return,GnomeVFSURI *uri,GnomeVFSOpenMode mode,gboolean exclusive,guint perm,
430                 GnomeVFSContext *context)
431 {
432 GnomeVFSResult errvfsresult;
433 ntfs_volume *volume;
434
435         g_return_val_if_fail(method==&GnomeVFSMethod_static,GNOME_VFS_ERROR_BAD_PARAMETERS);
436         g_return_val_if_fail(method_handle_return!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
437
438         errvfsresult=libntfs_gnomevfs_uri_parent_init(&volume,uri);
439         g_return_val_if_fail(errvfsresult==GNOME_VFS_OK,errvfsresult);
440
441         return GNOME_VFS_ERROR_READ_ONLY_FILE_SYSTEM;
442 }
443
444
445 static GnomeVFSResult libntfs_gnomevfs_close(GnomeVFSMethod *method,
446                 GnomeVFSMethodHandle *method_handle,GnomeVFSContext *context)
447 {
448 struct libntfs_file *libntfs_file;
449 int errint;
450
451         g_return_val_if_fail(method==&GnomeVFSMethod_static,GNOME_VFS_ERROR_BAD_PARAMETERS);
452         libntfs_file=(struct libntfs_file *)method_handle;
453         g_return_val_if_fail(libntfs_file!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
454
455         if (libntfs_file->attr) {
456                 G_LOCK(libntfs);
457                 ntfs_attr_close(libntfs_file->attr);
458                 G_UNLOCK(libntfs);
459                 }
460         G_LOCK(libntfs);
461         errint=ntfs_inode_close(libntfs_file->inode);
462         G_UNLOCK(libntfs);
463         if (errint)
464                 g_return_val_if_reached(GNOME_VFS_ERROR_INTERNAL);
465
466         g_free(libntfs_file);
467
468         return GNOME_VFS_OK;
469 }
470
471
472 static GnomeVFSResult libntfs_gnomevfs_read(GnomeVFSMethod *method,GnomeVFSMethodHandle *method_handle,
473                 gpointer buffer,GnomeVFSFileSize num_bytes,GnomeVFSFileSize *bytes_read_return,GnomeVFSContext *context)
474 {
475 GnomeVFSResult errvfsresult;
476 struct libntfs_file *libntfs_file;
477 s64 count_s64,got;
478
479         g_return_val_if_fail(method==&GnomeVFSMethod_static,GNOME_VFS_ERROR_BAD_PARAMETERS);
480         libntfs_file=(struct libntfs_file *)method_handle;
481         g_return_val_if_fail(libntfs_file!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
482         g_return_val_if_fail(buffer!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
483         g_return_val_if_fail(bytes_read_return!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
484
485         if (GNOME_VFS_OK!=(errvfsresult=libntfs_open_attr(libntfs_file)))
486                 return errvfsresult;
487
488         count_s64=num_bytes;
489         g_assert((GnomeVFSFileSize)count_s64==num_bytes);
490         G_LOCK(libntfs);
491         got=ntfs_attr_pread(libntfs_file->attr,libntfs_file->pos,count_s64,buffer);
492         G_UNLOCK(libntfs);
493         if (got==-1)
494                 return GNOME_VFS_ERROR_IO;
495
496         libntfs_file->pos+=got;
497         *bytes_read_return=got;
498         g_assert((s64)*bytes_read_return==got);
499
500         return GNOME_VFS_OK;
501 }
502
503
504 static GnomeVFSResult libntfs_gnomevfs_seek(GnomeVFSMethod *method,
505                 GnomeVFSMethodHandle *method_handle,GnomeVFSSeekPosition whence,GnomeVFSFileOffset offset,GnomeVFSContext *context)
506 {
507 GnomeVFSResult errvfsresult;
508 struct libntfs_file *libntfs_file;
509
510         g_return_val_if_fail(method==&GnomeVFSMethod_static,GNOME_VFS_ERROR_BAD_PARAMETERS);
511         libntfs_file=(struct libntfs_file *)method_handle;
512         g_return_val_if_fail(libntfs_file!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
513
514         if (GNOME_VFS_OK!=(errvfsresult=libntfs_open_attr(libntfs_file)))
515                 return errvfsresult;
516
517         switch (whence) {
518                 case GNOME_VFS_SEEK_START:
519                         libntfs_file->pos=offset;
520                         break;
521                 case GNOME_VFS_SEEK_CURRENT:
522                         libntfs_file->pos+=offset;
523                         break;
524                 case GNOME_VFS_SEEK_END:
525                         g_return_val_if_reached(GNOME_VFS_ERROR_BAD_PARAMETERS);        /* FIXME: NOT IMPLEMENTED YET */
526                 default: g_assert_not_reached();
527                 }
528
529         return GNOME_VFS_OK;
530 }
531
532 static GnomeVFSResult libntfs_gnomevfs_tell(GnomeVFSMethod *method,
533                 GnomeVFSMethodHandle *method_handle,GnomeVFSFileOffset *offset_return)
534 {
535 GnomeVFSResult errvfsresult;
536 struct libntfs_file *libntfs_file;
537
538         g_return_val_if_fail(method==&GnomeVFSMethod_static,GNOME_VFS_ERROR_BAD_PARAMETERS);
539         libntfs_file=(struct libntfs_file *)method_handle;
540         g_return_val_if_fail(libntfs_file!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
541         g_return_val_if_fail(offset_return!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
542
543         if (GNOME_VFS_OK!=(errvfsresult=libntfs_open_attr(libntfs_file)))
544                 return errvfsresult;
545
546         *offset_return=libntfs_file->pos;
547         g_assert(*offset_return==libntfs_file->pos);
548
549         return errvfsresult;
550 }
551
552
553 static gboolean libntfs_gnomevfs_is_local(GnomeVFSMethod *method,const GnomeVFSURI *uri)
554 {
555         g_return_val_if_fail(method==&GnomeVFSMethod_static,GNOME_VFS_ERROR_BAD_PARAMETERS);
556         g_return_val_if_fail(uri!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
557
558         return gnome_vfs_uri_is_local(uri->parent);
559 }
560
561
562 GnomeVFSResult libntfs_gnomevfs_get_file_info_from_handle(GnomeVFSMethod *method,
563                 GnomeVFSMethodHandle *method_handle,GnomeVFSFileInfo *file_info,GnomeVFSFileInfoOptions options,GnomeVFSContext *context)
564 {
565 GnomeVFSResult errvfsresult;
566 struct libntfs_file *libntfs_file;
567
568         g_return_val_if_fail(method==&GnomeVFSMethod_static,GNOME_VFS_ERROR_BAD_PARAMETERS);
569         libntfs_file=(struct libntfs_file *)method_handle;
570         g_return_val_if_fail(libntfs_file!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
571         g_return_val_if_fail(file_info!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
572         /* handle 'options & GNOME_VFS_FILE_INFO_GET_MIME_TYPE'? */
573
574         if (GNOME_VFS_OK!=(errvfsresult=libntfs_open_attr(libntfs_file)))
575                 return errvfsresult;
576
577         file_info->valid_fields=0;
578         file_info->name=NULL;   /* FIXME: It is complicated to read filename of open 'ntfs_inode'. */
579
580         file_info->size=libntfs_file->attr->data_size;  /* FIXME: Is 'data_size' the right field? */
581         file_info->valid_fields|=GNOME_VFS_FILE_INFO_FIELDS_SIZE;
582
583         /* FIXME: We do not really know the type of 'libntfs_file'
584          * but gnome-vfs-xfer.c/copy_items() requires 'GNOME_VFS_FILE_TYPE_REGULAR'
585          * to copy it.
586          */
587         file_info->type=GNOME_VFS_FILE_TYPE_REGULAR;
588         /* Do not: file_info->valid_fields|=GNOME_VFS_FILE_INFO_FIELDS_TYPE;
589          * as gnome-vfs-xfer.c/copy_items() does not check 'GNOME_VFS_FILE_INFO_FIELDS_TYPE'
590          * and we are just bluffing we know it.
591          */
592
593         return errvfsresult;
594 }
595
596
597 static GnomeVFSResult libntfs_gnomevfs_get_file_info(GnomeVFSMethod *method,
598                 GnomeVFSURI *uri,GnomeVFSFileInfo *file_info,GnomeVFSFileInfoOptions options,GnomeVFSContext *context)
599 {
600 GnomeVFSResult errvfsresult;
601 GnomeVFSMethodHandle *method_handle;
602
603         g_return_val_if_fail(method==&GnomeVFSMethod_static,GNOME_VFS_ERROR_BAD_PARAMETERS);
604         g_return_val_if_fail(file_info!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
605         /* handle 'options & GNOME_VFS_FILE_INFO_GET_MIME_TYPE'? */
606
607         if (GNOME_VFS_OK!=(errvfsresult=libntfs_gnomevfs_open(method,&method_handle,uri,GNOME_VFS_OPEN_READ,context)))
608                 return errvfsresult;
609         if (GNOME_VFS_OK!=(errvfsresult=libntfs_gnomevfs_get_file_info_from_handle(method,method_handle,file_info,options,context)))
610                 return errvfsresult;
611         if (GNOME_VFS_OK!=(errvfsresult=libntfs_gnomevfs_close(method,method_handle,context)))
612                 return errvfsresult;
613
614         return GNOME_VFS_OK;
615 }
616
617
618 GnomeVFSResult libntfs_gnomevfs_check_same_fs(GnomeVFSMethod *method,
619                 GnomeVFSURI *a,GnomeVFSURI *b,gboolean *same_fs_return,GnomeVFSContext *context)
620 {
621 ntfs_volume *volume_a;
622 ntfs_volume *volume_b;
623 GnomeVFSResult errvfsresult;
624
625         g_return_val_if_fail(method==&GnomeVFSMethod_static,GNOME_VFS_ERROR_BAD_PARAMETERS);
626         g_return_val_if_fail(same_fs_return!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
627
628         errvfsresult=libntfs_gnomevfs_uri_parent_init(&volume_a,a);
629         g_return_val_if_fail(errvfsresult==GNOME_VFS_OK,errvfsresult);
630
631         errvfsresult=libntfs_gnomevfs_uri_parent_init(&volume_b,b);
632         g_return_val_if_fail(errvfsresult==GNOME_VFS_OK,errvfsresult);
633
634         *same_fs_return=(volume_a==volume_b);
635
636         return GNOME_VFS_OK;
637 }
638
639
640 /**
641  * libntfs_gnomevfs_init:
642  *
643  * Returns: Initialized structure of #GnomeVFSMethod with static methods of libntfs-gnomevfs.
644  */
645 GnomeVFSMethod *libntfs_gnomevfs_method_init(const gchar *method_name,const gchar *args)
646 {
647 struct method_name_info *method_name_info;
648
649         g_return_val_if_fail(method_name!=NULL,NULL);
650         /* 'args' may be NULL if not supplied. */
651
652         method_name_hash_init();
653
654         G_LOCK(method_name_hash);
655         method_name_info=g_hash_table_lookup(method_name_hash,method_name);
656         if (method_name_info && strcmp(method_name_info->args,args))
657                 method_name_info=NULL;
658         G_UNLOCK(method_name_hash);
659         if (!method_name_info) {
660                 libntfs_new(method_name_info);
661                 method_name_info->args=g_strdup(args);
662                 G_LOCK(method_name_hash);
663                 g_hash_table_replace(method_name_hash,g_strdup(method_name),method_name_info);
664                 G_UNLOCK(method_name_hash);
665                 }
666
667         G_LOCK(GnomeVFSMethod_static);
668         LIBNTFS_MEMZERO(&GnomeVFSMethod_static);
669         GnomeVFSMethod_static.method_table_size=sizeof(GnomeVFSMethod_static);
670         GnomeVFSMethod_static.open                     =libntfs_gnomevfs_open;  /* mandatory */
671         GnomeVFSMethod_static.create                   =libntfs_gnomevfs_create;        /* mandatory */
672         GnomeVFSMethod_static.close                    =libntfs_gnomevfs_close;
673         GnomeVFSMethod_static.read                     =libntfs_gnomevfs_read;
674         GnomeVFSMethod_static.seek                     =libntfs_gnomevfs_seek;
675         GnomeVFSMethod_static.tell                     =libntfs_gnomevfs_tell;
676         GnomeVFSMethod_static.open_directory           =libntfs_gnomevfs_open_directory;
677         GnomeVFSMethod_static.close_directory          =libntfs_gnomevfs_close_directory;
678         GnomeVFSMethod_static.read_directory           =libntfs_gnomevfs_read_directory;
679         GnomeVFSMethod_static.get_file_info            =libntfs_gnomevfs_get_file_info; /* mandatory */
680         GnomeVFSMethod_static.get_file_info_from_handle=libntfs_gnomevfs_get_file_info_from_handle;
681         GnomeVFSMethod_static.is_local                 =libntfs_gnomevfs_is_local;      /* mandatory */
682         GnomeVFSMethod_static.check_same_fs            =libntfs_gnomevfs_check_same_fs;
683         /* TODO: GnomeVFSMethodFindDirectoryFunc find_directory; */
684         /* TODO: GnomeVFSMethodFileControlFunc file_control; */
685         /* R/W:  GnomeVFSMethodCreateSymbolicLinkFunc create_symbolic_link; */
686         /* R/W:  GnomeVFSMethodMonitorAddFunc monitor_add; */
687         /* R/W:  GnomeVFSMethodMonitorCancelFunc monitor_cancel; */
688         /* R/W:  GnomeVFSMethod_static.write; */
689         /* R/W:  GnomeVFSMethod_static.truncate_handle; */
690         /* R/W:  GnomeVFSMethod_static.make_directory; */
691         /* R/W:  GnomeVFSMethod_static.remove_directory; */
692         /* R/W:  GnomeVFSMethod_static.move; */
693         /* R/W:  GnomeVFSMethod_static.unlink; */
694         /* R/W:  GnomeVFSMethod_static.set_file_info; */
695         /* R/W:  GnomeVFSMethod_static.truncate; */
696         G_UNLOCK(GnomeVFSMethod_static);
697
698         return &GnomeVFSMethod_static;
699 }
700
701
702 /**
703  * libntfs_gnomevfs_method_shutdown:
704  *
705  * Shutdowns libntfs-gnomevfs successfuly flushing all caches.
706  *
707  * Sad note about gnome-vfs-2.1.5 is that it never calls this function. :-)
708  */ 
709 void libntfs_gnomevfs_method_shutdown(void)
710 {
711         uri_parent_string_hash_init();
712         G_LOCK(uri_parent_string_hash);
713         g_hash_table_destroy(uri_parent_string_hash);
714         uri_parent_string_hash=NULL;
715         G_UNLOCK(uri_parent_string_hash);
716
717         method_name_hash_init();
718         G_LOCK(method_name_hash);
719         g_hash_table_destroy(method_name_hash);
720         method_name_hash=NULL;
721         G_UNLOCK(method_name_hash);
722 }