xref: /onnv-gate/usr/src/lib/libntfs/common/libntfs/gnome-vfs-method.c (revision 10214:1f70f0c2183c)
1 /*
2  * gnome-vfs-method.c - Gnome-VFS init/shutdown implementation of interface to
3  *			libntfs. Part of the Linux-NTFS project.
4  *
5  * Copyright (c) 2003 Jan Kratochvil <project-captive@jankratochvil.net>
6  * Copyright (c) 2003-2006 Anton Altaparmakov
7  *
8  * This program/include file is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License as published
10  * by the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program/include file is distributed in the hope that it will be
14  * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
15  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program (in the main directory of the Linux-NTFS
20  * distribution in the file COPYING); if not, write to the Free Software
21  * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22  */
23 
24 #include "config.h"
25 
26 #undef FALSE
27 #undef TRUE
28 #include "types.h"		/* for 'FALSE'/'TRUE' libntfs definition */
29 #define FALSE FALSE
30 #define TRUE TRUE
31 
32 #include "gnome-vfs-method.h"	/* self */
33 #include <libgnomevfs/gnome-vfs-method.h>
34 #include <glib/gmessages.h>
35 #include "gnome-vfs-module.h"
36 #include <glib/ghash.h>
37 #ifdef HAVE_STRING_H
38 #include <string.h>
39 #endif
40 #include <libgnomevfs/gnome-vfs-utils.h>
41 
42 #include "compat.h"
43 #include "volume.h"
44 #include "dir.h"
45 
46 static GnomeVFSMethod GnomeVFSMethod_static;
47 G_LOCK_DEFINE_STATIC(GnomeVFSMethod_static);
48 
49 /* map: (gchar *)method_name -> (struct method_name_info *) */
50 static GHashTable *method_name_hash;
51 G_LOCK_DEFINE_STATIC(method_name_hash);
52 
53 #ifdef __sun
54 G_LOCK_DEFINE(libntfs);
55 #endif
56 
57 struct method_name_info {
58 	gchar *args;
59 };
60 
method_name_hash_key_destroy_func(gchar * key)61 static void method_name_hash_key_destroy_func(gchar *key)
62 {
63 	g_return_if_fail(key != NULL);
64 
65 	g_free(key);
66 }
67 
method_name_hash_value_destroy_func(struct method_name_info * value)68 static void method_name_hash_value_destroy_func(struct method_name_info *value)
69 {
70 	g_return_if_fail(value != NULL);
71 
72 	g_free(value->args);
73 	g_free(value);
74 }
75 
method_name_hash_init(void)76 static void method_name_hash_init(void)
77 {
78 	G_LOCK(method_name_hash);
79 	if (!method_name_hash) {
80 		method_name_hash = g_hash_table_new_full(
81 				g_str_hash,	/* hash_func */
82 				g_str_equal,	/* key_equal_func */
83 				(GDestroyNotify) method_name_hash_key_destroy_func,	/* key_destroy_func */
84 				(GDestroyNotify) method_name_hash_value_destroy_func);	/* value_destroy_func */
85 	}
86 	G_UNLOCK(method_name_hash);
87 }
88 
89 /*
90  * map: (gchar *)uri_parent_string "method_name:uri_parent" -> (ntfs_volume *)
91  */
92 static GHashTable *uri_parent_string_hash;
93 G_LOCK_DEFINE_STATIC(uri_parent_string_hash);
94 
uri_parent_string_hash_key_destroy_func(gchar * key)95 static void uri_parent_string_hash_key_destroy_func(gchar *key)
96 {
97 	g_return_if_fail(key != NULL);
98 
99 	g_free(key);
100 }
101 
uri_parent_string_hash_value_destroy_func(ntfs_volume * value)102 static void uri_parent_string_hash_value_destroy_func(ntfs_volume *value)
103 {
104 	g_return_if_fail(value != NULL);
105 
106 	ntfs_umount(	/* errors ignored */
107 			value,	/* vol */
108 			TRUE);	/* force; possibly loose modifications */
109 }
110 
uri_parent_string_hash_init(void)111 static void uri_parent_string_hash_init(void)
112 {
113 	G_LOCK(uri_parent_string_hash);
114 	if (!uri_parent_string_hash) {
115 		uri_parent_string_hash = g_hash_table_new_full(
116 				g_str_hash,	/* hash_func */
117 				g_str_equal,	/* key_equal_func */
118 				(GDestroyNotify) uri_parent_string_hash_key_destroy_func,	/* key_destroy_func */
119 				(GDestroyNotify) uri_parent_string_hash_value_destroy_func);	/* value_destroy_func */
120 	}
121 	G_UNLOCK(uri_parent_string_hash);
122 }
123 
libntfs_gnomevfs_uri_parent_init(ntfs_volume ** volume_return,GnomeVFSURI * uri)124 static GnomeVFSResult libntfs_gnomevfs_uri_parent_init(
125 		ntfs_volume **volume_return, GnomeVFSURI *uri)
126 {
127 	gchar *uri_parent_string;
128 	gchar *uri_parent_string_parent;
129 	ntfs_volume *volume;
130 
131 	g_return_val_if_fail(uri != NULL, GNOME_VFS_ERROR_INVALID_URI);
132 	g_return_val_if_fail(volume_return != NULL,
133 			     GNOME_VFS_ERROR_BAD_PARAMETERS);
134 
135 	uri_parent_string_hash_init();
136 
137 	if (!uri->parent)
138 		return GNOME_VFS_ERROR_INVALID_URI;
139 	if (!uri->text)		/* not needed here but we don't permit non-specific fs-image reference */
140 		return GNOME_VFS_ERROR_INVALID_URI;
141 	uri_parent_string_parent = gnome_vfs_uri_to_string(uri->parent,
142 			GNOME_VFS_URI_HIDE_NONE);
143 	g_assert(uri_parent_string_parent != NULL);
144 
145 	uri_parent_string = g_strdup_printf("%s:%s", uri->method_string,
146 			uri_parent_string_parent);
147 	g_assert(uri_parent_string != NULL);
148 
149 	G_LOCK(uri_parent_string_hash);
150 	volume = g_hash_table_lookup(uri_parent_string_hash, uri_parent_string);
151 	G_UNLOCK(uri_parent_string_hash);
152 	if (!volume) {
153 		struct method_name_info *method_name_info;
154 
155 		G_LOCK(method_name_hash);
156 		method_name_info = g_hash_table_lookup(method_name_hash,
157 				uri->method_string);
158 		G_UNLOCK(method_name_hash);
159 		if (!method_name_info) {
160 			/* should not happend */
161 			g_return_val_if_reached(GNOME_VFS_ERROR_INVALID_URI);
162 		}
163 
164 		/* TODO: Generic GnomeVFS filter. */
165 		if (strcmp(uri->parent->method_string, "file")) {
166 			g_free(uri_parent_string);
167 			return GNOME_VFS_ERROR_INVALID_URI;
168 		}
169 
170 		if (!(volume = ntfs_mount(uri->parent->text,
171 				NTFS_MNT_RDONLY))) {
172 			g_free(uri_parent_string);
173 			return GNOME_VFS_ERROR_WRONG_FORMAT;
174 		}
175 
176 		G_LOCK(uri_parent_string_hash);
177 		g_hash_table_insert(uri_parent_string_hash,
178 				g_strdup(uri_parent_string), volume);
179 		G_UNLOCK(uri_parent_string_hash);
180 	}
181 	g_free(uri_parent_string);
182 
183 	*volume_return = volume;
184 	return GNOME_VFS_OK;
185 }
186 
inode_open_by_pathname(ntfs_inode ** inode_return,ntfs_volume * volume,const gchar * pathname)187 static GnomeVFSResult inode_open_by_pathname(ntfs_inode **inode_return,
188 		ntfs_volume *volume, const gchar *pathname)
189 {
190 	MFT_REF mref;
191 	ntfs_inode *inode;
192 	gchar *pathname_parse, *pathname_next;
193 	int errint;
194 
195 	g_return_val_if_fail(inode_return != NULL,
196 			GNOME_VFS_ERROR_BAD_PARAMETERS);
197 	g_return_val_if_fail(volume != NULL, GNOME_VFS_ERROR_BAD_PARAMETERS);
198 	g_return_val_if_fail(pathname != NULL, GNOME_VFS_ERROR_BAD_PARAMETERS);
199 
200 	pathname = g_path_skip_root(pathname);
201 	pathname_parse = g_alloca(strlen(pathname) + 1);
202 	strcpy(pathname_parse, pathname);
203 	mref = FILE_root;
204 	for (;;) {
205 		ntfschar *pathname_parse_ucs2;
206 		gchar *pathname_parse_unescaped;
207 		int i;
208 
209 		G_LOCK(libntfs);
210 		inode = ntfs_inode_open(volume, mref);
211 		G_UNLOCK(libntfs);
212 		if (!inode)
213 			return GNOME_VFS_ERROR_NOT_FOUND;
214 		if (!*pathname_parse) {
215 			*inode_return = inode;
216 			return GNOME_VFS_OK;
217 		}
218 		for (pathname_next = pathname_parse; *pathname_next &&
219 		     *pathname_next != G_DIR_SEPARATOR; pathname_next++) ;
220 		if (*pathname_next) {
221 			/* terminate current path element */
222 			*pathname_next++ = 0;
223 		}
224 		while (*pathname_next == G_DIR_SEPARATOR)
225 			pathname_next++;
226 		/* FIXME: Is 'pathname' utf8? */
227 		pathname_parse_unescaped = gnome_vfs_unescape_string(
228 				pathname_parse, NULL);	/* illegal_characters */
229 #ifdef __sun
230 		pathname_parse_ucs2 = g_malloc(strlen(pathname_parse_unescaped) + 1);
231 #else /* !__sun */
232 		libntfs_newn(pathname_parse_ucs2,
233 				strlen(pathname_parse_unescaped) + 1);
234 #endif /* __sun */
235 		for (i = 0; pathname_parse_unescaped[i]; i++)
236 			pathname_parse_ucs2[i] = cpu_to_le16(
237 					pathname_parse_unescaped[i]);
238 		pathname_parse_ucs2[i] = 0;
239 		g_free(pathname_parse_unescaped);
240 		G_LOCK(libntfs);
241 		mref = ntfs_inode_lookup_by_name(inode, pathname_parse_ucs2, i);
242 		G_UNLOCK(libntfs);
243 		g_free(pathname_parse_ucs2);
244 		if ((MFT_REF)-1 == mref)
245 			return GNOME_VFS_ERROR_NOT_FOUND;
246 		G_LOCK(libntfs);
247 		errint = ntfs_inode_close(inode);
248 		G_UNLOCK(libntfs);
249 		if (errint)
250 			g_return_val_if_reached(GNOME_VFS_ERROR_INTERNAL);
251 		pathname_parse = pathname_next;
252 	}
253 	/* NOTREACHED */
254 }
255 
256 struct libntfs_directory {
257 	ntfs_inode *inode;
258 	GList *file_info_list;	/* of (GnomeVFSFileInfo *); last item has ->data == NULL */
259 };
260 
libntfs_gnomevfs_open_directory(GnomeVFSMethod * method,GnomeVFSMethodHandle ** method_handle,GnomeVFSURI * uri,GnomeVFSFileInfoOptions options,GnomeVFSContext * context)261 static GnomeVFSResult libntfs_gnomevfs_open_directory(GnomeVFSMethod *method,
262 		GnomeVFSMethodHandle **method_handle, GnomeVFSURI *uri,
263 		GnomeVFSFileInfoOptions options __attribute__((unused)),
264 		GnomeVFSContext *context __attribute__((unused)))
265 {
266 	GnomeVFSResult errvfsresult;
267 	ntfs_volume *volume;
268 	ntfs_inode *inode;
269 	struct libntfs_directory *libntfs_directory;
270 
271 	g_return_val_if_fail(method == &GnomeVFSMethod_static,
272 			GNOME_VFS_ERROR_BAD_PARAMETERS);
273 	g_return_val_if_fail(method_handle != NULL,
274 			GNOME_VFS_ERROR_BAD_PARAMETERS);
275 
276 	if (GNOME_VFS_OK != (errvfsresult =
277 			libntfs_gnomevfs_uri_parent_init(&volume, uri)))
278 		return errvfsresult;
279 
280 	if (GNOME_VFS_OK != (errvfsresult = inode_open_by_pathname(&inode,
281 			volume, uri->text)))
282 		return errvfsresult;
283 
284 #ifdef __sun
285 	libntfs_directory = g_new(struct libntfs_directory, 1);
286 #else /* !__sun */
287 	libntfs_new(libntfs_directory);
288 #endif /* __sun */
289 
290 	libntfs_directory->inode = inode;
291 	libntfs_directory->file_info_list = NULL;
292 
293 	*method_handle = (GnomeVFSMethodHandle *)libntfs_directory;
294 	return errvfsresult;
295 }
296 
libntfs_gnomevfs_close_directory(GnomeVFSMethod * method,GnomeVFSMethodHandle * method_handle,GnomeVFSContext * context)297 static GnomeVFSResult libntfs_gnomevfs_close_directory(GnomeVFSMethod *method,
298 		GnomeVFSMethodHandle *method_handle,
299 		GnomeVFSContext *context __attribute__((unused)))
300 {
301 	struct libntfs_directory *libntfs_directory;
302 	int errint;
303 
304 	g_return_val_if_fail(method == &GnomeVFSMethod_static,
305 			GNOME_VFS_ERROR_BAD_PARAMETERS);
306 	libntfs_directory = (struct libntfs_directory *)method_handle;
307 	g_return_val_if_fail(libntfs_directory != NULL,
308 			GNOME_VFS_ERROR_BAD_PARAMETERS);
309 
310 	G_LOCK(libntfs);
311 	errint = ntfs_inode_close(libntfs_directory->inode);
312 	G_UNLOCK(libntfs);
313 	if (errint)
314 		g_return_val_if_reached(GNOME_VFS_ERROR_INTERNAL);
315 
316 	if (libntfs_directory->file_info_list) {
317 		GList *last_l;
318 
319 		/*
320 		 * Prevent gnome_vfs_file_info_list_free() and its
321 		 * gnome_vfs_file_info_unref() on the last 'file_info_list'
322 		 * items as it is EOF with NULL '->data'.
323 		 */
324 		last_l = g_list_last(libntfs_directory->file_info_list);
325 		g_assert(last_l->data == NULL);
326 		libntfs_directory->file_info_list = g_list_delete_link(
327 				libntfs_directory->file_info_list, last_l);
328 		gnome_vfs_file_info_list_free(
329 				libntfs_directory->file_info_list);
330 	}
331 
332 	g_free(libntfs_directory);
333 
334 	return GNOME_VFS_OK;
335 }
336 
libntfs_ntfscharo_utf8(const ntfschar * name,const int name_len)337 static gchar *libntfs_ntfscharo_utf8(const ntfschar *name, const int name_len)
338 {
339 	GString *gstring;
340 	int i;
341 
342 	gstring = g_string_sized_new(name_len);
343 	for (i = 0; i < name_len; i++)
344 		gstring = g_string_append_unichar(gstring,
345 				le16_to_cpu(name[i]));
346 	return g_string_free(gstring,	/* returns utf8-formatted string */
347 			FALSE);	/* free_segment */
348 }
349 
350 /*
351  * Do not lock 'libntfs' here as we are already locked inside ntfs_readdir().
352  */
libntfs_gnomevfs_read_directory_filldir(struct libntfs_directory * libntfs_directory,const ntfschar * name,const int name_len,const int name_type,const s64 pos,const MFT_REF mref,const unsigned dt_type)353 static int libntfs_gnomevfs_read_directory_filldir(
354 		struct libntfs_directory *libntfs_directory /* dirent */,
355 		const ntfschar *name, const int name_len,
356 		const int name_type __attribute__((unused)),
357 		const s64 pos, const MFT_REF mref, const unsigned dt_type)
358 {
359 	GnomeVFSFileInfo *file_info;
360 
361 	g_return_val_if_fail(libntfs_directory != NULL, -1);
362 	g_return_val_if_fail(name != NULL, -1);
363 	g_return_val_if_fail(name_len >= 0, -1);
364 	g_return_val_if_fail(pos >= 0, -1);
365 
366 	/* system directory */
367 	if (MREF(mref) != FILE_root && MREF(mref) < FILE_first_user)
368 		return 0;	/* continue traversal */
369 
370 	file_info = gnome_vfs_file_info_new();
371 	file_info->name = libntfs_ntfscharo_utf8(name, name_len);
372 	file_info->valid_fields = 0;
373 
374 	switch (dt_type) {
375 	case NTFS_DT_FIFO:
376 		file_info->type = GNOME_VFS_FILE_TYPE_FIFO;
377 		break;
378 	case NTFS_DT_CHR:
379 		file_info->type = GNOME_VFS_FILE_TYPE_CHARACTER_DEVICE;
380 		break;
381 	case NTFS_DT_DIR:
382 		file_info->type = GNOME_VFS_FILE_TYPE_DIRECTORY;
383 		break;
384 	case NTFS_DT_BLK:
385 		file_info->type = GNOME_VFS_FILE_TYPE_BLOCK_DEVICE;
386 		break;
387 	case NTFS_DT_REG:
388 		file_info->type = GNOME_VFS_FILE_TYPE_REGULAR;
389 		break;
390 	case NTFS_DT_LNK:
391 		file_info->type = GNOME_VFS_FILE_TYPE_SYMBOLIC_LINK;
392 		break;
393 	case NTFS_DT_SOCK:
394 		file_info->type = GNOME_VFS_FILE_TYPE_SOCKET;
395 		break;
396 		/* FIXME: What is 'NTFS_DT_WHT'? */
397 	default:
398 		file_info->type = GNOME_VFS_FILE_TYPE_UNKNOWN;
399 	}
400 	if (file_info->type != GNOME_VFS_FILE_TYPE_UNKNOWN)
401 		file_info->valid_fields |= GNOME_VFS_FILE_INFO_FIELDS_TYPE;
402 
403 	/* Detect 'file_info->size': */
404 	if (file_info->type == GNOME_VFS_FILE_TYPE_REGULAR) {
405 		ntfs_inode *inode;
406 
407 		inode = ntfs_inode_open(libntfs_directory->inode->vol, mref);
408 		/* FIXME: Check failed 'inode' open. */
409 		if (inode) {
410 			ntfs_attr *attr;
411 			int errint;
412 
413 			attr = ntfs_attr_open(inode,	/* ni */
414 					AT_DATA,	/* type */
415 					AT_UNNAMED,	/* name */
416 					0);		/* name_len */
417 			/* FIXME: Check failed 'attr' open. */
418 			if (attr) {
419 				/* FIXME: Is 'data_size' the right field? */
420 				file_info->size = attr->data_size;
421 				file_info->valid_fields |=
422 						GNOME_VFS_FILE_INFO_FIELDS_SIZE;
423 				ntfs_attr_close(attr);
424 			}
425 			errint = ntfs_inode_close(inode);
426 			/* FIXME: Check 'errint'. */
427 		}
428 	}
429 
430 	libntfs_directory->file_info_list = g_list_prepend(
431 			libntfs_directory->file_info_list, file_info);
432 
433 	return 0;	/* continue traversal */
434 }
435 
libntfs_gnomevfs_read_directory(GnomeVFSMethod * method,GnomeVFSMethodHandle * method_handle,GnomeVFSFileInfo * file_info,GnomeVFSContext * context)436 static GnomeVFSResult libntfs_gnomevfs_read_directory(GnomeVFSMethod *method,
437 		GnomeVFSMethodHandle *method_handle,
438 		GnomeVFSFileInfo *file_info,
439 		GnomeVFSContext *context __attribute__((unused)))
440 {
441 	GnomeVFSResult errvfsresult;
442 	struct libntfs_directory *libntfs_directory;
443 
444 	g_return_val_if_fail(method == &GnomeVFSMethod_static,
445 			GNOME_VFS_ERROR_BAD_PARAMETERS);
446 	libntfs_directory = (struct libntfs_directory *)method_handle;
447 	g_return_val_if_fail(libntfs_directory != NULL,
448 			GNOME_VFS_ERROR_BAD_PARAMETERS);
449 	g_return_val_if_fail(file_info != NULL, GNOME_VFS_ERROR_BAD_PARAMETERS);
450 
451 	if (!libntfs_directory->file_info_list) {
452 		int errint;
453 		s64 pos;
454 
455 		pos = 0; /* read from the start; incl. "." and ".." entries */
456 		G_LOCK(libntfs);
457 		errint = ntfs_readdir(libntfs_directory->inode,	/* dir_ni */
458 				&pos,	/* pos */
459 				libntfs_directory,	/* dirent */
460 				(ntfs_filldir_t)libntfs_gnomevfs_read_directory_filldir);	/* filldir */
461 		G_UNLOCK(libntfs);
462 		if (errint)
463 			return GNOME_VFS_ERROR_INTERNAL;
464 
465 		libntfs_directory->file_info_list = g_list_prepend(
466 				libntfs_directory->file_info_list, NULL); /* EOF */
467 		libntfs_directory->file_info_list = g_list_reverse(
468 				libntfs_directory->file_info_list);
469 	}
470 
471 	if (!libntfs_directory->file_info_list->data) {
472 		g_assert(libntfs_directory->file_info_list->next == NULL);
473 		/*
474 		 * Do not clear the list to leave us stuck at EOF - GnomeVFS
475 		 * behaves that way.
476 		 */
477 		errvfsresult = GNOME_VFS_ERROR_EOF;
478 	} else {
479 		/* Cut first list item. */
480 		gnome_vfs_file_info_copy(file_info, /* dest */
481 				libntfs_directory->file_info_list->data); /* src */
482 		gnome_vfs_file_info_unref(
483 				libntfs_directory->file_info_list->data);
484 		libntfs_directory->file_info_list = g_list_delete_link(
485 				libntfs_directory->file_info_list,
486 				libntfs_directory->file_info_list);
487 		errvfsresult = GNOME_VFS_OK;
488 	}
489 	return errvfsresult;
490 }
491 
492 struct libntfs_file {
493 	ntfs_inode *inode;
494 	ntfs_attr *attr;
495 	s64 pos;
496 };
497 
libntfs_open_attr(struct libntfs_file * libntfs_file)498 static GnomeVFSResult libntfs_open_attr(struct libntfs_file *libntfs_file)
499 {
500 	g_return_val_if_fail(libntfs_file != NULL,
501 			GNOME_VFS_ERROR_BAD_PARAMETERS);
502 	g_return_val_if_fail(libntfs_file->inode != NULL,
503 			GNOME_VFS_ERROR_BAD_PARAMETERS);
504 
505 	if (!libntfs_file->attr) {
506 		G_LOCK(libntfs);
507 		libntfs_file->attr = ntfs_attr_open(
508 				libntfs_file->inode,	/* ni */
509 				AT_DATA,	/* type */
510 				AT_UNNAMED,	/* name */
511 				0);	/* name_len */
512 		G_UNLOCK(libntfs);
513 		if (!libntfs_file->attr)
514 			return GNOME_VFS_ERROR_BAD_FILE;
515 		libntfs_file->pos = 0;
516 	}
517 
518 	return GNOME_VFS_OK;
519 }
520 
libntfs_gnomevfs_open(GnomeVFSMethod * method,GnomeVFSMethodHandle ** method_handle_return,GnomeVFSURI * uri,GnomeVFSOpenMode mode,GnomeVFSContext * context)521 static GnomeVFSResult libntfs_gnomevfs_open(GnomeVFSMethod *method,
522 		GnomeVFSMethodHandle **method_handle_return, GnomeVFSURI *uri,
523 		GnomeVFSOpenMode mode,
524 		GnomeVFSContext *context __attribute__((unused)))
525 {
526 	GnomeVFSResult errvfsresult;
527 	ntfs_volume *volume;
528 	ntfs_inode *inode;
529 	struct libntfs_file *libntfs_file;
530 
531 	g_return_val_if_fail(method == &GnomeVFSMethod_static,
532 			GNOME_VFS_ERROR_BAD_PARAMETERS);
533 	g_return_val_if_fail(method_handle_return != NULL,
534 			GNOME_VFS_ERROR_BAD_PARAMETERS);
535 
536 	if (GNOME_VFS_OK != (errvfsresult =
537 			libntfs_gnomevfs_uri_parent_init(&volume, uri)))
538 		return errvfsresult;
539 
540 	if (mode & GNOME_VFS_OPEN_WRITE)
541 		return GNOME_VFS_ERROR_READ_ONLY_FILE_SYSTEM;
542 
543 	if (GNOME_VFS_OK != (errvfsresult =
544 			inode_open_by_pathname(&inode, volume, uri->text)))
545 		return errvfsresult;
546 
547 #ifdef __sun
548 	libntfs_file = g_new(struct libntfs_file, 1);
549 #else /* !__sun */
550 	libntfs_new(libntfs_file);
551 #endif /* __sun */
552 
553 	libntfs_file->inode = inode;
554 	libntfs_file->attr = NULL;
555 
556 	*method_handle_return = (GnomeVFSMethodHandle *)libntfs_file;
557 	return errvfsresult;
558 }
559 
libntfs_gnomevfs_create(GnomeVFSMethod * method,GnomeVFSMethodHandle ** method_handle_return,GnomeVFSURI * uri,GnomeVFSOpenMode mode,gboolean exclusive,guint perm,GnomeVFSContext * context)560 static GnomeVFSResult libntfs_gnomevfs_create(GnomeVFSMethod *method,
561 		GnomeVFSMethodHandle **method_handle_return, GnomeVFSURI *uri,
562 		GnomeVFSOpenMode mode __attribute__((unused)),
563 		gboolean exclusive __attribute__((unused)),
564 		guint perm __attribute__((unused)),
565 		GnomeVFSContext *context __attribute__((unused)))
566 {
567 	GnomeVFSResult errvfsresult;
568 	ntfs_volume *volume;
569 
570 	g_return_val_if_fail(method == &GnomeVFSMethod_static,
571 			GNOME_VFS_ERROR_BAD_PARAMETERS);
572 	g_return_val_if_fail(method_handle_return != NULL,
573 			GNOME_VFS_ERROR_BAD_PARAMETERS);
574 
575 	if (GNOME_VFS_OK != (errvfsresult =
576 			libntfs_gnomevfs_uri_parent_init(&volume, uri)))
577 		return errvfsresult;
578 
579 	return GNOME_VFS_ERROR_READ_ONLY_FILE_SYSTEM;
580 }
581 
libntfs_gnomevfs_close(GnomeVFSMethod * method,GnomeVFSMethodHandle * method_handle,GnomeVFSContext * context)582 static GnomeVFSResult libntfs_gnomevfs_close(GnomeVFSMethod *method,
583 		GnomeVFSMethodHandle *method_handle,
584 		GnomeVFSContext *context __attribute__((unused)))
585 {
586 	struct libntfs_file *libntfs_file;
587 	int errint;
588 
589 	g_return_val_if_fail(method == &GnomeVFSMethod_static,
590 			GNOME_VFS_ERROR_BAD_PARAMETERS);
591 	libntfs_file = (struct libntfs_file *) method_handle;
592 	g_return_val_if_fail(libntfs_file != NULL,
593 			GNOME_VFS_ERROR_BAD_PARAMETERS);
594 
595 	if (libntfs_file->attr) {
596 		G_LOCK(libntfs);
597 		ntfs_attr_close(libntfs_file->attr);
598 		G_UNLOCK(libntfs);
599 	}
600 	G_LOCK(libntfs);
601 	errint = ntfs_inode_close(libntfs_file->inode);
602 	G_UNLOCK(libntfs);
603 	if (errint)
604 		g_return_val_if_reached(GNOME_VFS_ERROR_INTERNAL);
605 
606 	g_free(libntfs_file);
607 
608 	return GNOME_VFS_OK;
609 }
610 
libntfs_gnomevfs_read(GnomeVFSMethod * method,GnomeVFSMethodHandle * method_handle,gpointer buffer,GnomeVFSFileSize num_bytes,GnomeVFSFileSize * bytes_read_return,GnomeVFSContext * context)611 static GnomeVFSResult libntfs_gnomevfs_read(GnomeVFSMethod *method,
612 		GnomeVFSMethodHandle *method_handle, gpointer buffer,
613 		GnomeVFSFileSize num_bytes, GnomeVFSFileSize *bytes_read_return,
614 		GnomeVFSContext *context __attribute__((unused)))
615 {
616 	GnomeVFSResult errvfsresult;
617 	struct libntfs_file *libntfs_file;
618 	s64 count_s64, got;
619 
620 	g_return_val_if_fail(method == &GnomeVFSMethod_static,
621 			GNOME_VFS_ERROR_BAD_PARAMETERS);
622 	libntfs_file = (struct libntfs_file *)method_handle;
623 	g_return_val_if_fail(libntfs_file != NULL,
624 			GNOME_VFS_ERROR_BAD_PARAMETERS);
625 	g_return_val_if_fail(buffer != NULL, GNOME_VFS_ERROR_BAD_PARAMETERS);
626 	g_return_val_if_fail(bytes_read_return != NULL,
627 			GNOME_VFS_ERROR_BAD_PARAMETERS);
628 
629 	if (GNOME_VFS_OK != (errvfsresult = libntfs_open_attr(libntfs_file)))
630 		return errvfsresult;
631 
632 	count_s64 = num_bytes;
633 	g_assert((GnomeVFSFileSize)count_s64 == num_bytes);
634 	G_LOCK(libntfs);
635 	got = ntfs_attr_pread(libntfs_file->attr, libntfs_file->pos, count_s64,
636 			buffer);
637 	G_UNLOCK(libntfs);
638 	if (got == -1)
639 		return GNOME_VFS_ERROR_IO;
640 
641 	libntfs_file->pos += got;
642 	*bytes_read_return = got;
643 	g_assert((s64)*bytes_read_return == got);
644 
645 	return GNOME_VFS_OK;
646 }
647 
libntfs_gnomevfs_seek(GnomeVFSMethod * method,GnomeVFSMethodHandle * method_handle,GnomeVFSSeekPosition whence,GnomeVFSFileOffset offset,GnomeVFSContext * context)648 static GnomeVFSResult libntfs_gnomevfs_seek(GnomeVFSMethod *method,
649 		GnomeVFSMethodHandle *method_handle,
650 		GnomeVFSSeekPosition whence, GnomeVFSFileOffset offset,
651 		GnomeVFSContext *context __attribute__((unused)))
652 {
653 	GnomeVFSResult errvfsresult;
654 	struct libntfs_file *libntfs_file;
655 
656 	g_return_val_if_fail(method == &GnomeVFSMethod_static,
657 			GNOME_VFS_ERROR_BAD_PARAMETERS);
658 	libntfs_file = (struct libntfs_file *)method_handle;
659 	g_return_val_if_fail(libntfs_file != NULL,
660 			GNOME_VFS_ERROR_BAD_PARAMETERS);
661 
662 	if (GNOME_VFS_OK != (errvfsresult = libntfs_open_attr(libntfs_file)))
663 		return errvfsresult;
664 
665 	switch (whence) {
666 	case GNOME_VFS_SEEK_START:
667 		libntfs_file->pos = offset;
668 		break;
669 	case GNOME_VFS_SEEK_CURRENT:
670 		libntfs_file->pos += offset;
671 		break;
672 	case GNOME_VFS_SEEK_END:
673 		/* FIXME: NOT IMPLEMENTED YET */
674 		g_return_val_if_reached(GNOME_VFS_ERROR_BAD_PARAMETERS);
675 	default:
676 		g_assert_not_reached();
677 	}
678 
679 	return GNOME_VFS_OK;
680 }
681 
libntfs_gnomevfs_tell(GnomeVFSMethod * method,GnomeVFSMethodHandle * method_handle,GnomeVFSFileSize * offset_return)682 static GnomeVFSResult libntfs_gnomevfs_tell(GnomeVFSMethod *method,
683 		GnomeVFSMethodHandle *method_handle,
684 		GnomeVFSFileSize *offset_return)
685 {
686 	GnomeVFSResult errvfsresult;
687 	struct libntfs_file *libntfs_file;
688 
689 	g_return_val_if_fail(method == &GnomeVFSMethod_static,
690 			GNOME_VFS_ERROR_BAD_PARAMETERS);
691 	libntfs_file = (struct libntfs_file *)method_handle;
692 	g_return_val_if_fail(libntfs_file != NULL,
693 			GNOME_VFS_ERROR_BAD_PARAMETERS);
694 	g_return_val_if_fail(offset_return != NULL,
695 			GNOME_VFS_ERROR_BAD_PARAMETERS);
696 
697 	if (GNOME_VFS_OK != (errvfsresult = libntfs_open_attr(libntfs_file)))
698 		return errvfsresult;
699 
700 	*offset_return = libntfs_file->pos;
701 	g_assert((s64)*offset_return == libntfs_file->pos);
702 
703 	return errvfsresult;
704 }
705 
libntfs_gnomevfs_is_local(GnomeVFSMethod * method,const GnomeVFSURI * uri)706 static gboolean libntfs_gnomevfs_is_local(GnomeVFSMethod *method,
707 		const GnomeVFSURI *uri)
708 {
709 	g_return_val_if_fail(method == &GnomeVFSMethod_static,
710 			GNOME_VFS_ERROR_BAD_PARAMETERS);
711 	g_return_val_if_fail(uri != NULL, GNOME_VFS_ERROR_BAD_PARAMETERS);
712 
713 	return gnome_vfs_uri_is_local(uri->parent);
714 }
715 
libntfs_gnomevfs_get_file_info_from_handle(GnomeVFSMethod * method,GnomeVFSMethodHandle * method_handle,GnomeVFSFileInfo * file_info,GnomeVFSFileInfoOptions options,GnomeVFSContext * context)716 static GnomeVFSResult libntfs_gnomevfs_get_file_info_from_handle(
717 		GnomeVFSMethod *method, GnomeVFSMethodHandle *method_handle,
718 		GnomeVFSFileInfo *file_info,
719 		GnomeVFSFileInfoOptions options __attribute__((unused)),
720 		GnomeVFSContext *context __attribute__((unused)))
721 {
722 	GnomeVFSResult errvfsresult;
723 	struct libntfs_file *libntfs_file;
724 
725 	g_return_val_if_fail(method == &GnomeVFSMethod_static,
726 			GNOME_VFS_ERROR_BAD_PARAMETERS);
727 	libntfs_file = (struct libntfs_file *)method_handle;
728 	g_return_val_if_fail(libntfs_file != NULL,
729 			GNOME_VFS_ERROR_BAD_PARAMETERS);
730 	g_return_val_if_fail(file_info != NULL, GNOME_VFS_ERROR_BAD_PARAMETERS);
731 	/* handle 'options & GNOME_VFS_FILE_INFO_GET_MIME_TYPE'? */
732 
733 	file_info->valid_fields = 0;
734 	/* FIXME: It is complicated to read filename of open 'ntfs_inode'. */
735 	file_info->name = NULL;
736 
737 	if (GNOME_VFS_OK != (errvfsresult = libntfs_open_attr(libntfs_file))) {
738 		/* Assume we are directory: */
739 		file_info->type = GNOME_VFS_FILE_TYPE_DIRECTORY;
740 		/*
741 		 * Do not: file_info->valid_fields |=
742 		 * GNOME_VFS_FILE_INFO_FIELDS_TYPE;
743 		 * as gnome-vfs-xfer.c/copy_items() does not check
744 		 * 'GNOME_VFS_FILE_INFO_FIELDS_TYPE' and we are just bluffing
745 		 * we know it.
746 		 */
747 		return GNOME_VFS_OK;
748 	}
749 
750 	/* FIXME: Is 'data_size' the right field? */
751 	file_info->size = libntfs_file->attr->data_size;
752 	file_info->valid_fields |= GNOME_VFS_FILE_INFO_FIELDS_SIZE;
753 
754 	/*
755 	 * FIXME: We do not really know the type of 'libntfs_file' but
756 	 * gnome-vfs-xfer.c/copy_items() requires 'GNOME_VFS_FILE_TYPE_REGULAR'
757 	 * to copy it.
758 	 */
759 	file_info->type = GNOME_VFS_FILE_TYPE_REGULAR;
760 	/*
761 	 * Do not: file_info->valid_fields|=GNOME_VFS_FILE_INFO_FIELDS_TYPE;
762 	 * as gnome-vfs-xfer.c/copy_items() does not check
763 	 * 'GNOME_VFS_FILE_INFO_FIELDS_TYPE' and we are just bluffing we know
764 	 * it.
765 	 */
766 
767 	return errvfsresult;
768 }
769 
libntfs_gnomevfs_get_file_info(GnomeVFSMethod * method,GnomeVFSURI * uri,GnomeVFSFileInfo * file_info,GnomeVFSFileInfoOptions options,GnomeVFSContext * context)770 static GnomeVFSResult libntfs_gnomevfs_get_file_info(GnomeVFSMethod *method,
771 		GnomeVFSURI *uri, GnomeVFSFileInfo *file_info,
772 		GnomeVFSFileInfoOptions options, GnomeVFSContext *context)
773 {
774 	GnomeVFSResult errvfsresult;
775 	GnomeVFSMethodHandle *method_handle;
776 
777 	g_return_val_if_fail(method == &GnomeVFSMethod_static,
778 			GNOME_VFS_ERROR_BAD_PARAMETERS);
779 	g_return_val_if_fail(file_info != NULL, GNOME_VFS_ERROR_BAD_PARAMETERS);
780 	/* handle 'options & GNOME_VFS_FILE_INFO_GET_MIME_TYPE'? */
781 
782 	if (GNOME_VFS_OK != (errvfsresult =
783 			libntfs_gnomevfs_open(method, &method_handle, uri,
784 			GNOME_VFS_OPEN_READ, context)))
785 		return errvfsresult;
786 	if (GNOME_VFS_OK != (errvfsresult =
787 			libntfs_gnomevfs_get_file_info_from_handle(method,
788 			method_handle, file_info, options, context)))
789 		return errvfsresult;
790 	if (GNOME_VFS_OK != (errvfsresult =
791 			libntfs_gnomevfs_close(method, method_handle, context)))
792 		return errvfsresult;
793 
794 	return GNOME_VFS_OK;
795 }
796 
libntfs_gnomevfs_check_same_fs(GnomeVFSMethod * method,GnomeVFSURI * a,GnomeVFSURI * b,gboolean * same_fs_return,GnomeVFSContext * context)797 static GnomeVFSResult libntfs_gnomevfs_check_same_fs(GnomeVFSMethod *method,
798 		GnomeVFSURI *a, GnomeVFSURI *b, gboolean *same_fs_return,
799 		GnomeVFSContext *context __attribute__((unused)))
800 {
801 	ntfs_volume *volume_a;
802 	ntfs_volume *volume_b;
803 	GnomeVFSResult errvfsresult;
804 
805 	g_return_val_if_fail(method == &GnomeVFSMethod_static,
806 			GNOME_VFS_ERROR_BAD_PARAMETERS);
807 	g_return_val_if_fail(same_fs_return != NULL,
808 			GNOME_VFS_ERROR_BAD_PARAMETERS);
809 
810 	errvfsresult = libntfs_gnomevfs_uri_parent_init(&volume_a, a);
811 	g_return_val_if_fail(errvfsresult == GNOME_VFS_OK, errvfsresult);
812 
813 	errvfsresult = libntfs_gnomevfs_uri_parent_init(&volume_b, b);
814 	g_return_val_if_fail(errvfsresult == GNOME_VFS_OK, errvfsresult);
815 
816 	*same_fs_return = (volume_a == volume_b);
817 
818 	return GNOME_VFS_OK;
819 }
820 
821 /**
822  * libntfs_gnomevfs_init:
823  *
824  * Returns: Initialized structure of #GnomeVFSMethod with static methods of
825  * libntfs-gnomevfs.
826  */
libntfs_gnomevfs_method_init(const gchar * method_name,const gchar * args)827 GnomeVFSMethod *libntfs_gnomevfs_method_init(const gchar *method_name,
828 		const gchar *args)
829 {
830 	struct method_name_info *method_name_info;
831 
832 	g_return_val_if_fail(method_name != NULL, NULL);
833 	/* 'args' may be NULL if not supplied. */
834 
835 	method_name_hash_init();
836 
837 	G_LOCK(method_name_hash);
838 	method_name_info = g_hash_table_lookup(method_name_hash, method_name);
839 	if (method_name_info && strcmp(method_name_info->args, args))
840 		method_name_info = NULL;
841 	G_UNLOCK(method_name_hash);
842 	if (!method_name_info) {
843 
844 #ifdef __sun
845 		method_name_info = g_new(struct method_name_info, 1);
846 #else /* !__sun */
847 		libntfs_new(method_name_info);
848 #endif /* __sun */
849 
850 		method_name_info->args = g_strdup(args);
851 		G_LOCK(method_name_hash);
852 		g_hash_table_replace(method_name_hash, g_strdup(method_name),
853 				method_name_info);
854 		G_UNLOCK(method_name_hash);
855 	}
856 
857 	G_LOCK(GnomeVFSMethod_static);
858 	LIBNTFS_MEMZERO(&GnomeVFSMethod_static);
859 	GnomeVFSMethod_static.method_table_size = sizeof(GnomeVFSMethod_static);
860 	GnomeVFSMethod_static.open = libntfs_gnomevfs_open;	/* mandatory */
861 	GnomeVFSMethod_static.create = libntfs_gnomevfs_create;	/* mandatory */
862 	GnomeVFSMethod_static.close = libntfs_gnomevfs_close;
863 	GnomeVFSMethod_static.read = libntfs_gnomevfs_read;
864 	GnomeVFSMethod_static.seek = libntfs_gnomevfs_seek;
865 	GnomeVFSMethod_static.tell = libntfs_gnomevfs_tell;
866 	GnomeVFSMethod_static.open_directory = libntfs_gnomevfs_open_directory;
867 	GnomeVFSMethod_static.close_directory =
868 			libntfs_gnomevfs_close_directory;
869 	GnomeVFSMethod_static.read_directory = libntfs_gnomevfs_read_directory;
870 	GnomeVFSMethod_static.get_file_info =
871 			libntfs_gnomevfs_get_file_info;	/* mandatory */
872 	GnomeVFSMethod_static.get_file_info_from_handle =
873 			libntfs_gnomevfs_get_file_info_from_handle;
874 	GnomeVFSMethod_static.is_local =
875 			libntfs_gnomevfs_is_local;	/* mandatory */
876 	GnomeVFSMethod_static.check_same_fs = libntfs_gnomevfs_check_same_fs;
877 	/* TODO: GnomeVFSMethodFindDirectoryFunc find_directory; */
878 	/* TODO: GnomeVFSMethodFileControlFunc file_control; */
879 	/* R/W:  GnomeVFSMethodCreateSymbolicLinkFunc create_symbolic_link; */
880 	/* R/W:  GnomeVFSMethodMonitorAddFunc monitor_add; */
881 	/* R/W:  GnomeVFSMethodMonitorCancelFunc monitor_cancel; */
882 	/* R/W:  GnomeVFSMethod_static.write; */
883 	/* R/W:  GnomeVFSMethod_static.truncate_handle; */
884 	/* R/W:  GnomeVFSMethod_static.make_directory; */
885 	/* R/W:  GnomeVFSMethod_static.remove_directory; */
886 	/* R/W:  GnomeVFSMethod_static.move; */
887 	/* R/W:  GnomeVFSMethod_static.unlink; */
888 	/* R/W:  GnomeVFSMethod_static.set_file_info; */
889 	/* R/W:  GnomeVFSMethod_static.truncate; */
890 	G_UNLOCK(GnomeVFSMethod_static);
891 
892 	return &GnomeVFSMethod_static;
893 }
894 
895 /**
896  * libntfs_gnomevfs_method_shutdown:
897  *
898  * Shutdowns libntfs-gnomevfs successfuly flushing all caches.
899  *
900  * Sad note about gnome-vfs-2.1.5 is that it never calls this function. :-)
901  */
libntfs_gnomevfs_method_shutdown(void)902 void libntfs_gnomevfs_method_shutdown(void)
903 {
904 	uri_parent_string_hash_init();
905 	G_LOCK(uri_parent_string_hash);
906 	g_hash_table_destroy(uri_parent_string_hash);
907 	uri_parent_string_hash = NULL;
908 	G_UNLOCK(uri_parent_string_hash);
909 
910 	method_name_hash_init();
911 	G_LOCK(method_name_hash);
912 	g_hash_table_destroy(method_name_hash);
913 	method_name_hash = NULL;
914 	G_UNLOCK(method_name_hash);
915 }
916 
917