aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLasse Collin <lasse.collin@tukaani.org>2011-04-10 12:47:47 +0300
committerLasse Collin <lasse.collin@tukaani.org>2011-04-10 12:47:47 +0300
commitcd4fe97852bcaeffe674ee51b4613709292a0972 (patch)
treec953e2ecb479ff2b183dce5e7f7ac97a4d184277
parentUpdate THANKS. (diff)
downloadxz-cd4fe97852bcaeffe674ee51b4613709292a0972.tar.xz
xz/DOS: Be more careful with the destination file.
Try to avoid overwriting the source file if --force is used and the generated destination filename refers to the source file. This can happen with 8.3 filenames where extra characters are ignored. If the generated output file refers to a special file like "con" or "prn", refuse to write to it even if --force is used.
-rw-r--r--src/xz/file_io.c35
1 files changed, 33 insertions, 2 deletions
diff --git a/src/xz/file_io.c b/src/xz/file_io.c
index 5eba9d87..5555891b 100644
--- a/src/xz/file_io.c
+++ b/src/xz/file_io.c
@@ -68,8 +68,7 @@ io_init(void)
#ifdef __DJGPP__
// Avoid doing useless things when statting files.
// This isn't important but doesn't hurt.
- _djstat_flags = _STAT_INODE | _STAT_EXEC_EXT
- | _STAT_EXEC_MAGIC | _STAT_DIRSIZE;
+ _djstat_flags = _STAT_EXEC_EXT | _STAT_EXEC_MAGIC | _STAT_DIRSIZE;
#endif
return;
@@ -452,8 +451,18 @@ io_open_src_real(file_pair *pair)
// Stat the source file. We need the result also when we copy
// the permissions, and when unlinking.
+ //
+ // NOTE: Use stat() instead of fstat() with DJGPP, because
+ // then we have a better chance to get st_ino value that can
+ // be used in io_open_dest_real() to prevent overwriting the
+ // source file.
+#ifdef __DJGPP__
+ if (stat(pair->src_name, &pair->src_st))
+ goto error_msg;
+#else
if (fstat(pair->src_fd, &pair->src_st))
goto error_msg;
+#endif
if (S_ISDIR(pair->src_st.st_mode)) {
message_warning(_("%s: Is a directory, skipping"),
@@ -599,6 +608,28 @@ io_open_dest_real(file_pair *pair)
if (pair->dest_name == NULL)
return true;
+#ifdef __DJGPP__
+ struct stat st;
+ if (stat(pair->dest_name, &st) == 0) {
+ // Check that it isn't a special file like "prn".
+ if (st.st_dev == -1) {
+ message_error("%s: Refusing to write to "
+ "a DOS special file",
+ pair->dest_name);
+ return true;
+ }
+
+ // Check that we aren't overwriting the source file.
+ if (st.st_dev == pair->src_st.st_dev
+ && st.st_ino == pair->src_st.st_ino) {
+ message_error("%s: Output file is the same "
+ "as the input file",
+ pair->dest_name);
+ return true;
+ }
+ }
+#endif
+
// If --force was used, unlink the target file first.
if (opt_force && unlink(pair->dest_name) && errno != ENOENT) {
message_error(_("%s: Cannot remove: %s"),