[PATCH] Improve tar method
- From: Christian Neumair <chris gnome-de org>
- To: gnome-vfs-list gnome org
- Subject: [PATCH] Improve tar method
- Date: Tue, 18 Apr 2006 00:46:15 +0200
After dedicating a notable time on an almost complete zip method, I've
spent some time on the tar method:
The attached patch significantly cleans up some weird aspects of the tar
method, for instance its inability to distinguish a 0 octal number from
an invalid or unpresent number, access of uninitialized memory and its
handling of the root node.
--
Christian Neumair <chris gnome-de org>
Index: modules/tar-method.c
===================================================================
RCS file: /cvs/gnome/gnome-vfs/modules/tar-method.c,v
retrieving revision 1.4
diff -u -p -r1.4 tar-method.c
--- modules/tar-method.c 29 Nov 2005 16:35:05 -0000 1.4
+++ modules/tar-method.c 17 Apr 2006 22:43:32 -0000
@@ -66,13 +66,19 @@ G_LOCK_DEFINE_STATIC (tar_cache);
#define IS_OCTAL_DIGIT(c) ((c) >= '0' && (c) <= '8')
#define OCTAL_DIGIT(c) ((c) - '0')
-static int parse_octal (const char *str, int len)
+static int inline
+parse_octal (const char *str, int len)
{
int i, ret = 0;
+
+ if (str[0] == '\0') {
+ return -1;
+ }
+
for (i = 0; i < len; i++)
{
if (str[i] == '\0') break;
- else if (!IS_OCTAL_DIGIT (str[i])) return 0;
+ else if (!IS_OCTAL_DIGIT (str[i])) return -1;
ret = ret * 8 + OCTAL_DIGIT (str[i]);
}
return ret;
@@ -155,7 +161,7 @@ real_lookup_entry (const GNode *tree, co
}
static GNode*
-tree_lookup_entry (const GNode *tree, const gchar *name)
+tree_lookup_entry (GNode *tree, const gchar *name)
{
GNode *ret;
char *root = g_strdup (name);
@@ -164,6 +170,10 @@ tree_lookup_entry (const GNode *tree, co
if (txt[0] == '/')
txt++;
+ if (txt[0] == '\0') {
+ return tree;
+ }
+
ret = real_lookup_entry (tree, txt, 1);
if (!ret && txt[strlen (txt) - 1] != '/')
{
@@ -240,7 +250,7 @@ static TarFile* read_tar_file (GnomeVFSH
g_free (rest);
maxsize = parse_octal_field (ret->blocks[i].p.size);
- if (maxsize)
+ if (maxsize > 0)
{
for (orig = i; i < ret->num_blocks && size < maxsize; i++)
{
@@ -250,9 +260,10 @@ static TarFile* read_tar_file (GnomeVFSH
size += wsize;
}
i++;
- }
- else
- {
+ } else if (maxsize < 0) {
+ g_warning ("unable to parse file size for %s", ret->blocks[i].p.name);
+ i++;
+ } else {
i++;
}
}
@@ -322,6 +333,7 @@ do_open (GnomeVFSMethod *method,
tar = ensure_tarfile (uri);
if (!tar)
return GNOME_VFS_ERROR_BAD_FILE;
+
node = tree_lookup_entry (tar->info_tree, uri->text);
if (!node)
{
@@ -330,7 +342,8 @@ do_open (GnomeVFSMethod *method,
}
start = node->data;
- if (start->p.name[strlen (start->p.name) - 1] == '/')
+ if (start == NULL /* NULL data means root node */ ||
+ start->p.name[strlen (start->p.name) - 1] == '/')
return GNOME_VFS_ERROR_IS_DIRECTORY;
new_handle = g_new0 (FileHandle, 1);
new_handle->tar = tar;
@@ -384,6 +397,10 @@ do_read (GnomeVFSMethod *method,
return GNOME_VFS_ERROR_IS_DIRECTORY;
maxsize = parse_octal_field (handle->start->p.size);
+ if (maxsize < 0) {
+ return GNOME_VFS_ERROR_CORRUPTED_DATA;
+ }
+
if (handle->current == handle->start)
{
handle->current_index++;
@@ -436,6 +453,9 @@ do_seek (GnomeVFSMethod *method,
break;
case GNOME_VFS_SEEK_END:
current_offset = parse_octal_field (handle->start->p.size);
+ if (current_offset < 0) {
+ return GNOME_VFS_ERROR_CORRUPTED_DATA;
+ }
break;
default:
current_offset = handle->current_offset;
@@ -472,40 +492,25 @@ do_open_directory (GnomeVFSMethod *metho
if (!uri->parent)
return GNOME_VFS_ERROR_INVALID_URI;
tar = ensure_tarfile (uri);
- if (uri->text)
- {
- node = tree_lookup_entry (tar->info_tree, uri->text);
- if (!node)
- {
- tar_file_unref (tar);
- return GNOME_VFS_ERROR_NOT_FOUND;
- }
- start = node->data;
-
- if (start->p.name[strlen (start->p.name) - 1] != '/')
- return GNOME_VFS_ERROR_NOT_A_DIRECTORY;
-
- if (node->children)
- current = node->children->data;
- else
- current = NULL;
+ if (tar == NULL) {
+ return GNOME_VFS_ERROR_BAD_FILE;
}
- else
- {
- node = tar->info_tree;
- if (!node)
- {
- tar_file_unref (tar);
- return GNOME_VFS_ERROR_NOT_FOUND;
- }
- if (node->children)
- start = node->children->data;
- else
- start = NULL;
- current = start;
+ node = tree_lookup_entry (tar->info_tree, uri->text);
+ if (node == NULL) {
+ tar_file_unref (tar);
+ return GNOME_VFS_ERROR_NOT_FOUND;
}
+ start = node->data;
+ if (start != NULL && start->p.name[strlen (start->p.name) - 1] != '/')
+ return GNOME_VFS_ERROR_NOT_A_DIRECTORY;
+
+ if (node->children)
+ current = node->children->data;
+ else
+ current = NULL;
+
new_handle = g_new0 (FileHandle, 1);
new_handle->tar = tar;
new_handle->filename = g_strdup (tar->filename);
@@ -546,33 +551,39 @@ do_get_file_info (GnomeVFSMethod *method
union TARPET_block *current;
gchar *name;
gchar *path;
- char *mime_type;
+ const char *mime_type;
int i;
if (!uri->parent)
return GNOME_VFS_ERROR_INVALID_URI;
tar = ensure_tarfile (uri);
-
- if (uri->text)
- node = tree_lookup_entry (tar->info_tree, uri->text);
- else
- node = tar->info_tree->children;
-
+ if (tar == NULL) {
+ return GNOME_VFS_ERROR_BAD_FILE;
+ }
+
+ node = tree_lookup_entry (tar->info_tree, uri->text);
if (!node)
{
tar_file_unref (tar);
return GNOME_VFS_ERROR_NOT_FOUND;
}
+ name = NULL;
+
current = node->data;
- for (i = 0; i < tar->num_blocks; i++)
- if (&(tar->blocks[i]) == current)
- break;
- if (i && tar->blocks[i - 2].p.typeflag == TARPET_TYPE_LONGFILEN)
- name = g_strdup (tar->blocks[i - 1].raw.data);
- else
- name = g_strdup (current->p.name);
+ if (current != NULL) {
+ for (i = 0; i < tar->num_blocks; i++)
+ if (&(tar->blocks[i]) == current)
+ break;
+
+ if (i >= 2 && i < tar->num_blocks && tar->blocks[i - 2].p.typeflag == TARPET_TYPE_LONGFILEN)
+ name = g_strdup (tar->blocks[i - 1].raw.data);
+ else
+ name = g_strdup (current->p.name);
+ } else { /* root node */
+ name = g_strdup ("/");
+ }
file_info->name = g_path_get_basename (name);
if (name[strlen (name) - 1] == '/')
@@ -585,13 +596,38 @@ do_get_file_info (GnomeVFSMethod *method
else
file_info->type = GNOME_VFS_FILE_TYPE_REGULAR;
- file_info->permissions = parse_octal_field (current->p.mode);
- file_info->uid = parse_octal_field (current->p.uid);
- file_info->gid = parse_octal_field (current->p.gid);
- file_info->size = parse_octal_field (current->p.size);
- file_info->mtime = parse_octal_field (current->p.mtime);
- file_info->atime = parse_octal_field (current->gnu.atime);
- file_info->ctime = parse_octal_field (current->gnu.ctime);
+ if (current != NULL) {
+ file_info->permissions = parse_octal_field (current->p.mode);
+ if (!(file_info->permissions < 0)) {
+ file_info->valid_fields |= GNOME_VFS_FILE_INFO_FIELDS_PERMISSIONS;
+ }
+
+ file_info->uid = parse_octal_field (current->p.uid);
+ file_info->gid = parse_octal_field (current->p.gid);
+ if (!(file_info->uid < 0) && !(file_info->gid < 0)) {
+ file_info->valid_fields |= GNOME_VFS_FILE_INFO_FIELDS_IDS;
+ }
+
+ file_info->size = parse_octal_field (current->p.size);
+ if (!(file_info->size < 0)) {
+ file_info->valid_fields |= GNOME_VFS_FILE_INFO_FIELDS_SIZE;
+ }
+
+ file_info->mtime = parse_octal_field (current->p.mtime);
+ if (!(file_info->mtime < 0)) {
+ file_info->valid_fields |= GNOME_VFS_FILE_INFO_FIELDS_MTIME;
+ }
+
+ file_info->atime = parse_octal_field (current->gnu.atime);
+ if (!(file_info->atime < 0)) {
+ file_info->valid_fields |= GNOME_VFS_FILE_INFO_FIELDS_ATIME;
+ }
+
+ file_info->ctime = parse_octal_field (current->gnu.ctime);
+ if (!(file_info->ctime < 0)) {
+ file_info->valid_fields |= GNOME_VFS_FILE_INFO_FIELDS_CTIME;
+ }
+ }
if (file_info->type == GNOME_VFS_FILE_TYPE_DIRECTORY)
mime_type = "x-directory/normal";
@@ -616,14 +652,8 @@ do_get_file_info (GnomeVFSMethod *method
file_info->mime_type = g_strdup (mime_type);
- file_info->valid_fields = GNOME_VFS_FILE_INFO_FIELDS_TYPE |
- GNOME_VFS_FILE_INFO_FIELDS_PERMISSIONS |
- GNOME_VFS_FILE_INFO_FIELDS_SIZE |
- GNOME_VFS_FILE_INFO_FIELDS_ATIME |
- GNOME_VFS_FILE_INFO_FIELDS_MTIME |
- GNOME_VFS_FILE_INFO_FIELDS_CTIME |
- GNOME_VFS_FILE_INFO_FIELDS_MIME_TYPE |
- GNOME_VFS_FILE_INFO_FIELDS_IDS;
+ file_info->valid_fields |= GNOME_VFS_FILE_INFO_FIELDS_TYPE |
+ GNOME_VFS_FILE_INFO_FIELDS_MIME_TYPE;
g_free (name);
tar_file_unref (tar);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]