From d82db8e9a618ddd9a11cc57aff37f687abb0effb Mon Sep 17 00:00:00 2001 From: Ron Yorston Date: Sat, 16 Feb 2019 12:36:52 +0000 Subject: win32: make stat(2) fetch additional metadata Modify the WIN32 implementation of stat(2) to fetch inode number, device id and number of hardlinks. This requires opening a handle to the target file so it will be slower. A number of features can be enabled or start to work: - tar can detect if an archive is being stored in itself; - find can support the -inum and -links options; - ls can display inode numbers; - diff can detect attempts to compare a file with itself; - du has better support for hardlinked files; - cp can detect attempts to copy a file over itself. --- Config.in | 10 ++++++++++ archival/tar.c | 6 +++--- configs/mingw32_defconfig | 6 ++++-- configs/mingw64_defconfig | 6 ++++-- coreutils/ls.c | 4 ++++ editors/diff.c | 3 ++- findutils/find.c | 8 ++++++-- include/libbb.h | 2 +- include/mingw.h | 3 +++ libbb/Kbuild.src | 1 + libbb/copy_file.c | 2 +- win32/mingw.c | 39 +++++++++++++++++++++++++++++++++++---- 12 files changed, 74 insertions(+), 16 deletions(-) diff --git a/Config.in b/Config.in index 0318a6aff..9f8d4bf7c 100644 --- a/Config.in +++ b/Config.in @@ -463,6 +463,16 @@ config FEATURE_EURO requires the OEM code page to be 858. If the OEM code page of the console is 850 when BusyBox starts it's changed to 858. +config FEATURE_EXTRA_FILE_DATA + bool "Read additional file metadata (1.3 kb)" + default y + depends on PLATFORM_MINGW32 + help + Read additional file metadata: device id, inode number and number + of hard links. This may slow down some file operations but it + permits extra features such as warning of attempts to copy a file + onto itself or to store a tar archive in itself. + comment 'Build Options' config STATIC diff --git a/archival/tar.c b/archival/tar.c index b9ae93004..54989b953 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 +#if !ENABLE_PLATFORM_MINGW32 || 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,7 +529,7 @@ static int FAST_FUNC writeFileToTarball(const char *fileName, struct stat *statb } } -#if !ENABLE_PLATFORM_MINGW32 +#if !ENABLE_PLATFORM_MINGW32 || 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 */ @@ -707,7 +707,7 @@ static NOINLINE int writeTarFile( /*tbInfo->hlInfoHead = NULL; - already is */ -#if !ENABLE_PLATFORM_MINGW32 +#if !ENABLE_PLATFORM_MINGW32 || 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/configs/mingw32_defconfig b/configs/mingw32_defconfig index aec3b97e7..cb74f8c20 100644 --- a/configs/mingw32_defconfig +++ b/configs/mingw32_defconfig @@ -48,6 +48,8 @@ CONFIG_FEATURE_ICON=y # CONFIG_FEATURE_ICON_ATERM is not set # CONFIG_FEATURE_ICON_STERM is not set CONFIG_FEATURE_ICON_ALL=y +CONFIG_FEATURE_EURO=y +CONFIG_FEATURE_EXTRA_FILE_DATA=y # # Build Options @@ -457,7 +459,7 @@ CONFIG_FEATURE_FIND_EXECUTABLE=y # CONFIG_FEATURE_FIND_XDEV is not set CONFIG_FEATURE_FIND_MAXDEPTH=y CONFIG_FEATURE_FIND_NEWER=y -# CONFIG_FEATURE_FIND_INUM is not set +CONFIG_FEATURE_FIND_INUM=y CONFIG_FEATURE_FIND_EXEC=y CONFIG_FEATURE_FIND_EXEC_PLUS=y # CONFIG_FEATURE_FIND_USER is not set @@ -472,7 +474,7 @@ CONFIG_FEATURE_FIND_DELETE=y CONFIG_FEATURE_FIND_PATH=y CONFIG_FEATURE_FIND_REGEX=y # CONFIG_FEATURE_FIND_CONTEXT is not set -# CONFIG_FEATURE_FIND_LINKS is not set +CONFIG_FEATURE_FIND_LINKS=y CONFIG_GREP=y CONFIG_EGREP=y CONFIG_FGREP=y diff --git a/configs/mingw64_defconfig b/configs/mingw64_defconfig index 4fa2a1735..a0569b23a 100644 --- a/configs/mingw64_defconfig +++ b/configs/mingw64_defconfig @@ -48,6 +48,8 @@ CONFIG_FEATURE_ICON=y # CONFIG_FEATURE_ICON_ATERM is not set # CONFIG_FEATURE_ICON_STERM is not set CONFIG_FEATURE_ICON_ALL=y +CONFIG_FEATURE_EURO=y +CONFIG_FEATURE_EXTRA_FILE_DATA=y # # Build Options @@ -457,7 +459,7 @@ CONFIG_FEATURE_FIND_EXECUTABLE=y # CONFIG_FEATURE_FIND_XDEV is not set CONFIG_FEATURE_FIND_MAXDEPTH=y CONFIG_FEATURE_FIND_NEWER=y -# CONFIG_FEATURE_FIND_INUM is not set +CONFIG_FEATURE_FIND_INUM=y CONFIG_FEATURE_FIND_EXEC=y CONFIG_FEATURE_FIND_EXEC_PLUS=y # CONFIG_FEATURE_FIND_USER is not set @@ -472,7 +474,7 @@ CONFIG_FEATURE_FIND_DELETE=y CONFIG_FEATURE_FIND_PATH=y CONFIG_FEATURE_FIND_REGEX=y # CONFIG_FEATURE_FIND_CONTEXT is not set -# CONFIG_FEATURE_FIND_LINKS is not set +CONFIG_FEATURE_FIND_LINKS=y CONFIG_GREP=y CONFIG_EGREP=y CONFIG_FGREP=y diff --git a/coreutils/ls.c b/coreutils/ls.c index 48927c964..a1782ed45 100644 --- a/coreutils/ls.c +++ b/coreutils/ls.c @@ -499,7 +499,11 @@ static NOINLINE unsigned display_single(const struct dnode *dn) #endif if (opt & OPT_i) /* show inode# */ +#if !ENABLE_FEATURE_EXTRA_FILE_DATA column += printf("%7"LL_FMT"u ", (long long) dn->dn_ino); +#else + column += printf("%19"LL_FMT"u ", (long long) dn->dn_ino); +#endif //TODO: -h should affect -s too: if (opt & OPT_s) /* show allocated blocks */ column += printf("%6"OFF_FMT"u ", (off_t) (dn->dn_blocks >> 1)); diff --git a/editors/diff.c b/editors/diff.c index 929beb054..815c8a915 100644 --- a/editors/diff.c +++ b/editors/diff.c @@ -1039,7 +1039,8 @@ int diff_main(int argc UNUSED_PARAM, char **argv) * single NFS file system, if a local device number (st_dev) exceeds * 255, or if a local inode number (st_ino) exceeds 16777215. */ - if (ENABLE_DESKTOP && !ENABLE_PLATFORM_MINGW32 + if (ENABLE_DESKTOP + && (!ENABLE_PLATFORM_MINGW32 || ENABLE_FEATURE_EXTRA_FILE_DATA) && 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/findutils/find.c b/findutils/find.c index 06ad1b39c..0381f0685 100644 --- a/findutils/find.c +++ b/findutils/find.c @@ -121,7 +121,7 @@ //config:config FEATURE_FIND_INUM //config: bool "Enable -inum: inode number matching" //config: default y -//config: depends on FIND +//config: depends on FIND && (PLATFORM_POSIX || FEATURE_EXTRA_FILE_DATA) //config: //config:config FEATURE_FIND_EXEC //config: bool "Enable -exec: execute commands" @@ -227,7 +227,7 @@ //config:config FEATURE_FIND_LINKS //config: bool "Enable -links: link count matching" //config: default y -//config: depends on FIND +//config: depends on FIND && (PLATFORM_POSIX || FEATURE_EXTRA_FILE_DATA) //config: help //config: Support the 'find -links' option for matching number of links. @@ -1361,7 +1361,11 @@ static action*** parse_params(char **argv) action_inum *ap; dbg("%d", __LINE__); ap = ALLOC_ACTION(inum); +# if !ENABLE_FEATURE_EXTRA_FILE_DATA ap->inode_num = xatoul(arg1); +# else + ap->inode_num = xatoull(arg1); +# endif } #endif #if ENABLE_FEATURE_FIND_USER diff --git a/include/libbb.h b/include/libbb.h index 0c7e03ee8..61574b5ee 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -1712,7 +1712,7 @@ int bb_xioctl(int fd, unsigned request, void *argp) FAST_FUNC; #define xioctl(fd,request,argp) bb_xioctl(fd,request,argp) #endif -#if !ENABLE_PLATFORM_MINGW32 +#if !ENABLE_PLATFORM_MINGW32 || ENABLE_FEATURE_EXTRA_FILE_DATA char *is_in_ino_dev_hashtable(const struct stat *statbuf) FAST_FUNC; void add_to_ino_dev_hashtable(const struct stat *statbuf, const char *name) FAST_FUNC; void reset_ino_dev_hashtable(void) FAST_FUNC; diff --git a/include/mingw.h b/include/mingw.h index 185eb66ed..0f403b993 100644 --- a/include/mingw.h +++ b/include/mingw.h @@ -283,6 +283,9 @@ int mingw_chmod(const char *path, int mode); typedef int nlink_t; typedef int blksize_t; typedef off_t blkcnt_t; +#if ENABLE_FEATURE_EXTRA_FILE_DATA +#define ino_t uint64_t +#endif struct mingw_stat { dev_t st_dev; diff --git a/libbb/Kbuild.src b/libbb/Kbuild.src index b298040ac..799f6d01a 100644 --- a/libbb/Kbuild.src +++ b/libbb/Kbuild.src @@ -98,6 +98,7 @@ lib-$(CONFIG_PLATFORM_POSIX) += getpty.o lib-$(CONFIG_PLATFORM_POSIX) += get_volsize.o lib-$(CONFIG_PLATFORM_POSIX) += inet_common.o lib-$(CONFIG_PLATFORM_POSIX) += inode_hash.o +lib-$(CONFIG_FEATURE_EXTRA_FILE_DATA) += inode_hash.o lib-$(CONFIG_PLATFORM_POSIX) += kernel_version.o lib-$(CONFIG_PLATFORM_POSIX) += login.o lib-$(CONFIG_PLATFORM_POSIX) += makedev.o diff --git a/libbb/copy_file.c b/libbb/copy_file.c index 299cd7bea..db7a00060 100644 --- a/libbb/copy_file.c +++ b/libbb/copy_file.c @@ -105,7 +105,7 @@ int FAST_FUNC copy_file(const char *source, const char *dest, int flags) return -1; } } else { -#if !ENABLE_PLATFORM_MINGW32 +#if !ENABLE_PLATFORM_MINGW32 || ENABLE_FEATURE_EXTRA_FILE_DATA /* MinGW does not have inode, and does not use device */ if (source_stat.st_dev == dest_stat.st_dev && source_stat.st_ino == dest_stat.st_ino diff --git a/win32/mingw.c b/win32/mingw.c index 8217ec772..03636a04b 100644 --- a/win32/mingw.c +++ b/win32/mingw.c @@ -403,7 +403,7 @@ static int do_lstat(int follow, const char *file_name, struct mingw_stat *buf) buf->st_ino = 0; buf->st_uid = DEFAULT_UID; buf->st_gid = DEFAULT_GID; - buf->st_nlink = 1; + buf->st_nlink = S_ISDIR(buf->st_mode) ? 2 : 1; buf->st_mode = file_attr_to_st_mode(fdata.dwFileAttributes); if (S_ISREG(buf->st_mode) && (has_exe_suffix(file_name) || has_exec_format(file_name))) @@ -434,6 +434,30 @@ static int do_lstat(int follow, const char *file_name, struct mingw_stat *buf) } } +#if ENABLE_FEATURE_EXTRA_FILE_DATA + { + BY_HANDLE_FILE_INFORMATION hdata; + HANDLE fh = CreateFile(file_name, 0, + 0, NULL, OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL|FILE_FLAG_BACKUP_SEMANTICS, + NULL); + if (fh != INVALID_HANDLE_VALUE) { + if (GetFileInformationByHandle(fh, &hdata)) { + buf->st_dev = hdata.dwVolumeSerialNumber; + buf->st_ino = hdata.nFileIndexLow | + (((uint64_t)hdata.nFileIndexHigh)<<32); + buf->st_nlink = S_ISDIR(buf->st_mode) ? 2 : + hdata.nNumberOfLinks; + } + CloseHandle(fh); + } + else { + errno = err_win_to_posix(GetLastError()); + return -1; + } + } +#endif + /* * Assume a block is 4096 bytes and calculate number of 512 byte * sectors. @@ -522,12 +546,19 @@ int mingw_fstat(int fd, struct mingw_stat *buf) buf->st_ctime = filetime_to_time_t(&(fdata.ftCreationTime)); buf->st_blocks = ((buf->st_size+4095)>>12)<<3; success: - buf->st_dev = buf->st_rdev = 0; +#if ENABLE_FEATURE_EXTRA_FILE_DATA + buf->st_dev = fdata.dwVolumeSerialNumber; + buf->st_ino = fdata.nFileIndexLow | + (((uint64_t)fdata.nFileIndexHigh)<<32); + buf->st_nlink = S_ISDIR(buf->st_mode) ? 2 : fdata.nNumberOfLinks; +#else + buf->st_dev = 0; buf->st_ino = 0; + buf->st_nlink = S_ISDIR(buf->st_mode) ? 2 : 1; +#endif + buf->st_rdev = 0; buf->st_uid = DEFAULT_UID; buf->st_gid = DEFAULT_GID; - /* could use fdata.nNumberOfLinks but it's inconsistent with stat */ - buf->st_nlink = 1; buf->st_blksize = 4096; return 0; } -- cgit v1.2.3-55-g6feb