1N/A/*
1N/A * gnome-vfs-method.c - Gnome-VFS init/shutdown implementation of interface to
1N/A * libntfs. Part of the Linux-NTFS project.
1N/A *
1N/A * Copyright (c) 2003 Jan Kratochvil <project-captive@jankratochvil.net>
1N/A * Copyright (c) 2003-2006 Anton Altaparmakov
1N/A *
1N/A * This program/include file is free software; you can redistribute it and/or
1N/A * modify it under the terms of the GNU General Public License as published
1N/A * by the Free Software Foundation; either version 2 of the License, or
1N/A * (at your option) any later version.
1N/A *
1N/A * This program/include file is distributed in the hope that it will be
1N/A * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
1N/A * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1N/A * GNU General Public License for more details.
1N/A *
1N/A * You should have received a copy of the GNU General Public License
1N/A * along with this program (in the main directory of the Linux-NTFS
1N/A * distribution in the file COPYING); if not, write to the Free Software
1N/A * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
1N/A */
1N/A
1N/A#include "config.h"
1N/A
1N/A#undef FALSE
1N/A#undef TRUE
1N/A#include "types.h" /* for 'FALSE'/'TRUE' libntfs definition */
1N/A#define FALSE FALSE
1N/A#define TRUE TRUE
1N/A
1N/A#include "gnome-vfs-method.h" /* self */
1N/A#include <libgnomevfs/gnome-vfs-method.h>
1N/A#include <glib/gmessages.h>
1N/A#include "gnome-vfs-module.h"
1N/A#include <glib/ghash.h>
1N/A#ifdef HAVE_STRING_H
1N/A#include <string.h>
1N/A#endif
1N/A#include <libgnomevfs/gnome-vfs-utils.h>
1N/A
1N/A#include "compat.h"
1N/A#include "volume.h"
1N/A#include "dir.h"
1N/A
1N/Astatic GnomeVFSMethod GnomeVFSMethod_static;
1N/AG_LOCK_DEFINE_STATIC(GnomeVFSMethod_static);
1N/A
1N/A/* map: (gchar *)method_name -> (struct method_name_info *) */
1N/Astatic GHashTable *method_name_hash;
1N/AG_LOCK_DEFINE_STATIC(method_name_hash);
1N/A
1N/A#ifdef __sun
1N/AG_LOCK_DEFINE(libntfs);
1N/A#endif
1N/A
1N/Astruct method_name_info {
1N/A gchar *args;
1N/A};
1N/A
1N/Astatic void method_name_hash_key_destroy_func(gchar *key)
1N/A{
1N/A g_return_if_fail(key != NULL);
1N/A
1N/A g_free(key);
1N/A}
1N/A
1N/Astatic void method_name_hash_value_destroy_func(struct method_name_info *value)
1N/A{
1N/A g_return_if_fail(value != NULL);
1N/A
1N/A g_free(value->args);
1N/A g_free(value);
1N/A}
1N/A
1N/Astatic void method_name_hash_init(void)
1N/A{
1N/A G_LOCK(method_name_hash);
1N/A if (!method_name_hash) {
1N/A method_name_hash = g_hash_table_new_full(
1N/A g_str_hash, /* hash_func */
1N/A g_str_equal, /* key_equal_func */
1N/A (GDestroyNotify) method_name_hash_key_destroy_func, /* key_destroy_func */
1N/A (GDestroyNotify) method_name_hash_value_destroy_func); /* value_destroy_func */
1N/A }
1N/A G_UNLOCK(method_name_hash);
1N/A}
1N/A
1N/A/*
1N/A * map: (gchar *)uri_parent_string "method_name:uri_parent" -> (ntfs_volume *)
1N/A */
1N/Astatic GHashTable *uri_parent_string_hash;
1N/AG_LOCK_DEFINE_STATIC(uri_parent_string_hash);
1N/A
1N/Astatic void uri_parent_string_hash_key_destroy_func(gchar *key)
1N/A{
1N/A g_return_if_fail(key != NULL);
1N/A
1N/A g_free(key);
1N/A}
1N/A
1N/Astatic void uri_parent_string_hash_value_destroy_func(ntfs_volume *value)
1N/A{
1N/A g_return_if_fail(value != NULL);
1N/A
1N/A ntfs_umount( /* errors ignored */
1N/A value, /* vol */
1N/A TRUE); /* force; possibly lose modifications */
1N/A}
1N/A
1N/Astatic void uri_parent_string_hash_init(void)
1N/A{
1N/A G_LOCK(uri_parent_string_hash);
1N/A if (!uri_parent_string_hash) {
1N/A uri_parent_string_hash = g_hash_table_new_full(
1N/A g_str_hash, /* hash_func */
1N/A g_str_equal, /* key_equal_func */
1N/A (GDestroyNotify) uri_parent_string_hash_key_destroy_func, /* key_destroy_func */
1N/A (GDestroyNotify) uri_parent_string_hash_value_destroy_func); /* value_destroy_func */
1N/A }
1N/A G_UNLOCK(uri_parent_string_hash);
1N/A}
1N/A
1N/Astatic GnomeVFSResult libntfs_gnomevfs_uri_parent_init(
1N/A ntfs_volume **volume_return, GnomeVFSURI *uri)
1N/A{
1N/A gchar *uri_parent_string;
1N/A gchar *uri_parent_string_parent;
1N/A ntfs_volume *volume;
1N/A
1N/A g_return_val_if_fail(uri != NULL, GNOME_VFS_ERROR_INVALID_URI);
1N/A g_return_val_if_fail(volume_return != NULL,
1N/A GNOME_VFS_ERROR_BAD_PARAMETERS);
1N/A
1N/A uri_parent_string_hash_init();
1N/A
1N/A if (!uri->parent)
1N/A return GNOME_VFS_ERROR_INVALID_URI;
1N/A if (!uri->text) /* not needed here but we don't permit non-specific fs-image reference */
1N/A return GNOME_VFS_ERROR_INVALID_URI;
1N/A uri_parent_string_parent = gnome_vfs_uri_to_string(uri->parent,
1N/A GNOME_VFS_URI_HIDE_NONE);
1N/A g_assert(uri_parent_string_parent != NULL);
1N/A
1N/A uri_parent_string = g_strdup_printf("%s:%s", uri->method_string,
1N/A uri_parent_string_parent);
1N/A g_assert(uri_parent_string != NULL);
1N/A
1N/A G_LOCK(uri_parent_string_hash);
1N/A volume = g_hash_table_lookup(uri_parent_string_hash, uri_parent_string);
1N/A G_UNLOCK(uri_parent_string_hash);
1N/A if (!volume) {
1N/A struct method_name_info *method_name_info;
1N/A
1N/A G_LOCK(method_name_hash);
1N/A method_name_info = g_hash_table_lookup(method_name_hash,
1N/A uri->method_string);
1N/A G_UNLOCK(method_name_hash);
1N/A if (!method_name_info) {
1N/A /* should not happend */
1N/A g_return_val_if_reached(GNOME_VFS_ERROR_INVALID_URI);
1N/A }
1N/A
1N/A /* TODO: Generic GnomeVFS filter. */
1N/A if (strcmp(uri->parent->method_string, "file")) {
1N/A g_free(uri_parent_string);
1N/A return GNOME_VFS_ERROR_INVALID_URI;
1N/A }
1N/A
1N/A if (!(volume = ntfs_mount(uri->parent->text,
1N/A NTFS_MNT_RDONLY))) {
1N/A g_free(uri_parent_string);
1N/A return GNOME_VFS_ERROR_WRONG_FORMAT;
1N/A }
1N/A
1N/A G_LOCK(uri_parent_string_hash);
1N/A g_hash_table_insert(uri_parent_string_hash,
1N/A g_strdup(uri_parent_string), volume);
1N/A G_UNLOCK(uri_parent_string_hash);
1N/A }
1N/A g_free(uri_parent_string);
1N/A
1N/A *volume_return = volume;
1N/A return GNOME_VFS_OK;
1N/A}
1N/A
1N/Astatic GnomeVFSResult inode_open_by_pathname(ntfs_inode **inode_return,
1N/A ntfs_volume *volume, const gchar *pathname)
1N/A{
1N/A MFT_REF mref;
1N/A ntfs_inode *inode;
1N/A gchar *pathname_parse, *pathname_next;
1N/A int errint;
1N/A
1N/A g_return_val_if_fail(inode_return != NULL,
1N/A GNOME_VFS_ERROR_BAD_PARAMETERS);
1N/A g_return_val_if_fail(volume != NULL, GNOME_VFS_ERROR_BAD_PARAMETERS);
1N/A g_return_val_if_fail(pathname != NULL, GNOME_VFS_ERROR_BAD_PARAMETERS);
1N/A
1N/A pathname = g_path_skip_root(pathname);
1N/A pathname_parse = g_alloca(strlen(pathname) + 1);
1N/A strcpy(pathname_parse, pathname);
1N/A mref = FILE_root;
1N/A for (;;) {
1N/A ntfschar *pathname_parse_ucs2;
1N/A gchar *pathname_parse_unescaped;
1N/A int i;
1N/A
1N/A G_LOCK(libntfs);
1N/A inode = ntfs_inode_open(volume, mref);
1N/A G_UNLOCK(libntfs);
1N/A if (!inode)
1N/A return GNOME_VFS_ERROR_NOT_FOUND;
1N/A if (!*pathname_parse) {
1N/A *inode_return = inode;
1N/A return GNOME_VFS_OK;
1N/A }
1N/A for (pathname_next = pathname_parse; *pathname_next &&
1N/A *pathname_next != G_DIR_SEPARATOR; pathname_next++) ;
1N/A if (*pathname_next) {
1N/A /* terminate current path element */
1N/A *pathname_next++ = 0;
1N/A }
1N/A while (*pathname_next == G_DIR_SEPARATOR)
1N/A pathname_next++;
1N/A /* FIXME: Is 'pathname' utf8? */
1N/A pathname_parse_unescaped = gnome_vfs_unescape_string(
1N/A pathname_parse, NULL); /* illegal_characters */
1N/A#ifdef __sun
1N/A pathname_parse_ucs2 = g_malloc(strlen(pathname_parse_unescaped) + 1);
1N/A#else /* !__sun */
1N/A libntfs_newn(pathname_parse_ucs2,
1N/A strlen(pathname_parse_unescaped) + 1);
1N/A#endif /* __sun */
1N/A for (i = 0; pathname_parse_unescaped[i]; i++)
1N/A pathname_parse_ucs2[i] = cpu_to_le16(
1N/A pathname_parse_unescaped[i]);
1N/A pathname_parse_ucs2[i] = 0;
1N/A g_free(pathname_parse_unescaped);
1N/A G_LOCK(libntfs);
1N/A mref = ntfs_inode_lookup_by_name(inode, pathname_parse_ucs2, i);
1N/A G_UNLOCK(libntfs);
1N/A g_free(pathname_parse_ucs2);
1N/A if ((MFT_REF)-1 == mref)
1N/A return GNOME_VFS_ERROR_NOT_FOUND;
1N/A G_LOCK(libntfs);
1N/A errint = ntfs_inode_close(inode);
1N/A G_UNLOCK(libntfs);
1N/A if (errint)
1N/A g_return_val_if_reached(GNOME_VFS_ERROR_INTERNAL);
1N/A pathname_parse = pathname_next;
1N/A }
1N/A /* NOTREACHED */
1N/A}
1N/A
1N/Astruct libntfs_directory {
1N/A ntfs_inode *inode;
1N/A GList *file_info_list; /* of (GnomeVFSFileInfo *); last item has ->data == NULL */
1N/A};
1N/A
1N/Astatic GnomeVFSResult libntfs_gnomevfs_open_directory(GnomeVFSMethod *method,
1N/A GnomeVFSMethodHandle **method_handle, GnomeVFSURI *uri,
1N/A GnomeVFSFileInfoOptions options __attribute__((unused)),
1N/A GnomeVFSContext *context __attribute__((unused)))
1N/A{
1N/A GnomeVFSResult errvfsresult;
1N/A ntfs_volume *volume;
1N/A ntfs_inode *inode;
1N/A struct libntfs_directory *libntfs_directory;
1N/A
1N/A g_return_val_if_fail(method == &GnomeVFSMethod_static,
1N/A GNOME_VFS_ERROR_BAD_PARAMETERS);
1N/A g_return_val_if_fail(method_handle != NULL,
1N/A GNOME_VFS_ERROR_BAD_PARAMETERS);
1N/A
1N/A if (GNOME_VFS_OK != (errvfsresult =
1N/A libntfs_gnomevfs_uri_parent_init(&volume, uri)))
1N/A return errvfsresult;
1N/A
1N/A if (GNOME_VFS_OK != (errvfsresult = inode_open_by_pathname(&inode,
1N/A volume, uri->text)))
1N/A return errvfsresult;
1N/A
1N/A#ifdef __sun
1N/A libntfs_directory = g_new(struct libntfs_directory, 1);
1N/A#else /* !__sun */
1N/A libntfs_new(libntfs_directory);
1N/A#endif /* __sun */
1N/A
1N/A libntfs_directory->inode = inode;
1N/A libntfs_directory->file_info_list = NULL;
1N/A
1N/A *method_handle = (GnomeVFSMethodHandle *)libntfs_directory;
1N/A return errvfsresult;
1N/A}
1N/A
1N/Astatic GnomeVFSResult libntfs_gnomevfs_close_directory(GnomeVFSMethod *method,
1N/A GnomeVFSMethodHandle *method_handle,
1N/A GnomeVFSContext *context __attribute__((unused)))
1N/A{
1N/A struct libntfs_directory *libntfs_directory;
1N/A int errint;
1N/A
1N/A g_return_val_if_fail(method == &GnomeVFSMethod_static,
1N/A GNOME_VFS_ERROR_BAD_PARAMETERS);
1N/A libntfs_directory = (struct libntfs_directory *)method_handle;
1N/A g_return_val_if_fail(libntfs_directory != NULL,
1N/A GNOME_VFS_ERROR_BAD_PARAMETERS);
1N/A
1N/A G_LOCK(libntfs);
1N/A errint = ntfs_inode_close(libntfs_directory->inode);
1N/A G_UNLOCK(libntfs);
1N/A if (errint)
1N/A g_return_val_if_reached(GNOME_VFS_ERROR_INTERNAL);
1N/A
1N/A if (libntfs_directory->file_info_list) {
1N/A GList *last_l;
1N/A
1N/A /*
1N/A * Prevent gnome_vfs_file_info_list_free() and its
1N/A * gnome_vfs_file_info_unref() on the last 'file_info_list'
1N/A * items as it is EOF with NULL '->data'.
1N/A */
1N/A last_l = g_list_last(libntfs_directory->file_info_list);
1N/A g_assert(last_l->data == NULL);
1N/A libntfs_directory->file_info_list = g_list_delete_link(
1N/A libntfs_directory->file_info_list, last_l);
1N/A gnome_vfs_file_info_list_free(
1N/A libntfs_directory->file_info_list);
1N/A }
1N/A
1N/A g_free(libntfs_directory);
1N/A
1N/A return GNOME_VFS_OK;
1N/A}
1N/A
1N/Astatic gchar *libntfs_ntfscharo_utf8(const ntfschar *name, const int name_len)
1N/A{
1N/A GString *gstring;
1N/A int i;
1N/A
1N/A gstring = g_string_sized_new(name_len);
1N/A for (i = 0; i < name_len; i++)
1N/A gstring = g_string_append_unichar(gstring,
1N/A le16_to_cpu(name[i]));
1N/A return g_string_free(gstring, /* returns utf8-formatted string */
1N/A FALSE); /* free_segment */
1N/A}
1N/A
1N/A/*
1N/A * Do not lock 'libntfs' here as we are already locked inside ntfs_readdir().
1N/A */
1N/Astatic int libntfs_gnomevfs_read_directory_filldir(
1N/A struct libntfs_directory *libntfs_directory /* dirent */,
1N/A const ntfschar *name, const int name_len,
1N/A const int name_type __attribute__((unused)),
1N/A const s64 pos, const MFT_REF mref, const unsigned dt_type)
1N/A{
1N/A GnomeVFSFileInfo *file_info;
1N/A
1N/A g_return_val_if_fail(libntfs_directory != NULL, -1);
1N/A g_return_val_if_fail(name != NULL, -1);
1N/A g_return_val_if_fail(name_len >= 0, -1);
1N/A g_return_val_if_fail(pos >= 0, -1);
1N/A
1N/A /* system directory */
1N/A if (MREF(mref) != FILE_root && MREF(mref) < FILE_first_user)
1N/A return 0; /* continue traversal */
1N/A
1N/A file_info = gnome_vfs_file_info_new();
1N/A file_info->name = libntfs_ntfscharo_utf8(name, name_len);
1N/A file_info->valid_fields = 0;
1N/A
1N/A switch (dt_type) {
1N/A case NTFS_DT_FIFO:
1N/A file_info->type = GNOME_VFS_FILE_TYPE_FIFO;
1N/A break;
1N/A case NTFS_DT_CHR:
1N/A file_info->type = GNOME_VFS_FILE_TYPE_CHARACTER_DEVICE;
1N/A break;
1N/A case NTFS_DT_DIR:
1N/A file_info->type = GNOME_VFS_FILE_TYPE_DIRECTORY;
1N/A break;
1N/A case NTFS_DT_BLK:
1N/A file_info->type = GNOME_VFS_FILE_TYPE_BLOCK_DEVICE;
1N/A break;
1N/A case NTFS_DT_REG:
1N/A file_info->type = GNOME_VFS_FILE_TYPE_REGULAR;
1N/A break;
1N/A case NTFS_DT_LNK:
1N/A file_info->type = GNOME_VFS_FILE_TYPE_SYMBOLIC_LINK;
1N/A break;
1N/A case NTFS_DT_SOCK:
1N/A file_info->type = GNOME_VFS_FILE_TYPE_SOCKET;
1N/A break;
1N/A /* FIXME: What is 'NTFS_DT_WHT'? */
1N/A default:
1N/A file_info->type = GNOME_VFS_FILE_TYPE_UNKNOWN;
1N/A }
1N/A if (file_info->type != GNOME_VFS_FILE_TYPE_UNKNOWN)
1N/A file_info->valid_fields |= GNOME_VFS_FILE_INFO_FIELDS_TYPE;
1N/A
1N/A /* Detect 'file_info->size': */
1N/A if (file_info->type == GNOME_VFS_FILE_TYPE_REGULAR) {
1N/A ntfs_inode *inode;
1N/A
1N/A inode = ntfs_inode_open(libntfs_directory->inode->vol, mref);
1N/A /* FIXME: Check failed 'inode' open. */
1N/A if (inode) {
1N/A ntfs_attr *attr;
1N/A int errint;
1N/A
1N/A attr = ntfs_attr_open(inode, /* ni */
1N/A AT_DATA, /* type */
1N/A AT_UNNAMED, /* name */
1N/A 0); /* name_len */
1N/A /* FIXME: Check failed 'attr' open. */
1N/A if (attr) {
1N/A /* FIXME: Is 'data_size' the right field? */
1N/A file_info->size = attr->data_size;
1N/A file_info->valid_fields |=
1N/A GNOME_VFS_FILE_INFO_FIELDS_SIZE;
1N/A ntfs_attr_close(attr);
1N/A }
1N/A errint = ntfs_inode_close(inode);
1N/A /* FIXME: Check 'errint'. */
1N/A }
1N/A }
1N/A
1N/A libntfs_directory->file_info_list = g_list_prepend(
1N/A libntfs_directory->file_info_list, file_info);
1N/A
1N/A return 0; /* continue traversal */
1N/A}
1N/A
1N/Astatic GnomeVFSResult libntfs_gnomevfs_read_directory(GnomeVFSMethod *method,
1N/A GnomeVFSMethodHandle *method_handle,
1N/A GnomeVFSFileInfo *file_info,
1N/A GnomeVFSContext *context __attribute__((unused)))
1N/A{
1N/A GnomeVFSResult errvfsresult;
1N/A struct libntfs_directory *libntfs_directory;
1N/A
1N/A g_return_val_if_fail(method == &GnomeVFSMethod_static,
1N/A GNOME_VFS_ERROR_BAD_PARAMETERS);
1N/A libntfs_directory = (struct libntfs_directory *)method_handle;
1N/A g_return_val_if_fail(libntfs_directory != NULL,
1N/A GNOME_VFS_ERROR_BAD_PARAMETERS);
1N/A g_return_val_if_fail(file_info != NULL, GNOME_VFS_ERROR_BAD_PARAMETERS);
1N/A
1N/A if (!libntfs_directory->file_info_list) {
1N/A int errint;
1N/A s64 pos;
1N/A
1N/A pos = 0; /* read from the start; incl. "." and ".." entries */
1N/A G_LOCK(libntfs);
1N/A errint = ntfs_readdir(libntfs_directory->inode, /* dir_ni */
1N/A &pos, /* pos */
1N/A libntfs_directory, /* dirent */
1N/A (ntfs_filldir_t)libntfs_gnomevfs_read_directory_filldir); /* filldir */
1N/A G_UNLOCK(libntfs);
1N/A if (errint)
1N/A return GNOME_VFS_ERROR_INTERNAL;
1N/A
1N/A libntfs_directory->file_info_list = g_list_prepend(
1N/A libntfs_directory->file_info_list, NULL); /* EOF */
1N/A libntfs_directory->file_info_list = g_list_reverse(
1N/A libntfs_directory->file_info_list);
1N/A }
1N/A
1N/A if (!libntfs_directory->file_info_list->data) {
1N/A g_assert(libntfs_directory->file_info_list->next == NULL);
1N/A /*
1N/A * Do not clear the list to leave us stuck at EOF - GnomeVFS
1N/A * behaves that way.
1N/A */
1N/A errvfsresult = GNOME_VFS_ERROR_EOF;
1N/A } else {
1N/A /* Cut first list item. */
1N/A gnome_vfs_file_info_copy(file_info, /* dest */
1N/A libntfs_directory->file_info_list->data); /* src */
1N/A gnome_vfs_file_info_unref(
1N/A libntfs_directory->file_info_list->data);
1N/A libntfs_directory->file_info_list = g_list_delete_link(
1N/A libntfs_directory->file_info_list,
1N/A libntfs_directory->file_info_list);
1N/A errvfsresult = GNOME_VFS_OK;
1N/A }
1N/A return errvfsresult;
1N/A}
1N/A
1N/Astruct libntfs_file {
1N/A ntfs_inode *inode;
1N/A ntfs_attr *attr;
1N/A s64 pos;
1N/A};
1N/A
1N/Astatic GnomeVFSResult libntfs_open_attr(struct libntfs_file *libntfs_file)
1N/A{
1N/A g_return_val_if_fail(libntfs_file != NULL,
1N/A GNOME_VFS_ERROR_BAD_PARAMETERS);
1N/A g_return_val_if_fail(libntfs_file->inode != NULL,
1N/A GNOME_VFS_ERROR_BAD_PARAMETERS);
1N/A
1N/A if (!libntfs_file->attr) {
1N/A G_LOCK(libntfs);
1N/A libntfs_file->attr = ntfs_attr_open(
1N/A libntfs_file->inode, /* ni */
1N/A AT_DATA, /* type */
1N/A AT_UNNAMED, /* name */
1N/A 0); /* name_len */
1N/A G_UNLOCK(libntfs);
1N/A if (!libntfs_file->attr)
1N/A return GNOME_VFS_ERROR_BAD_FILE;
1N/A libntfs_file->pos = 0;
1N/A }
1N/A
1N/A return GNOME_VFS_OK;
1N/A}
1N/A
1N/Astatic GnomeVFSResult libntfs_gnomevfs_open(GnomeVFSMethod *method,
1N/A GnomeVFSMethodHandle **method_handle_return, GnomeVFSURI *uri,
1N/A GnomeVFSOpenMode mode,
1N/A GnomeVFSContext *context __attribute__((unused)))
1N/A{
1N/A GnomeVFSResult errvfsresult;
1N/A ntfs_volume *volume;
1N/A ntfs_inode *inode;
1N/A struct libntfs_file *libntfs_file;
1N/A
1N/A g_return_val_if_fail(method == &GnomeVFSMethod_static,
1N/A GNOME_VFS_ERROR_BAD_PARAMETERS);
1N/A g_return_val_if_fail(method_handle_return != NULL,
1N/A GNOME_VFS_ERROR_BAD_PARAMETERS);
1N/A
1N/A if (GNOME_VFS_OK != (errvfsresult =
1N/A libntfs_gnomevfs_uri_parent_init(&volume, uri)))
1N/A return errvfsresult;
1N/A
1N/A if (mode & GNOME_VFS_OPEN_WRITE)
1N/A return GNOME_VFS_ERROR_READ_ONLY_FILE_SYSTEM;
1N/A
1N/A if (GNOME_VFS_OK != (errvfsresult =
1N/A inode_open_by_pathname(&inode, volume, uri->text)))
1N/A return errvfsresult;
1N/A
1N/A#ifdef __sun
1N/A libntfs_file = g_new(struct libntfs_file, 1);
1N/A#else /* !__sun */
1N/A libntfs_new(libntfs_file);
1N/A#endif /* __sun */
1N/A
1N/A libntfs_file->inode = inode;
1N/A libntfs_file->attr = NULL;
1N/A
1N/A *method_handle_return = (GnomeVFSMethodHandle *)libntfs_file;
1N/A return errvfsresult;
1N/A}
1N/A
1N/Astatic GnomeVFSResult libntfs_gnomevfs_create(GnomeVFSMethod *method,
1N/A GnomeVFSMethodHandle **method_handle_return, GnomeVFSURI *uri,
1N/A GnomeVFSOpenMode mode __attribute__((unused)),
1N/A gboolean exclusive __attribute__((unused)),
1N/A guint perm __attribute__((unused)),
1N/A GnomeVFSContext *context __attribute__((unused)))
1N/A{
1N/A GnomeVFSResult errvfsresult;
1N/A ntfs_volume *volume;
1N/A
1N/A g_return_val_if_fail(method == &GnomeVFSMethod_static,
1N/A GNOME_VFS_ERROR_BAD_PARAMETERS);
1N/A g_return_val_if_fail(method_handle_return != NULL,
1N/A GNOME_VFS_ERROR_BAD_PARAMETERS);
1N/A
1N/A if (GNOME_VFS_OK != (errvfsresult =
1N/A libntfs_gnomevfs_uri_parent_init(&volume, uri)))
1N/A return errvfsresult;
1N/A
1N/A return GNOME_VFS_ERROR_READ_ONLY_FILE_SYSTEM;
1N/A}
1N/A
1N/Astatic GnomeVFSResult libntfs_gnomevfs_close(GnomeVFSMethod *method,
1N/A GnomeVFSMethodHandle *method_handle,
1N/A GnomeVFSContext *context __attribute__((unused)))
1N/A{
1N/A struct libntfs_file *libntfs_file;
1N/A int errint;
1N/A
1N/A g_return_val_if_fail(method == &GnomeVFSMethod_static,
1N/A GNOME_VFS_ERROR_BAD_PARAMETERS);
1N/A libntfs_file = (struct libntfs_file *) method_handle;
1N/A g_return_val_if_fail(libntfs_file != NULL,
1N/A GNOME_VFS_ERROR_BAD_PARAMETERS);
1N/A
1N/A if (libntfs_file->attr) {
1N/A G_LOCK(libntfs);
1N/A ntfs_attr_close(libntfs_file->attr);
1N/A G_UNLOCK(libntfs);
1N/A }
1N/A G_LOCK(libntfs);
1N/A errint = ntfs_inode_close(libntfs_file->inode);
1N/A G_UNLOCK(libntfs);
1N/A if (errint)
1N/A g_return_val_if_reached(GNOME_VFS_ERROR_INTERNAL);
1N/A
1N/A g_free(libntfs_file);
1N/A
1N/A return GNOME_VFS_OK;
1N/A}
1N/A
1N/Astatic GnomeVFSResult libntfs_gnomevfs_read(GnomeVFSMethod *method,
1N/A GnomeVFSMethodHandle *method_handle, gpointer buffer,
1N/A GnomeVFSFileSize num_bytes, GnomeVFSFileSize *bytes_read_return,
1N/A GnomeVFSContext *context __attribute__((unused)))
1N/A{
1N/A GnomeVFSResult errvfsresult;
1N/A struct libntfs_file *libntfs_file;
1N/A s64 count_s64, got;
1N/A
1N/A g_return_val_if_fail(method == &GnomeVFSMethod_static,
1N/A GNOME_VFS_ERROR_BAD_PARAMETERS);
1N/A libntfs_file = (struct libntfs_file *)method_handle;
1N/A g_return_val_if_fail(libntfs_file != NULL,
1N/A GNOME_VFS_ERROR_BAD_PARAMETERS);
1N/A g_return_val_if_fail(buffer != NULL, GNOME_VFS_ERROR_BAD_PARAMETERS);
1N/A g_return_val_if_fail(bytes_read_return != NULL,
1N/A GNOME_VFS_ERROR_BAD_PARAMETERS);
1N/A
1N/A if (GNOME_VFS_OK != (errvfsresult = libntfs_open_attr(libntfs_file)))
1N/A return errvfsresult;
1N/A
1N/A count_s64 = num_bytes;
1N/A g_assert((GnomeVFSFileSize)count_s64 == num_bytes);
1N/A G_LOCK(libntfs);
1N/A got = ntfs_attr_pread(libntfs_file->attr, libntfs_file->pos, count_s64,
1N/A buffer);
1N/A G_UNLOCK(libntfs);
1N/A if (got == -1)
1N/A return GNOME_VFS_ERROR_IO;
1N/A
1N/A libntfs_file->pos += got;
1N/A *bytes_read_return = got;
1N/A g_assert((s64)*bytes_read_return == got);
1N/A
1N/A return GNOME_VFS_OK;
1N/A}
1N/A
1N/Astatic GnomeVFSResult libntfs_gnomevfs_seek(GnomeVFSMethod *method,
1N/A GnomeVFSMethodHandle *method_handle,
1N/A GnomeVFSSeekPosition whence, GnomeVFSFileOffset offset,
1N/A GnomeVFSContext *context __attribute__((unused)))
1N/A{
1N/A GnomeVFSResult errvfsresult;
1N/A struct libntfs_file *libntfs_file;
1N/A
1N/A g_return_val_if_fail(method == &GnomeVFSMethod_static,
1N/A GNOME_VFS_ERROR_BAD_PARAMETERS);
1N/A libntfs_file = (struct libntfs_file *)method_handle;
1N/A g_return_val_if_fail(libntfs_file != NULL,
1N/A GNOME_VFS_ERROR_BAD_PARAMETERS);
1N/A
1N/A if (GNOME_VFS_OK != (errvfsresult = libntfs_open_attr(libntfs_file)))
1N/A return errvfsresult;
1N/A
1N/A switch (whence) {
1N/A case GNOME_VFS_SEEK_START:
1N/A libntfs_file->pos = offset;
1N/A break;
1N/A case GNOME_VFS_SEEK_CURRENT:
1N/A libntfs_file->pos += offset;
1N/A break;
1N/A case GNOME_VFS_SEEK_END:
1N/A /* FIXME: NOT IMPLEMENTED YET */
1N/A g_return_val_if_reached(GNOME_VFS_ERROR_BAD_PARAMETERS);
1N/A default:
1N/A g_assert_not_reached();
1N/A }
1N/A
1N/A return GNOME_VFS_OK;
1N/A}
1N/A
1N/Astatic GnomeVFSResult libntfs_gnomevfs_tell(GnomeVFSMethod *method,
1N/A GnomeVFSMethodHandle *method_handle,
1N/A GnomeVFSFileSize *offset_return)
1N/A{
1N/A GnomeVFSResult errvfsresult;
1N/A struct libntfs_file *libntfs_file;
1N/A
1N/A g_return_val_if_fail(method == &GnomeVFSMethod_static,
1N/A GNOME_VFS_ERROR_BAD_PARAMETERS);
1N/A libntfs_file = (struct libntfs_file *)method_handle;
1N/A g_return_val_if_fail(libntfs_file != NULL,
1N/A GNOME_VFS_ERROR_BAD_PARAMETERS);
1N/A g_return_val_if_fail(offset_return != NULL,
1N/A GNOME_VFS_ERROR_BAD_PARAMETERS);
1N/A
1N/A if (GNOME_VFS_OK != (errvfsresult = libntfs_open_attr(libntfs_file)))
1N/A return errvfsresult;
1N/A
1N/A *offset_return = libntfs_file->pos;
1N/A g_assert((s64)*offset_return == libntfs_file->pos);
1N/A
1N/A return errvfsresult;
1N/A}
1N/A
1N/Astatic gboolean libntfs_gnomevfs_is_local(GnomeVFSMethod *method,
1N/A const GnomeVFSURI *uri)
1N/A{
1N/A g_return_val_if_fail(method == &GnomeVFSMethod_static,
1N/A GNOME_VFS_ERROR_BAD_PARAMETERS);
1N/A g_return_val_if_fail(uri != NULL, GNOME_VFS_ERROR_BAD_PARAMETERS);
1N/A
1N/A return gnome_vfs_uri_is_local(uri->parent);
1N/A}
1N/A
1N/Astatic GnomeVFSResult libntfs_gnomevfs_get_file_info_from_handle(
1N/A GnomeVFSMethod *method, GnomeVFSMethodHandle *method_handle,
1N/A GnomeVFSFileInfo *file_info,
1N/A GnomeVFSFileInfoOptions options __attribute__((unused)),
1N/A GnomeVFSContext *context __attribute__((unused)))
1N/A{
1N/A GnomeVFSResult errvfsresult;
1N/A struct libntfs_file *libntfs_file;
1N/A
1N/A g_return_val_if_fail(method == &GnomeVFSMethod_static,
1N/A GNOME_VFS_ERROR_BAD_PARAMETERS);
1N/A libntfs_file = (struct libntfs_file *)method_handle;
1N/A g_return_val_if_fail(libntfs_file != NULL,
1N/A GNOME_VFS_ERROR_BAD_PARAMETERS);
1N/A g_return_val_if_fail(file_info != NULL, GNOME_VFS_ERROR_BAD_PARAMETERS);
1N/A /* handle 'options & GNOME_VFS_FILE_INFO_GET_MIME_TYPE'? */
1N/A
1N/A file_info->valid_fields = 0;
1N/A /* FIXME: It is complicated to read filename of open 'ntfs_inode'. */
1N/A file_info->name = NULL;
1N/A
1N/A if (GNOME_VFS_OK != (errvfsresult = libntfs_open_attr(libntfs_file))) {
1N/A /* Assume we are directory: */
1N/A file_info->type = GNOME_VFS_FILE_TYPE_DIRECTORY;
1N/A /*
1N/A * Do not: file_info->valid_fields |=
1N/A * GNOME_VFS_FILE_INFO_FIELDS_TYPE;
1N/A * as gnome-vfs-xfer.c/copy_items() does not check
1N/A * 'GNOME_VFS_FILE_INFO_FIELDS_TYPE' and we are just bluffing
1N/A * we know it.
1N/A */
1N/A return GNOME_VFS_OK;
1N/A }
1N/A
1N/A /* FIXME: Is 'data_size' the right field? */
1N/A file_info->size = libntfs_file->attr->data_size;
1N/A file_info->valid_fields |= GNOME_VFS_FILE_INFO_FIELDS_SIZE;
1N/A
1N/A /*
1N/A * FIXME: We do not really know the type of 'libntfs_file' but
1N/A * gnome-vfs-xfer.c/copy_items() requires 'GNOME_VFS_FILE_TYPE_REGULAR'
1N/A * to copy it.
1N/A */
1N/A file_info->type = GNOME_VFS_FILE_TYPE_REGULAR;
1N/A /*
1N/A * Do not: file_info->valid_fields|=GNOME_VFS_FILE_INFO_FIELDS_TYPE;
1N/A * as gnome-vfs-xfer.c/copy_items() does not check
1N/A * 'GNOME_VFS_FILE_INFO_FIELDS_TYPE' and we are just bluffing we know
1N/A * it.
1N/A */
1N/A
1N/A return errvfsresult;
1N/A}
1N/A
1N/Astatic GnomeVFSResult libntfs_gnomevfs_get_file_info(GnomeVFSMethod *method,
1N/A GnomeVFSURI *uri, GnomeVFSFileInfo *file_info,
1N/A GnomeVFSFileInfoOptions options, GnomeVFSContext *context)
1N/A{
1N/A GnomeVFSResult errvfsresult;
1N/A GnomeVFSMethodHandle *method_handle;
1N/A
1N/A g_return_val_if_fail(method == &GnomeVFSMethod_static,
1N/A GNOME_VFS_ERROR_BAD_PARAMETERS);
1N/A g_return_val_if_fail(file_info != NULL, GNOME_VFS_ERROR_BAD_PARAMETERS);
1N/A /* handle 'options & GNOME_VFS_FILE_INFO_GET_MIME_TYPE'? */
1N/A
1N/A if (GNOME_VFS_OK != (errvfsresult =
1N/A libntfs_gnomevfs_open(method, &method_handle, uri,
1N/A GNOME_VFS_OPEN_READ, context)))
1N/A return errvfsresult;
1N/A if (GNOME_VFS_OK != (errvfsresult =
1N/A libntfs_gnomevfs_get_file_info_from_handle(method,
1N/A method_handle, file_info, options, context)))
1N/A return errvfsresult;
1N/A if (GNOME_VFS_OK != (errvfsresult =
1N/A libntfs_gnomevfs_close(method, method_handle, context)))
1N/A return errvfsresult;
1N/A
1N/A return GNOME_VFS_OK;
1N/A}
1N/A
1N/Astatic GnomeVFSResult libntfs_gnomevfs_check_same_fs(GnomeVFSMethod *method,
1N/A GnomeVFSURI *a, GnomeVFSURI *b, gboolean *same_fs_return,
1N/A GnomeVFSContext *context __attribute__((unused)))
1N/A{
1N/A ntfs_volume *volume_a;
1N/A ntfs_volume *volume_b;
1N/A GnomeVFSResult errvfsresult;
1N/A
1N/A g_return_val_if_fail(method == &GnomeVFSMethod_static,
1N/A GNOME_VFS_ERROR_BAD_PARAMETERS);
1N/A g_return_val_if_fail(same_fs_return != NULL,
1N/A GNOME_VFS_ERROR_BAD_PARAMETERS);
1N/A
1N/A errvfsresult = libntfs_gnomevfs_uri_parent_init(&volume_a, a);
1N/A g_return_val_if_fail(errvfsresult == GNOME_VFS_OK, errvfsresult);
1N/A
1N/A errvfsresult = libntfs_gnomevfs_uri_parent_init(&volume_b, b);
1N/A g_return_val_if_fail(errvfsresult == GNOME_VFS_OK, errvfsresult);
1N/A
1N/A *same_fs_return = (volume_a == volume_b);
1N/A
1N/A return GNOME_VFS_OK;
1N/A}
1N/A
1N/A/**
1N/A * libntfs_gnomevfs_init:
1N/A *
1N/A * Returns: Initialized structure of #GnomeVFSMethod with static methods of
1N/A * libntfs-gnomevfs.
1N/A */
1N/AGnomeVFSMethod *libntfs_gnomevfs_method_init(const gchar *method_name,
1N/A const gchar *args)
1N/A{
1N/A struct method_name_info *method_name_info;
1N/A
1N/A g_return_val_if_fail(method_name != NULL, NULL);
1N/A /* 'args' may be NULL if not supplied. */
1N/A
1N/A method_name_hash_init();
1N/A
1N/A G_LOCK(method_name_hash);
1N/A method_name_info = g_hash_table_lookup(method_name_hash, method_name);
1N/A if (method_name_info && strcmp(method_name_info->args, args))
1N/A method_name_info = NULL;
1N/A G_UNLOCK(method_name_hash);
1N/A if (!method_name_info) {
1N/A
1N/A#ifdef __sun
1N/A method_name_info = g_new(struct method_name_info, 1);
1N/A#else /* !__sun */
1N/A libntfs_new(method_name_info);
1N/A#endif /* __sun */
1N/A
1N/A method_name_info->args = g_strdup(args);
1N/A G_LOCK(method_name_hash);
1N/A g_hash_table_replace(method_name_hash, g_strdup(method_name),
1N/A method_name_info);
1N/A G_UNLOCK(method_name_hash);
1N/A }
1N/A
1N/A G_LOCK(GnomeVFSMethod_static);
1N/A LIBNTFS_MEMZERO(&GnomeVFSMethod_static);
1N/A GnomeVFSMethod_static.method_table_size = sizeof(GnomeVFSMethod_static);
1N/A GnomeVFSMethod_static.open = libntfs_gnomevfs_open; /* mandatory */
1N/A GnomeVFSMethod_static.create = libntfs_gnomevfs_create; /* mandatory */
1N/A GnomeVFSMethod_static.close = libntfs_gnomevfs_close;
1N/A GnomeVFSMethod_static.read = libntfs_gnomevfs_read;
1N/A GnomeVFSMethod_static.seek = libntfs_gnomevfs_seek;
1N/A GnomeVFSMethod_static.tell = libntfs_gnomevfs_tell;
1N/A GnomeVFSMethod_static.open_directory = libntfs_gnomevfs_open_directory;
1N/A GnomeVFSMethod_static.close_directory =
1N/A libntfs_gnomevfs_close_directory;
1N/A GnomeVFSMethod_static.read_directory = libntfs_gnomevfs_read_directory;
1N/A GnomeVFSMethod_static.get_file_info =
1N/A libntfs_gnomevfs_get_file_info; /* mandatory */
1N/A GnomeVFSMethod_static.get_file_info_from_handle =
1N/A libntfs_gnomevfs_get_file_info_from_handle;
1N/A GnomeVFSMethod_static.is_local =
1N/A libntfs_gnomevfs_is_local; /* mandatory */
1N/A GnomeVFSMethod_static.check_same_fs = libntfs_gnomevfs_check_same_fs;
1N/A /* TODO: GnomeVFSMethodFindDirectoryFunc find_directory; */
1N/A /* TODO: GnomeVFSMethodFileControlFunc file_control; */
1N/A /* R/W: GnomeVFSMethodCreateSymbolicLinkFunc create_symbolic_link; */
1N/A /* R/W: GnomeVFSMethodMonitorAddFunc monitor_add; */
1N/A /* R/W: GnomeVFSMethodMonitorCancelFunc monitor_cancel; */
1N/A /* R/W: GnomeVFSMethod_static.write; */
1N/A /* R/W: GnomeVFSMethod_static.truncate_handle; */
1N/A /* R/W: GnomeVFSMethod_static.make_directory; */
1N/A /* R/W: GnomeVFSMethod_static.remove_directory; */
1N/A /* R/W: GnomeVFSMethod_static.move; */
1N/A /* R/W: GnomeVFSMethod_static.unlink; */
1N/A /* R/W: GnomeVFSMethod_static.set_file_info; */
1N/A /* R/W: GnomeVFSMethod_static.truncate; */
1N/A G_UNLOCK(GnomeVFSMethod_static);
1N/A
1N/A return &GnomeVFSMethod_static;
1N/A}
1N/A
1N/A/**
1N/A * libntfs_gnomevfs_method_shutdown:
1N/A *
1N/A * Shutdowns libntfs-gnomevfs successfuly flushing all caches.
1N/A *
1N/A * Sad note about gnome-vfs-2.1.5 is that it never calls this function. :-)
1N/A */
1N/Avoid libntfs_gnomevfs_method_shutdown(void)
1N/A{
1N/A uri_parent_string_hash_init();
1N/A G_LOCK(uri_parent_string_hash);
1N/A g_hash_table_destroy(uri_parent_string_hash);
1N/A uri_parent_string_hash = NULL;
1N/A G_UNLOCK(uri_parent_string_hash);
1N/A
1N/A method_name_hash_init();
1N/A G_LOCK(method_name_hash);
1N/A g_hash_table_destroy(method_name_hash);
1N/A method_name_hash = NULL;
1N/A G_UNLOCK(method_name_hash);
1N/A}
1N/A