diff options
author | Ross Lagerwall <rosslagerwall@gmail.com> | 2014-08-31 10:29:02 +0100 |
---|---|---|
committer | Ross Lagerwall <rosslagerwall@gmail.com> | 2014-09-05 07:44:15 +0100 |
commit | ce9d7700c5641610d1c4c2400c2ab3f9183288fb (patch) | |
tree | bf914355174e4318229d7a3b6dbef59aa6a26847 /daemon/gvfsbackendarchive.c | |
parent | 8a8c9942ed2f2f98b614747e4bfbae6b29f04d56 (diff) | |
download | gvfs-ce9d7700c5641610d1c4c2400c2ab3f9183288fb.tar.gz |
archive: Allow reading files with '/./' in the path
Allow reading files with a "." component in the path. This is a
followup to 46bdbf1d4596 ('archive: Ignore filenames consisting of a
single "."'), which allowed the archive backend to enumerate an archive
with a single "." in the path.
Implement this with a generic function to fixup an archive_entry path,
and use this wherever archive_entry_pathname() is used.
https://bugzilla.gnome.org/show_bug.cgi?id=729463
Diffstat (limited to 'daemon/gvfsbackendarchive.c')
-rw-r--r-- | daemon/gvfsbackendarchive.c | 80 |
1 files changed, 55 insertions, 25 deletions
diff --git a/daemon/gvfsbackendarchive.c b/daemon/gvfsbackendarchive.c index f98ee78a..3720467d 100644 --- a/daemon/gvfsbackendarchive.c +++ b/daemon/gvfsbackendarchive.c @@ -257,8 +257,46 @@ g_vfs_backend_archive_init (GVfsBackendArchive *archive) } /*** FILE TREE HANDLING ***/ +static char * +fixup_path (const char *path) +{ + char *str, *ptr; + int len; + + /* skip leading garbage if present */ + if (g_str_has_prefix (path, "./")) + str = g_strdup (path + 2); + else + str = g_strdup (path); + + /* strip '/./' from the path */ + ptr = str; + while ((ptr = strstr (ptr, "/./"))) + { + char *dst = ptr + 2; + while (*dst) + *++ptr = *++dst; + } + + /* strip '//' from the path */ + ptr = str; + while ((ptr = strstr (ptr, "//"))) + { + char *dst = ptr + 1; + while (*dst) + *++ptr = *++dst; + } -/* NB: filename must NOT start with a slash */ + /* strip trailing slash from the path */ + len = strlen (str); + if (len > 0 && str[len - 1] == '/') + str[len - 1] = '\0'; + + return str; +} + +/* Filename must be a clean path containing no '.' entries, no empty entries + * and must not start with a '/'. */ static ArchiveFile * archive_file_get_from_path (ArchiveFile *file, const char *filename, gboolean add) { @@ -267,9 +305,6 @@ archive_file_get_from_path (ArchiveFile *file, const char *filename, gboolean ad GSList *walk; guint i; - /* libarchive reports paths starting with ./ for some archive types */ - if (g_str_has_prefix (filename, "./")) - filename += 2; names = g_strsplit (filename, "/", -1); DEBUG ("%s %s\n", add ? "add" : "find", filename); @@ -286,19 +321,9 @@ archive_file_get_from_path (ArchiveFile *file, const char *filename, gboolean ad if (cur == NULL && add != FALSE) { DEBUG ("adding node %s to %s\n", names[i], file->name); - if (names[i][0] != 0 && - strcmp (names[i], ".") != 0) - { - cur = g_slice_new0 (ArchiveFile); - cur->name = g_strdup (names[i]); - file->children = g_slist_prepend (file->children, cur); - } - else - { - /* Ignore empty elements from directories ending with a slash. - * Ignore elements consisting of a single "." */ - cur = file; - } + cur = g_slice_new0 (ArchiveFile); + cur->name = g_strdup (names[i]); + file->children = g_slist_prepend (file->children, cur); } file = cur; } @@ -534,6 +559,9 @@ create_file_tree (GVfsBackendArchive *ba, GVfsJob *job) result = archive_read_next_header (archive->archive, &entry); if (result >= ARCHIVE_WARN && result <= ARCHIVE_OK) { + ArchiveFile *file; + char *path; + if (result < ARCHIVE_OK) { DEBUG ("archive_read_next_header: result = %d, error = '%s'\n", result, archive_error_string (archive->archive)); archive_set_error (archive->archive, ARCHIVE_OK, "No error"); @@ -542,9 +570,9 @@ create_file_tree (GVfsBackendArchive *ba, GVfsJob *job) continue; } - ArchiveFile *file = archive_file_get_from_path (ba->files, - archive_entry_pathname (entry), - TRUE); + path = fixup_path (archive_entry_pathname (entry)); + file = archive_file_get_from_path (ba->files, path, TRUE); + g_free (path); /* Don't set info for root */ if (file != ba->files) { @@ -695,7 +723,7 @@ do_open_for_read (GVfsBackend * backend, struct archive_entry *entry; int result; ArchiveFile *file; - const char *entry_pathname; + char *entry_pathname; file = archive_file_find (ba, filename); if (file == NULL) @@ -730,12 +758,12 @@ do_open_for_read (GVfsBackend * backend, continue; } - entry_pathname = archive_entry_pathname (entry); - /* skip leading garbage if present */ - if (g_str_has_prefix (entry_pathname, "./")) - entry_pathname += 2; + entry_pathname = fixup_path (archive_entry_pathname (entry)); + if (g_str_equal (entry_pathname, filename + 1)) { + g_free (entry_pathname); + /* SUCCESS */ g_vfs_job_open_for_read_set_handle (job, archive); g_vfs_job_open_for_read_set_can_seek (job, FALSE); @@ -744,6 +772,8 @@ do_open_for_read (GVfsBackend * backend, } else archive_read_data_skip (archive->archive); + + g_free (entry_pathname); } } while (result != ARCHIVE_FATAL && result != ARCHIVE_EOF); |