summaryrefslogtreecommitdiffstats
path: root/cpukit/libmisc
diff options
context:
space:
mode:
authorChristian Mauderer <christian.mauderer@embedded-brains.de>2021-12-01 16:39:46 +0100
committerChristian Mauderer <christian.mauderer@embedded-brains.de>2021-12-09 08:23:47 +0100
commitffc57e3cf33ec0e2cc51ce214cedc24f390a7ea5 (patch)
tree210db2da29d65be56aff24dfc737c036a8707854 /cpukit/libmisc
parentscore: Fix _Workspace_Initialize_for_one_area() (diff)
downloadrtems-ffc57e3cf33ec0e2cc51ce214cedc24f390a7ea5.tar.bz2
untar: Make behavior similar to GNU or BSD tar
RTEMS untar implementation had problems with overwriting or integrating archives into existing directory structures. This patch adapts the behavior to mimic that of a GNU tar or BSD tar and extends the tar01 test to check for the behavior. That is: * If a directory structure exists, the files from the archive will be integrated. Existing files are overwritten. * If a file exists and the archive contains a directory with the same name, the file is removed and a directory is created. In the above example: if l1/l2 is a file it will be overwritten with a new directory. * If a directory exists and the archive contains a file with the same name, the directory will be replaced if it is empty. If it contains files, the result is an error. * An archive also can contain only a file without the parent directories. If in that case one of the parent directories exists as a file extracting the archive results in an error. In the example: if l1/l2 is a file and the archive doesn't contain the directories but only the file l1/l2/x.txt that would be an error. * In case of an error, it is possible that the archive has been partially extracted. Closes #4568
Diffstat (limited to 'cpukit/libmisc')
-rw-r--r--cpukit/libmisc/untar/untar.c57
1 files changed, 37 insertions, 20 deletions
diff --git a/cpukit/libmisc/untar/untar.c b/cpukit/libmisc/untar/untar.c
index a2f09fb99f..8888ab2c57 100644
--- a/cpukit/libmisc/untar/untar.c
+++ b/cpukit/libmisc/untar/untar.c
@@ -126,30 +126,25 @@ Make_Path(const rtems_printer *printer, char *path)
*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) {
+ if (errno == EEXIST) {
+ /* If it exists already: Check whether it is a directory */
struct stat sb;
-
- if (stat(path, &sb) != 0) {
+ if (lstat(path, &sb) != 0) {
+ Print_Error(printer, "lstat", path);
+ return -1;
+ } else if (!S_ISDIR(sb.st_mode)) {
+ rtems_printf(printer,
+ "untar: mkdir: %s: exists but is not a directory\n",
+ path);
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;
- }
- }
+ } else {
+ Print_Error(printer, "mkdir", path);
+ return -1;
}
}
@@ -206,6 +201,12 @@ Untar_ProcessHeader(
if (Make_Path(ctx->printer, ctx->file_path) != 0) {
retval = UNTAR_FAIL;
+ } else {
+ /*
+ * Speculatively unlink. This should unlink everything but non-empty
+ * directories or write protected stuff.
+ */
+ unlink(ctx->file_path);
}
if (ctx->linkflag == SYMTYPE) {
@@ -225,8 +226,22 @@ Untar_ProcessHeader(
rtems_printf(ctx->printer, "untar: dir: %s\n", ctx->file_path);
r = mkdir(ctx->file_path, ctx->mode);
if (r != 0) {
- Print_Error(ctx->printer, "mkdir", ctx->file_path);
- retval = UNTAR_FAIL;
+ if (errno == EEXIST) {
+ /* If it exists already: Check whether it is a directory */
+ struct stat sb;
+ if (lstat(ctx->file_path, &sb) != 0) {
+ Print_Error(ctx->printer, "lstat", ctx->file_path);
+ retval = UNTAR_FAIL;
+ } else if (!S_ISDIR(sb.st_mode)) {
+ rtems_printf(ctx->printer,
+ "untar: mkdir: %s: exists but is not a directory\n",
+ ctx->file_path);
+ retval = UNTAR_FAIL;
+ }
+ } else {
+ Print_Error(ctx->printer, "mkdir", ctx->file_path);
+ retval = UNTAR_FAIL;
+ }
}
}
@@ -426,7 +441,9 @@ Untar_FromFile_Print(
*/
if ((out_fd = creat(ctx.file_path, ctx.mode)) == -1) {
- (void) lseek(fd, SEEK_CUR, 512UL * ctx.nblocks);
+ /* Couldn't create that file. Abort. */
+ retval = UNTAR_FAIL;
+ break;
} else {
for (i = 0; i < ctx.nblocks; i++) {
n = read(fd, bufr, 512);