untar: Properly make parent path

Close #3823.
This commit is contained in:
Sebastian Huber
2019-11-26 08:07:55 +01:00
parent 4a056523cf
commit 4551f5f0db
4 changed files with 78 additions and 176 deletions

View File

@@ -1,14 +1,9 @@
/**
* @file
*
* @brief Untar an Image
*
* @ingroup libmisc_untar_img Untar Image
* FIXME:
* 1. Symbolic links are not created.
* 2. Untar_FromMemory uses FILE *fp.
* 3. How to determine end of archive?
*/
/*
@@ -105,143 +100,61 @@ Print_Error(const rtems_printer *printer, const char* message, const char* path)
message, path, errno, strerror(errno));
}
/*
* Get the type of node on in the file system if present.
*/
static int
Stat_Node(const char* path)
{
struct stat sb;
if (stat(path, &sb) < 0)
return -1;
if (S_ISDIR(sb.st_mode))
return DIRTYPE;
return REGTYPE;
}
/*
* Make the directory path for a file if it does not exist.
*/
static int
Make_Path(const rtems_printer *printer, const char* filename, int linktype)
Make_Path(const rtems_printer *printer, char *path)
{
char* copy = strdup(filename);
char* path = copy;
char *p;
/*
* Skip leading path separators.
*/
while (*path == '/')
while (*path == '/') {
++path;
/*
* Any path left?
*/
if (*path != '\0') {
bool path_end = false;
char* end = path;
int r;
/*
* Split the path into directory components. Check the node and if a file
* and not the end of the path remove it and create a directory. If a
* directory and not the end of the path decend into the directory.
*/
while (!path_end) {
while (*end != '\0' && *end != '/')
++end;
/*
* Are we at the end of the path?
*/
if (*end == '\0')
path_end = true;
/*
* Split the path.
*/
*end = '\0';
/*
* Get the node's status, exists, error, directory or regular? Regular
* means not a directory.
*/
r = Stat_Node(path);
/*
* If there are errors other than not existing we are finished.
*/
if (r < 0 && errno != ENOENT) {
Print_Error(printer, "stat", path);
return -1;
}
/*
* If a file remove and create a directory if not the end.
*/
if (r == REGTYPE) {
r = unlink(path);
if (r < 0) {
Print_Error(printer, "unlink", path);
free(copy);
return -1;
}
if (!path_end) {
r = mkdir(path, S_IRWXU | S_IRWXG | S_IRWXO);
if (r < 0) {
Print_Error(printer, "mkdir (unlink)", path);
free(copy);
return -1;
}
}
}
else if (r < 0) {
/*
* Node does not exist which means the rest of the path will not exist.
*/
while (!path_end) {
r = mkdir(path, S_IRWXU | S_IRWXG | S_IRWXO);
if (r < 0) {
Print_Error(printer, "mkdir", path);
free(copy);
return -1;
}
if (!path_end) {
*end = '/';
++end;
}
while (*end != '\0' && *end != '/')
++end;
if (*end == '\0')
path_end = true;
}
}
else if (path_end && r == DIRTYPE && linktype != DIRTYPE) {
/*
* We only handle a directory if at the end of the path and the end is
* a file. If we cannot remove the directory because it is not empty we
* raise an error. Otherwise this is a directory and we do nothing
* which lets us decend into it.
*/
r = rmdir(path);
if (r < 0) {
Print_Error(printer, "rmdir", path);
free(copy);
return -1;
}
}
/*
* If not the end of the path put back the directory separator.
*/
if (!path_end) {
*end = '/';
++end;
}
}
}
free(copy);
p = path;
for (; ; ++p) {
if (p[0] == '\0') {
return 0;
} else if (p[0] != '/') {
continue;
}
*p = '\0';
if (p[1] == '\0') {
/* Speculatively unlink the last component so that it can be re-created */
unlink(path);
return 0;
}
if (mkdir(path, S_IRWXU | S_IRWXG | S_IRWXO) != 0) {
if (errno == EEXIST || errno == EISDIR) {
struct stat sb;
if (stat(path, &sb) != 0) {
return -1;
}
if (!S_ISDIR(sb.st_mode)) {
if (unlink(path) != 0) {
Print_Error(printer, "unlink", path);
return -1;
}
if (mkdir(path, S_IRWXU | S_IRWXG | S_IRWXO) != 0) {
Print_Error(printer, "mkdir (unlink)", path);
return -1;
}
}
}
}
*p = '/';
}
return 0;
}
@@ -252,9 +165,10 @@ Untar_ProcessHeader(
const char *bufr
)
{
int sum;
int hdr_chksum;
int retval = UNTAR_SUCCESSFUL;
int sum;
int hdr_chksum;
int retval = UNTAR_SUCCESSFUL;
int r;
ctx->file_name[0] = '\0';
ctx->file_size = 0;
@@ -290,7 +204,7 @@ Untar_ProcessHeader(
* with it.
*/
if (Make_Path(ctx->printer, ctx->file_path, ctx->linkflag) < 0) {
if (Make_Path(ctx->printer, ctx->file_path) != 0) {
retval = UNTAR_FAIL;
}
@@ -298,33 +212,21 @@ Untar_ProcessHeader(
strlcpy(ctx->link_name, &bufr[157], sizeof(ctx->link_name));
rtems_printf(ctx->printer, "untar: symlink: %s -> %s\n",
ctx->link_name, ctx->file_path);
symlink(ctx->link_name, ctx->file_path);
r = symlink(ctx->link_name, ctx->file_path);
if (r != 0) {
Print_Error(ctx->printer, "symlink", ctx->file_path);
retval = UNTAR_FAIL;
}
} else if (ctx->linkflag == REGTYPE) {
rtems_printf(ctx->printer, "untar: file: %s (s:%lu,m:%04lo)\n",
ctx->file_path, ctx->file_size, ctx->mode);
ctx->nblocks = (((ctx->file_size) + 511) & ~511) / 512;
} else if (ctx->linkflag == DIRTYPE) {
int r;
rtems_printf(ctx->printer, "untar: dir: %s\n", ctx->file_path);
r = mkdir(ctx->file_path, S_IRWXU | S_IRWXG | S_IRWXO);
if (r < 0) {
if (errno == EEXIST) {
struct stat stat_buf;
if (stat(ctx->file_path, &stat_buf) == 0) {
if (S_ISDIR(stat_buf.st_mode)) {
r = 0;
} else {
r = unlink(ctx->file_path);
if (r == 0) {
r = mkdir(ctx->file_path, ctx->mode);
}
}
}
}
if (r < 0) {
Print_Error(ctx->printer, "mkdir", ctx->file_path);
retval = UNTAR_FAIL;
}
r = mkdir(ctx->file_path, ctx->mode);
if (r != 0) {
Print_Error(ctx->printer, "mkdir", ctx->file_path);
retval = UNTAR_FAIL;
}
}

View File

@@ -1288,9 +1288,9 @@ endif
tar01_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_FLAGS_tar01) \
$(support_includes) $(test_includes) -I$(top_srcdir)/include
tar01_LDADD = $(RTEMS_ROOT)cpukit/librtemscpu.a $(RTEMS_ROOT)cpukit/libz.a $(LDADD)
tar01.tar: Makefile
tar01.tar: $(srcdir)/tar01/home/test_file $(srcdir)/tar01/home/abc/def/test_script $(srcdir)/tar01/symlink
@rm -f $@
$(AM_V_GEN)$(PAX) -w -f $@ -s ,$(srcdir)/tar01/,, $(srcdir)/tar01/home $(srcdir)/tar01/symlink
$(AM_V_GEN)$(PAX) -w -f $@ -s ,$(srcdir)/tar01/,, $+
tar01-tar.c: tar01.tar
$(AM_V_GEN)$(BIN2C) -C $< $@
tar01-tar.h: tar01.tar
@@ -1327,9 +1327,9 @@ tar02_SOURCES = tar02/init.c ../psxtests/psxfile01/test_cat.c \
tar02-tar.c tar02-tar.h
tar02_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_FLAGS_tar02) \
$(support_includes) $(test_includes) -I$(top_srcdir)/include
tar02.tar: Makefile
tar02.tar: $(srcdir)/tar01/home/test_file $(srcdir)/tar01/home/abc/def/test_script $(srcdir)/tar01/symlink
@rm -f $@
$(AM_V_GEN)$(PAX) -w -f $@ -s ,$(srcdir)/tar01/,, $(srcdir)/tar01/home $(srcdir)/tar01/symlink
$(AM_V_GEN)$(PAX) -w -f $@ -s ,$(srcdir)/tar01/,, $+
tar02-tar.c: tar02.tar
$(AM_V_GEN)$(BIN2C) -C $< $@
tar02-tar.h: tar02.tar

View File

@@ -85,9 +85,9 @@ void test_untar_from_memory(void)
test_cat( "/home/test_file", 0, 0 );
/******************/
printf( "========= /home/test_script =========\n" );
test_cat( "/home/test_script", 0, 0 );
test_untar_check_mode("/home/test_script", 0755);
printf( "========= /home/abc/def/test_script =========\n" );
test_cat( "/home/abc/def/test_script", 0, 0 );
test_untar_check_mode("/home/abc/def/test_script", 0755);
/******************/
printf( "========= /symlink =========\n" );
@@ -133,9 +133,9 @@ void test_untar_from_file(void)
test_cat( "/dest/home/test_file", 0, 0 );
/******************/
printf( "========= /dest/home/test_script =========\n" );
test_cat( "/dest/home/test_script", 0, 0 );
test_untar_check_mode("/dest/home/test_script", 0755);
printf( "========= /dest/home/abc/def/test_script =========\n" );
test_cat( "/dest/home/abc/def/test_script", 0, 0 );
test_untar_check_mode("/dest/home/abc/def/test_script", 0755);
/******************/
printf( "========= /dest/symlink =========\n" );
@@ -179,9 +179,9 @@ void test_untar_chunks_from_memory(void)
test_cat( "/dest2/home/test_file", 0, 0 );
/******************/
printf( "========= /dest2/home/test_script =========\n" );
test_cat( "/dest2/home/test_script", 0, 0 );
test_untar_check_mode("/dest2/home/test_script", 0755);
printf( "========= /dest2/home/abc/def/test_script =========\n" );
test_cat( "/dest2/home/abc/def/test_script", 0, 0 );
test_untar_check_mode("/dest2/home/abc/def/test_script", 0755);
/******************/
printf( "========= /dest2/symlink =========\n" );
@@ -225,9 +225,9 @@ void test_untar_unzip_tgz(void)
test_cat( "/dest3/home/test_file", 0, 0 );
/******************/
printf( "========= /dest3/home/test_script =========\n" );
test_cat( "/dest3/home/test_script", 0, 0 );
test_untar_check_mode("/dest3/home/test_script", 0755);
printf( "========= /dest3/home/abc/def/test_script =========\n" );
test_cat( "/dest3/home/abc/def/test_script", 0, 0 );
test_untar_check_mode("/dest3/home/abc/def/test_script", 0755);
/******************/
printf( "========= /dest3/symlink =========\n" );
@@ -275,9 +275,9 @@ void test_untar_unzip_txz(void)
test_cat( "/dest4/home/test_file", 0, 0 );
/******************/
printf( "========= /dest4/home/test_script =========\n" );
test_cat( "/dest4/home/test_script", 0, 0 );
test_untar_check_mode("/dest4/home/test_script", 0755);
printf( "========= /dest4/home/abc/def/test_script =========\n" );
test_cat( "/dest4/home/abc/def/test_script", 0, 0 );
test_untar_check_mode("/dest4/home/abc/def/test_script", 0755);
/******************/
printf( "========= /dest4/symlink =========\n" );