untar: do not exit with error when created directory already exists.

The problem exists for both RTEMS untar implementations and their
variants: Untar_FromMemory(), Untar_FromFile() and rtems_tarfs_load().

If filesystem object already exists at extracted directory path
then if it is directory, creation is ignored. Attempt
to delete/unlink object and make directory is tried for other cases.

This simple approach problem reported in ticket fixes #2413.
Behavior follows GNU tar and BSD tar practice for directories
but much more work is required to achieve full semantics
of the full featured tar implementation still.
This commit is contained in:
Pavel Pisa
2015-11-23 10:09:06 +01:00
committed by Gedare Bloom
parent 3e1196d9e1
commit 9394aa5ed7
2 changed files with 46 additions and 2 deletions

View File

@@ -103,8 +103,24 @@ int rtems_tarfs_load(
strcat(full_filename, "/");
++len;
strncat(full_filename, filename, 256-len-1);
rv = mkdir(full_filename, S_IRWXU | S_IRWXG | S_IRWXO);
if ( mkdir(full_filename, S_IRWXU | S_IRWXG | S_IRWXO) != 0 ) {
if (errno == EEXIST) {
struct stat stat_buf;
if ( stat(full_filename, &stat_buf) == 0 ) {
if ( S_ISDIR(stat_buf.st_mode) ) {
continue;
} else {
if ( unlink(full_filename) != -1 ) {
if ( mkdir(full_filename, S_IRWXU | S_IRWXG | S_IRWXO) == 0 )
continue;
}
}
}
}
rv = -1;
}
}
/*
* Create a LINEAR_FILE node
*/

View File

@@ -28,6 +28,7 @@
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <rtems/untar.h>
@@ -203,6 +204,19 @@ Untar_FromMemory(
}
} else if (linkflag == DIRTYPE) {
if ( mkdir(fname, S_IRWXU | S_IRWXG | S_IRWXO) != 0 ) {
if (errno == EEXIST) {
struct stat stat_buf;
if ( stat(fname, &stat_buf) == 0 ) {
if ( S_ISDIR(stat_buf.st_mode) ) {
continue;
} else {
if ( unlink(fname) != -1 ) {
if ( mkdir(fname, S_IRWXU | S_IRWXG | S_IRWXO) == 0 )
continue;
}
}
}
}
printk("Untar: failed to create directory %s\n", fname);
retval = UNTAR_FAIL;
break;
@@ -319,7 +333,21 @@ Untar_FromFile(
close(out_fd);
}
} else if (linkflag == DIRTYPE) {
(void) mkdir(fname, S_IRWXU | S_IRWXG | S_IRWXO);
if ( mkdir(fname, S_IRWXU | S_IRWXG | S_IRWXO) != 0 ) {
if (errno == EEXIST) {
struct stat stat_buf;
if ( stat(fname, &stat_buf) == 0 ) {
if ( S_ISDIR(stat_buf.st_mode) ) {
continue;
} else {
if ( unlink(fname) != -1 ) {
if ( mkdir(fname, S_IRWXU | S_IRWXG | S_IRWXO) == 0 )
continue;
}
}
}
}
}
}
}
free(bufr);