From cd4fe97852bcaeffe674ee51b4613709292a0972 Mon Sep 17 00:00:00 2001 From: Lasse Collin Date: Sun, 10 Apr 2011 12:47:47 +0300 Subject: [PATCH] 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. --- src/xz/file_io.c | 35 +++++++++++++++++++++++++++++++++-- 1 file 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"),