From 8c47a98c9166ff23c3bcbb3e1ef8430b349cf71e Mon Sep 17 00:00:00 2001
From: Ron Yorston <rmy@pobox.com>
Date: Tue, 19 Feb 2019 10:59:45 +0000
Subject: win32: stat(2) succeeds if fetching extra metadata fails

Some files can't be opened to fetch additional metadata.  When
that happens allow stat(2) to successfully return what data it
has.

In a few cases where the inode number is used to determine if
files are identical ignore invalid inode numbers.
---
 archival/tar.c     |  8 +++++---
 editors/diff.c     |  4 +++-
 libbb/copy_file.c  |  5 +++--
 libbb/inode_hash.c |  5 +++++
 win32/mingw.c      | 14 +++-----------
 5 files changed, 19 insertions(+), 17 deletions(-)

diff --git a/archival/tar.c b/archival/tar.c
index 54989b953..3375d1fe9 100644
--- a/archival/tar.c
+++ b/archival/tar.c
@@ -161,7 +161,7 @@ typedef struct TarBallInfo {
 # endif
 	HardLinkInfo *hlInfoHead;       /* Hard Link Tracking Information */
 	HardLinkInfo *hlInfo;           /* Hard Link Info for the current file */
-#if !ENABLE_PLATFORM_MINGW32 || ENABLE_FEATURE_EXTRA_FILE_DATA
+#if ENABLE_PLATFORM_POSIX || ENABLE_FEATURE_EXTRA_FILE_DATA
 //TODO: save only st_dev + st_ino
 	struct stat tarFileStatBuf;     /* Stat info for the tarball, letting
 	                                 * us know the inode and device that the
@@ -529,12 +529,14 @@ static int FAST_FUNC writeFileToTarball(const char *fileName, struct stat *statb
 		}
 	}
 
-#if !ENABLE_PLATFORM_MINGW32 || ENABLE_FEATURE_EXTRA_FILE_DATA
+#if ENABLE_PLATFORM_POSIX || ENABLE_FEATURE_EXTRA_FILE_DATA
 	/* It is a bad idea to store the archive we are in the process of creating,
 	 * so check the device and inode to be sure that this particular file isn't
 	 * the new tarball */
 	if (tbInfo->tarFileStatBuf.st_dev == statbuf->st_dev
 	 && tbInfo->tarFileStatBuf.st_ino == statbuf->st_ino
+	 /* ignore invalid inode numbers */
+	 && (ENABLE_FEATURE_EXTRA_FILE_DATA && statbuf->st_ino != 0)
 	) {
 		bb_error_msg("%s: file is the archive; skipping", fileName);
 		return TRUE;
@@ -707,7 +709,7 @@ static NOINLINE int writeTarFile(
 
 	/*tbInfo->hlInfoHead = NULL; - already is */
 
-#if !ENABLE_PLATFORM_MINGW32 || ENABLE_FEATURE_EXTRA_FILE_DATA
+#if ENABLE_PLATFORM_POSIX || ENABLE_FEATURE_EXTRA_FILE_DATA
 	/* Store the stat info for the tarball's file, so
 	 * can avoid including the tarball into itself....  */
 	xfstat(tbInfo->tarFd, &tbInfo->tarFileStatBuf, "can't stat tar file");
diff --git a/editors/diff.c b/editors/diff.c
index 815c8a915..308d9782b 100644
--- a/editors/diff.c
+++ b/editors/diff.c
@@ -1040,7 +1040,9 @@ int diff_main(int argc UNUSED_PARAM, char **argv)
 	 * 255, or if a local inode number (st_ino) exceeds 16777215.
 	 */
 	if (ENABLE_DESKTOP
-	 && (!ENABLE_PLATFORM_MINGW32 || ENABLE_FEATURE_EXTRA_FILE_DATA)
+	 && (ENABLE_PLATFORM_POSIX || ENABLE_FEATURE_EXTRA_FILE_DATA)
+	 /* ignore invalid inode numbers */
+	 && (ENABLE_FEATURE_EXTRA_FILE_DATA && stb[0].st_ino != 0)
 	 && stb[0].st_ino == stb[1].st_ino
 	 && stb[0].st_dev == stb[1].st_dev
 	 && stb[0].st_size == stb[1].st_size
diff --git a/libbb/copy_file.c b/libbb/copy_file.c
index db7a00060..abe034f50 100644
--- a/libbb/copy_file.c
+++ b/libbb/copy_file.c
@@ -105,10 +105,11 @@ int FAST_FUNC copy_file(const char *source, const char *dest, int flags)
 			return -1;
 		}
 	} else {
-#if !ENABLE_PLATFORM_MINGW32 || ENABLE_FEATURE_EXTRA_FILE_DATA
-        /* MinGW does not have inode, and does not use device */
+#if ENABLE_PLATFORM_POSIX || ENABLE_FEATURE_EXTRA_FILE_DATA
 		if (source_stat.st_dev == dest_stat.st_dev
 		 && source_stat.st_ino == dest_stat.st_ino
+		 /* ignore invalid inode numbers */
+		 && (ENABLE_FEATURE_EXTRA_FILE_DATA && source_stat.st_ino != 0)
 		) {
 			bb_error_msg("'%s' and '%s' are the same file", source, dest);
 			return -1;
diff --git a/libbb/inode_hash.c b/libbb/inode_hash.c
index 4142813e3..37fed9c82 100644
--- a/libbb/inode_hash.c
+++ b/libbb/inode_hash.c
@@ -61,6 +61,11 @@ void FAST_FUNC add_to_ino_dev_hashtable(const struct stat *statbuf, const char *
 	int i;
 	ino_dev_hashtable_bucket_t *bucket;
 
+#if ENABLE_FEATURE_EXTRA_FILE_DATA
+	/* ignore invalid inode numbers */
+	if (statbuf->st_ino == 0)
+		return;
+#endif
 	if (!name)
 		name = "";
 	bucket = xmalloc(sizeof(ino_dev_hashtable_bucket_t) + strlen(name));
diff --git a/win32/mingw.c b/win32/mingw.c
index 3713fea95..84522d3ea 100644
--- a/win32/mingw.c
+++ b/win32/mingw.c
@@ -441,22 +441,14 @@ static int do_lstat(int follow, const char *file_name, struct mingw_stat *buf)
 #if ENABLE_FEATURE_EXTRA_FILE_DATA
 		fh = CreateFile(file_name, 0, 0, NULL, OPEN_EXISTING,
 							FILE_FLAG_BACKUP_SEMANTICS, NULL);
-		if (fh == INVALID_HANDLE_VALUE)
-			goto error;
-
-		if (GetFileInformationByHandle(fh, &hdata)) {
+		if (fh != INVALID_HANDLE_VALUE &&
+				GetFileInformationByHandle(fh, &hdata)) {
 			buf->st_dev = hdata.dwVolumeSerialNumber;
 			buf->st_ino = hdata.nFileIndexLow |
 							(((ino_t)hdata.nFileIndexHigh)<<32);
 			buf->st_nlink = S_ISDIR(buf->st_mode) ? 2 : hdata.nNumberOfLinks;
-			CloseHandle(fh);
-		}
-		else {
- error:
-			errno = err_win_to_posix(GetLastError());
-			CloseHandle(fh);
-			return -1;
 		}
+		CloseHandle(fh);
 #endif
 
 		/*
-- 
cgit v1.2.3-55-g6feb