/* Tux Commander VFS: convenient interface for VFS modules to a filelist tree * Copyright (C) 2007-2009 Tomas Bzatek * Check for updates on tuxcmd.sourceforge.net * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include "tuxcmd-vfs.h" #include "strutils.h" #include "logutils.h" #include "vfsutils.h" #include "filelist.h" #include "filelist-vfs-intf.h" struct VfsFilelistData * vfs_filelist_new (struct PathTree *files) { struct VfsFilelistData * data; data = g_malloc0 (sizeof (struct VfsFilelistData)); data->files = files; return data; } void vfs_filelist_free (struct VfsFilelistData *data) { if (data == NULL) return; g_free (data->list_dir_path); g_free (data); } /* -------------------------------------------------------------------------------------- */ guint64 internal_get_dir_size (struct VfsFilelistData *data, struct PathTree *tree) { guint64 Size; struct PathTree *n; unsigned long idx; Size = 0; if (! data->break_get_dir_size && tree) { n = NULL; idx = 0; while ((n = filelist_tree_get_item_by_index (tree, idx))) { if (data->break_get_dir_size) break; if (n->data) { log_debug ("internal_get_dir_size: found item '%s', size = %zd", n->node, n->data->iSize); Size += (n->data->ItemType == vDirectory) ? internal_get_dir_size (data, n) : n->data->iSize; } idx++; } } return Size; } guint64 vfs_filelist_get_dir_size (struct VfsFilelistData *data, const char *APath) { struct PathTree *node; if (! data) return 0; data->break_get_dir_size = FALSE; node = filelist_tree_find_node_by_path (data->files, APath); if (node) { return internal_get_dir_size (data, node); } else { log_error ("VFSGetDirSize: path '%s' not found", APath); return 0; } } void vfs_filelist_get_dir_size_break (struct VfsFilelistData *data) { if (data) data->break_get_dir_size = TRUE; } /* -------------------------------------------------------------------------------------- */ static struct TVFSItem * assign_file_info (struct PathTree* node, const char *reference_full_path, gboolean follow_symlinks, gboolean add_full_path) { struct TVFSItem *Item; Item = g_malloc (sizeof (struct TVFSItem)); copy_vfs_item (node->data, Item); if (add_full_path && reference_full_path) { g_free (Item->FName); g_free (Item->FDisplayName); Item->FName = g_strdup (reference_full_path); Item->FDisplayName = g_filename_display_name (reference_full_path); } if (follow_symlinks && node->symlink_target_data) { Item->iSize = node->symlink_target_data->iSize; Item->iPackedSize = node->symlink_target_data->iPackedSize; Item->ItemType = node->symlink_target_data->ItemType; } return Item; } struct TVFSItem * vfs_filelist_file_info (struct VfsFilelistData *data, const char *AFileName, gboolean FollowSymlinks, gboolean AddFullPath, GError **error) { struct PathTree *node; if (data && data->files) { node = filelist_tree_find_node_by_path (data->files, AFileName); if (node) { if (node->data) { log_debug ("vfs_filelist_file_info: found file: '%s'", node->node); return assign_file_info (node, AFileName, FollowSymlinks, AddFullPath); } else { log_error ("vfs_filelist_file_info: node->data == NULL!"); g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_INITIALIZED, "node->data == NULL"); return NULL; } } else { log_error ("vfs_filelist_file_info: file specified not found"); g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, "File specified not found."); return NULL; } } else { log_error ("vfs_filelist_file_info: Invalid pointers to data objects."); g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, "Invalid pointers to data objects."); return NULL; } } struct TVFSItem * vfs_filelist_list_first (struct VfsFilelistData *data, const char *sDir, gboolean FollowSymlinks, gboolean AddFullPath, GError **error) { struct PathTree *node; char *full_path; struct TVFSItem *Item; data->list_dir_index = -1; data->list_dir_node = NULL; if (sDir == NULL) { log_error ("vfs_filelist_list_first: sDir is NULL!"); g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, "NewPath is NULL"); return NULL; } data->list_dir_index = 0; data->list_dir_node = filelist_tree_find_node_by_path (data->files, sDir); data->follow_symlinks = FollowSymlinks; data->add_full_path = AddFullPath; data->list_dir_path = include_trailing_path_sep (sDir); /* Find the directory in the filelist */ if (data->list_dir_node) { node = filelist_tree_get_item_by_index (data->list_dir_node, data->list_dir_index); if (node) { full_path = NULL; if (AddFullPath) full_path = g_build_filename (sDir, node->data->FName, NULL); Item = assign_file_info (node, full_path, FollowSymlinks, AddFullPath); g_free (full_path); log_debug ("vfs_filelist_list_first: found file: %s", Item->FName); return Item; } else { log_debug ("vfs_filelist_list_first: no more files"); return NULL; } } else { log_error ("vfs_filelist_list_first: Directory '%s' not found.", sDir); g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, "Directory '%s' not found.", sDir); return NULL; } } struct TVFSItem * vfs_filelist_list_next (struct VfsFilelistData *data, GError **error) { struct PathTree *node; char *full_path; struct TVFSItem *Item; full_path = NULL; if (! data->list_dir_node) { log_error ("vfs_filelist_list_next: data->list_dir_node is NULL!"); g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_INITIALIZED, "data->list_dir_node is NULL"); return NULL; } data->list_dir_index++; node = filelist_tree_get_item_by_index (data->list_dir_node, data->list_dir_index); if (node) { if (data->add_full_path) full_path = g_build_filename (data->list_dir_path, node->data->FName, NULL); Item = assign_file_info (node, full_path, data->follow_symlinks, data->add_full_path); g_free (full_path); log_debug ("vfs_filelist_list_next: found file: %s", Item->FName); return Item; } else { log_debug ("vfs_filelist_list_next: no more files"); return NULL; } } gboolean vfs_filelist_list_close (struct VfsFilelistData *data, GError **error) { data->list_dir_index = -1; data->list_dir_node = NULL; g_free (data->list_dir_path); data->list_dir_path = NULL; return TRUE; } /* -------------------------------------------------------------------------------------- */ char * vfs_filelist_change_dir (struct VfsFilelistData *data, const char *NewPath, GError **error) { char *ANewPath; if (NewPath == NULL) { log_error ("VFSChangeDir: NewPath is NULL!"); g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, "NewPath is NULL"); return NULL; } /* make up the target path */ log_debug ("VFSChangeDir: Going to change dir from '%s'", NewPath); ANewPath = exclude_trailing_path_sep (NewPath); if (! ANewPath || strlen (ANewPath) <= 0) ANewPath = g_strdup ("/"); log_debug ("VFSChangeDir: Going to change dir to '%s'", ANewPath); /* find the directory in the filelist */ if (filelist_tree_find_node_by_path (data->files, ANewPath)) { return ANewPath; } else { log_error ("VFSChangeDir: Directory '%s' not found.", ANewPath); g_free (ANewPath); g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, "Directory '%s' not found.", ANewPath); return NULL; } }