Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package jdupes for openSUSE:Factory checked 
in at 2022-12-07 17:35:21
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/jdupes (Old)
 and      /work/SRC/openSUSE:Factory/.jdupes.new.1835 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "jdupes"

Wed Dec  7 17:35:21 2022 rev:3 rq:1040814 version:1.21.1

Changes:
--------
--- /work/SRC/openSUSE:Factory/jdupes/jdupes.changes    2022-03-22 
19:39:51.799068706 +0100
+++ /work/SRC/openSUSE:Factory/.jdupes.new.1835/jdupes.changes  2022-12-07 
17:36:41.669107316 +0100
@@ -1,0 +2,16 @@
+Tue Dec  6 21:35:51 UTC 2022 - Dirk Müller <dmuel...@suse.com>
+
+- update to 1.21.1:
+  * Reinstate '-I/--isolate' by popular demand; use at your own risk!
+  * Expect to lose data if you use this feature. It is strongly susceptible
+    to the documented "triangle problem" and absolutely does not protect
+    files in each directory from matching with one another. Don't get mad at
+    me if you use it and see a cloud of smoke come out of your disk array.
+  * Remove '-I/--isolate' which has never worked correctly
+  * Fix compiling when NO_HARDLINKS and NO_SYMLINKS are both defined
+  * Increased stack size limits to enable deeper recursion without crashing
+  * Fixes to make compilation under Cygwin (instead of MSYS2 MinGW) work
+  * Remove the temporary '-X help' warning about changes in functionality
+  * Some minor under-the-hood changes for future enhancements
+
+-------------------------------------------------------------------

Old:
----
  v1.20.2.tar.gz

New:
----
  v1.21.1.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ jdupes.spec ++++++
--- /var/tmp/diff_new_pack.c2mZNx/_old  2022-12-07 17:36:42.125109813 +0100
+++ /var/tmp/diff_new_pack.c2mZNx/_new  2022-12-07 17:36:42.129109835 +0100
@@ -18,7 +18,7 @@
 
 
 Name:           jdupes
-Version:        1.20.2
+Version:        1.21.1
 Release:        0
 Summary:        A powerful duplicate file finder and an enhanced fork of 
'fdupes'
 License:        MIT

++++++ v1.20.2.tar.gz -> v1.21.1.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/jdupes-1.20.2/.dockerignore 
new/jdupes-1.21.1/.dockerignore
--- old/jdupes-1.20.2/.dockerignore     1970-01-01 01:00:00.000000000 +0100
+++ new/jdupes-1.21.1/.dockerignore     2022-12-01 18:46:17.000000000 +0100
@@ -0,0 +1,3 @@
+.*
+example_scripts
+testdir
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/jdupes-1.20.2/.github/ISSUE_TEMPLATE/template-for-all-issue-submissions.md 
new/jdupes-1.21.1/.github/ISSUE_TEMPLATE/template-for-all-issue-submissions.md
--- 
old/jdupes-1.20.2/.github/ISSUE_TEMPLATE/template-for-all-issue-submissions.md  
    1970-01-01 01:00:00.000000000 +0100
+++ 
new/jdupes-1.21.1/.github/ISSUE_TEMPLATE/template-for-all-issue-submissions.md  
    2022-12-01 18:46:17.000000000 +0100
@@ -0,0 +1,43 @@
+---
+name: Template for all Issue submissions
+about: Use this template for all submissions, including bug reports and 
feature requests
+title: ''
+labels: ''
+assignees: ''
+
+---
+
+<!-- Run `jdupes -v` to get your version information, i.e. "jdupes 1.20.2 
(2021-11-02) 64-bit i32" -->
+**What jdupes version are you using?**
+
+`paste version within these backquotes`
+
+
+<!-- Change the box to [x] with your answer -->
+**Where did you get your copy of the jdupes binary?**
+
+[ ] Official binary from jdupes releases
+[ ] OS distribution repository (Linux, Homebrew, etc. - put distro's 
name/version in text block below)
+[ ] I personally compiled it from source code (paste your build commands in 
the text block below)
+[ ] Other (please explain below)
+
+```
+No additional information provided (replace this line with info requested 
above as needed)
+```
+
+
+<!-- Certify that you've searched through Issues before adding yours. Failure 
to do this will result in immediate closure or deletion of your issue. -->
+**Have you searched in Issues?**
+
+[ ] I have searched for my problem in Issues and I am confident that this is 
not a duplicate of a previous reported issue or feature request.
+
+
+<!--Certify that you're not posting about common non-issues. We see a lot of 
submissions that wouldn't exist if people read the documentation and code 
before making them. -->
+**I have done my due diligence**
+
+[ ] I am not suggesting changing the hash algorithm, storing files in a 
database, comparing file data blocks differently, suggesting that file sizes 
should be used before comparison, or other common suggestions that indicate I 
haven't read the documentation, code, or examined the issue tracker entries to 
discover that all of these things have already been implemented or won't make a 
difference if they were implemented. I have done my due diligence before asking 
for help or making a suggestion.
+
+<!-- Describe the issue you're having or feature you're requesting. Be as 
clear and detailed as possible. -->
+**Issue or feature request details**
+
+blah blah blah, I didn't fill this out, please close my request
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/jdupes-1.20.2/.github/workflows/main.yml 
new/jdupes-1.21.1/.github/workflows/main.yml
--- old/jdupes-1.20.2/.github/workflows/main.yml        1970-01-01 
01:00:00.000000000 +0100
+++ new/jdupes-1.21.1/.github/workflows/main.yml        2022-12-01 
18:46:17.000000000 +0100
@@ -0,0 +1,56 @@
+name: ci
+
+on:
+  push:
+    branches:
+      - 'master'
+      - 'github-action'
+
+jobs:
+  docker:
+    runs-on: ubuntu-latest
+    
+    steps:
+      - name: set lower case owner name
+        run: |
+          echo "OWNER_LC=${OWNER,,}" >>${GITHUB_ENV}
+        env:
+          OWNER: '${{ github.repository_owner }}'
+      -
+        name: Checkout
+        uses: actions/checkout@v2
+      -
+        name: Set up QEMU
+        uses: docker/setup-qemu-action@v1
+      -
+        name: Set up Docker Buildx
+        uses: docker/setup-buildx-action@v1
+      -
+        name: Login to GitHub Container Registry
+        uses: docker/login-action@v1 
+        with:
+          registry: ghcr.io
+          username: ${{ env.OWNER_LC }}
+          password: ${{ secrets.PERSONAL_ACCESS_TOKEN }}
+      -
+        name: Build and push slim
+        uses: docker/build-push-action@v2
+        with:
+          context: .
+          file: docker/slim.Dockerfile
+          platforms: linux/amd64
+          push: true
+          tags: |
+            ghcr.io/${{ env.OWNER_LC }}/jdupes:latest
+            ghcr.io/${{ env.OWNER_LC }}/jdupes:${{ github.ref_name }}          
  
+      -
+        name: Build and push alpine
+        uses: docker/build-push-action@v2
+        with:
+          context: .
+          file: docker/alpine.Dockerfile
+          platforms: linux/amd64
+          push: true
+          tags: |
+            ghcr.io/${{ env.OWNER_LC }}/jdupes:alpine
+            ghcr.io/${{ env.OWNER_LC }}/jdupes:${{ github.ref_name }}-alpine
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/jdupes-1.20.2/CHANGES new/jdupes-1.21.1/CHANGES
--- old/jdupes-1.20.2/CHANGES   2021-11-03 03:54:09.000000000 +0100
+++ new/jdupes-1.21.1/CHANGES   2022-12-01 18:46:17.000000000 +0100
@@ -1,3 +1,16 @@
+jdupes 1.21.1
+
+- Reinstate '-I/--isolate' by popular demand; use at your own risk!
+
+jdupes 1.21.0
+
+- Remove '-I/--isolate' which has never worked correctly
+- Fix compiling when NO_HARDLINKS and NO_SYMLINKS are both defined
+- Increased stack size limits to enable deeper recursion without crashing
+- Fixes to make compilation under Cygwin (instead of MSYS2 MinGW) work
+- Remove the temporary '-X help' warning about changes in functionality
+- Some minor under-the-hood changes for future enhancements
+
 jdupes 1.20.2
 
 - Interactive deletion now offers "link set" options too
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/jdupes-1.20.2/INSTALL new/jdupes-1.21.1/INSTALL
--- old/jdupes-1.20.2/INSTALL   2021-11-03 03:54:09.000000000 +0100
+++ new/jdupes-1.21.1/INSTALL   2022-12-01 18:46:17.000000000 +0100
@@ -11,6 +11,15 @@
 to a different location by editing the Makefile or specifying a PREFIX on the
 command line: make PREFIX=/usr install
 
+On Windows, you need to use MSYS2 with MinGW-w64 installed. Use this guide to
+install the build environment:
+
+https://stackoverflow.com/a/30071634/1906641
+
+Running "make" as usual under the MSYS2 mingw32/mingw64 terminal will build a
+Windows binary for the bitness of the terminal you're using. The Makefile will
+detect a Windows environment and automatically make the needed build changes.
+
 Various build options are available and can be turned on at compile time by
 setting CFLAGS_EXTRA or by passing it to 'make':
 
@@ -21,19 +30,22 @@
 
 OMIT_GETOPT_LONG       Do not use getopt_long() C library call
 ON_WINDOWS             Modify code to compile with MinGW on Windows
+NO_WINDOWS             Disable Windows MinGW special cases (mainly for Cygwin)
+NO_PERMS               Disable permission options and code
+NO_HARDLINKS           Disable hard linking options and code
+NO_SYMLINKS            Disable symbolic linking options and code
+NO_USER_ORDER          Disable -I/-O options and code
+NO_MTIME               Disable all modify time features and code
+NO_ATIME               Disable all access time features and code
 
-Certain options need to be turned on by setting a variable passed to make
-instead of using CFLAGS_EXTRA, i.e. 'make DEBUG=1':
+Certain options can be turned on by setting a variable passed to make instead
+of using CFLAGS_EXTRA, i.e. 'make DEBUG=1':
 
 DEBUG                  Turn on algorithm statistic reporting with '-D'
 LOUD                   '-@' for low-level debugging; enables DEBUG
 ENABLE_DEDUPE          Enable '-B/--dedupe' deduplication features
 STATIC_DEDUPE_H        Build dedupe support with included minimal header file
 LOW_MEMORY             Build for extremely low-RAM environments (CAUTION!)
-NO_PERMS               Disable permission options and code
-NO_HARDLINKS           Disable hard linking options and code
-NO_SYMLINKS            Disable symbolic linking options and code
-NO_USER_ORDER          Disable -I/-O options and code
 NO_UNICODE             [Windows only] disable all Unicode support
 
 The LOW_MEMORY option tweaks various knobs in the program to lower total
@@ -61,3 +73,14 @@
 
 chrootpackage  Uses chroots under /chroot to build Linux packages
 package        Makes auto-detected macOS/Linux/Windows packages
+
+Windows builds do not support dedupe or symbolic links. Dedupe would only work
+in ReFS which was removed from all non-enterprise Windows 10 editions, so it
+will likely never be supported for Windows builds of jdupes. Symbolic linking
+is supported on Windows, but on all versions of Windows before Windows 10 1703
+(the "Creators Update"), creating symlinks required administrative escalation.
+Symlinks can be dangerous on Windows because most Windows software is symlink-
+unaware. Support can be added in the future, but it is not a priority. If you
+are interested in seeing symlink support added, leave a +1 comment here:
+
+https://github.com/jbruchon/jdupes/issues/194
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/jdupes-1.20.2/LICENSE new/jdupes-1.21.1/LICENSE
--- old/jdupes-1.20.2/LICENSE   2021-11-03 03:54:09.000000000 +0100
+++ new/jdupes-1.21.1/LICENSE   2022-12-01 18:46:17.000000000 +0100
@@ -1,6 +1,6 @@
 The MIT License (MIT)
 
-Copyright (C) 2015-2021 Jody Lee Bruchon and contributors
+Copyright (C) 2015-2022 Jody Lee Bruchon and contributors
 Forked from fdupes 1.51, Copyright (C) 1999-2014 Adrian Lopez and contributors
 
 Permission is hereby granted, free of charge, to any person obtaining a copy of
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/jdupes-1.20.2/Makefile new/jdupes-1.21.1/Makefile
--- old/jdupes-1.20.2/Makefile  2021-11-03 03:54:09.000000000 +0100
+++ new/jdupes-1.21.1/Makefile  2022-12-01 18:46:17.000000000 +0100
@@ -55,18 +55,25 @@
 COMPILER_OPTIONS = -Wall -Wwrite-strings -Wcast-align -Wstrict-aliasing 
-Wstrict-prototypes -Wpointer-arith -Wundef
 COMPILER_OPTIONS += -Wshadow -Wfloat-equal -Waggregate-return -Wcast-qual 
-Wswitch-default -Wswitch-enum -Wconversion -Wunreachable-code -Wformat=2
 COMPILER_OPTIONS += -std=gnu99 -O2 -g -D_FILE_OFFSET_BITS=64 -fstrict-aliasing 
-pipe
-COMPILER_OPTIONS += -DSMA_MAX_FREE=11
+COMPILER_OPTIONS += -DSMA_MAX_FREE=11 -DNO_ATIME
 
 #####################################################################
 # no need to modify anything beyond this point                      #
 #####################################################################
 
 # Don't use unsupported compiler options on gcc 3/4 (OS X 10.5.8 Xcode)
-GCCVERSION = $(shell expr `gcc -v 2>&1 | grep 'gcc version ' | cut -d\  -f3 | 
cut -d. -f1` \>= 5)
+GCCVERSION = $(shell expr `LC_ALL=C gcc -v 2>&1 | grep 'gcc version ' | cut 
-d\  -f3 | cut -d. -f1` \>= 5)
 ifeq "$(GCCVERSION)" "1"
        COMPILER_OPTIONS += -Wextra -Wstrict-overflow=5 -Winit-self
 endif
 
+# Are we running on a Windows OS?
+ifeq ($(OS), Windows_NT)
+       ifndef NO_WINDOWS
+               ON_WINDOWS=1
+       endif
+endif
+
 # Debugging code inclusion
 ifdef LOUD
 DEBUG=1
@@ -92,7 +99,7 @@
 UNAME_S=$(shell uname -s)
 
 # MinGW needs this for printf() conversions to work
-ifeq ($(OS), Windows_NT)
+ifdef ON_WINDOWS
        ifndef NO_UNICODE
                UNICODE=1
                COMPILER_OPTIONS += -municode
@@ -108,6 +115,16 @@
        override undefine ENABLE_DEDUPE
 endif
 
+# Stack size limit can be too small for deep directory trees, so set to 16 MiB
+# The ld syntax for Windows is the same for both Cygwin and MinGW
+ifeq ($(OS), Windows_NT)
+COMPILER_OPTIONS += -Wl,--stack=16777216
+else ifeq ($(UNAME_S), Darwin)
+COMPILER_OPTIONS += -Wl,-stack_size -Wl,0x1000000
+else
+COMPILER_OPTIONS += -Wl,-z,stack-size=16777216
+endif
+
 # Don't do clonefile on Mac OS X < 10.13 (High Sierra)
 ifeq ($(UNAME_S), Darwin)
        DARWINVER := $(shell expr `uname -r | cut -d. -f1` \< 17)
@@ -137,7 +154,7 @@
 
 # Low memory mode
 ifdef LOW_MEMORY
-COMPILER_OPTIONS += -DLOW_MEMORY -DSMA_PAGE_SIZE=32768 -DCHUNK_SIZE=16384 
-DNO_HARDLINKS -DNO_SYMLINKS -DNO_USER_ORDER -DNO_PERMS
+COMPILER_OPTIONS += -DLOW_MEMORY -DSMA_PAGE_SIZE=32768 -DCHUNK_SIZE=16384 
-DNO_HARDLINKS -DNO_SYMLINKS -DNO_USER_ORDER -DNO_PERMS -DNO_ATIME
 endif
 
 CFLAGS += $(COMPILER_OPTIONS) $(CFLAGS_EXTRA)
@@ -198,7 +215,7 @@
        strip $(PROGRAM_NAME)$(PROGRAM_SUFFIX)
 
 clean:
-       $(RM) $(OBJS) $(OBJS_CLEAN) build_date.h $(PROGRAM_NAME) 
$(PROGRAM_NAME).exe *~ *.gcno *.gcda *.gcov
+       $(RM) $(OBJS) $(OBJS_CLEAN) build_date.h $(PROGRAM_NAME) 
$(PROGRAM_NAME).exe *~ .*.un~ *.gcno *.gcda *.gcov
 
 distclean: clean
        $(RM) *.pkg.tar.*
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/jdupes-1.20.2/README.md new/jdupes-1.21.1/README.md
--- old/jdupes-1.20.2/README.md 2021-11-03 03:54:09.000000000 +0100
+++ new/jdupes-1.21.1/README.md 2022-12-01 18:46:17.000000000 +0100
@@ -142,6 +142,10 @@
 ```
 Usage: jdupes [options] DIRECTORY...
 ```
+### Or with Docker
+```
+docker run -it --init -v /path/to/dir:/data ghcr.io/jbruchon/jdupes:latest 
[options] /data
+```
 
 Duplicate file sets will be printed by default unless a different action
 option is specified (delete, summarize, link, dedupe, etc.)
@@ -387,6 +391,8 @@
 
 `-@@->` File was symlinked to the first file in the chain
 
+`-##->` File was cloned from the first file in the chain
+
 `-==->` Already a hard link to the first file in the chain
 
 `-//->` File linking failed due to an error during the linking process
@@ -533,9 +539,9 @@
 
 Legal information and software license
 -------------------------------------------------------------------------------
-jdupes is Copyright (C) 2015-2021 by Jody Bruchon <j...@jodybruchon.com>
+jdupes is Copyright (C) 2015-2022 by Jody Bruchon <j...@jodybruchon.com>
 Derived from the original 'fdupes' 1.51 (C) 1999-2014 by Adrian Lopez
-Includes other code libraries which are (C) 2015-2021 by Jody Bruchon
+Includes other code libraries which are (C) 2015-2022 by Jody Bruchon
 
 The MIT License
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/jdupes-1.20.2/README.stupid_dupes 
new/jdupes-1.21.1/README.stupid_dupes
--- old/jdupes-1.20.2/README.stupid_dupes       2021-11-03 03:54:09.000000000 
+0100
+++ new/jdupes-1.21.1/README.stupid_dupes       2022-12-01 18:46:17.000000000 
+0100
@@ -35,7 +35,7 @@
 
 Legal information and software license
 -------------------------------------------------------------------------------
-Copyright (C) 2020-2021 by Jody Bruchon <j...@jodybruchon.com> and contributors
+Copyright (C) 2020-2022 by Jody Bruchon <j...@jodybruchon.com> and contributors
 and for some reason Jody is willing to admit to writing it.
 
 The MIT License
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/jdupes-1.20.2/act_deletefiles.c 
new/jdupes-1.21.1/act_deletefiles.c
--- old/jdupes-1.20.2/act_deletefiles.c 2021-11-03 03:54:09.000000000 +0100
+++ new/jdupes-1.21.1/act_deletefiles.c 2022-12-01 18:46:17.000000000 +0100
@@ -113,7 +113,11 @@
 
         token = strtok(preservestr, " ,\n");
         if (token != NULL) {
+#if defined NO_HARDLINKS && defined NO_SYMLINKS
+          /* no linktype needed */
+#else
           int linktype = -1;
+#endif /* defined NO_HARDLINKS && defined NO_SYMLINKS */
           /* "Delete none" = stop parsing string */
           if (*token == 'n' || *token == 'N') goto stop_scanning;
           /* If requested, link this set instead */
@@ -123,10 +127,14 @@
 #ifndef NO_SYMLINKS
           if (*token == 's' || *token == 'S') linktype = 0; /* symlink */
 #endif
+#if defined NO_HARDLINKS && defined NO_SYMLINKS
+         /* no linking calls */
+#else
           if (linktype != -1) {
             linkfiles(files, linktype, 1);
             goto skip_deletion;
           }
+#endif /* defined NO_HARDLINKS && defined NO_SYMLINKS */
         }
 
         while (token != NULL) {
@@ -172,7 +180,11 @@
           }
         }
       }
+#if defined NO_HARDLINKS && defined NO_SYMLINKS
+      /* label not needed */
+#else
 skip_deletion:
+#endif /* defined NO_HARDLINKS && defined NO_SYMLINKS */
       printf("\n");
     }
   }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/jdupes-1.20.2/act_linkfiles.c 
new/jdupes-1.21.1/act_linkfiles.c
--- old/jdupes-1.20.2/act_linkfiles.c   2021-11-03 03:54:09.000000000 +0100
+++ new/jdupes-1.21.1/act_linkfiles.c   2022-12-01 18:46:17.000000000 +0100
@@ -53,6 +53,12 @@
   static unsigned int symsrc;
   static char rel_path[PATHBUF_SIZE];
 #endif
+#ifdef ENABLE_CLONEFILE_LINK
+  static unsigned int srcfile_preserved_flags = 0;
+  static unsigned int dupfile_preserved_flags = 0;
+  static unsigned int dupfile_original_flags = 0;
+  static struct timeval dupfile_original_tval[2];
+#endif
 
   LOUD(fprintf(stderr, "linkfiles(%d): %p\n", linktype, files);)
   curfile = files;
@@ -121,6 +127,20 @@
       if (!ISFLAG(flags, F_HIDEPROGRESS)) {
         printf("[SRC] "); fwprint(stdout, srcfile->d_name, 1);
       }
+#ifdef ENABLE_CLONEFILE_LINK
+      if (linktype == 2) {
+        if (STAT(srcfile->d_name, &s) != 0) {
+          fprintf(stderr, "warning: stat() on source file failed, 
skipping:\n[SRC] ");
+          fwprint(stderr, srcfile->d_name, 1);
+          continue;
+        }
+
+        /* macOS unexpectedly copies the compressed flag when copying metadata
+         * (which can result in files being unreadable), so we want to retain
+         * the compression flag of srcfile */
+        srcfile_preserved_flags = s.st_flags & UF_COMPRESSED;
+      }
+#endif
       for (; x <= counter; x++) {
         if (linktype == 1 || linktype == 2) {
           /* Can't hard link files on different devices */
@@ -203,6 +223,25 @@
           continue;
         }
 #endif
+#ifdef ENABLE_CLONEFILE_LINK
+        if (linktype == 2) {
+          if (STAT(dupelist[x]->d_name, &s) != 0) {
+            fprintf(stderr, "warning: stat() on destination file failed, 
skipping:\n-##-> ");
+            fwprint(stderr, dupelist[x]->d_name, 1);
+            continue;
+          }
+
+          /* macOS unexpectedly copies the compressed flag when copying 
metadata
+           * (which can result in files being unreadable), so we want to ignore
+           * the compression flag on dstfile in favor of the one from srcfile 
*/
+          dupfile_preserved_flags = s.st_flags & ~(unsigned int)UF_COMPRESSED;
+          dupfile_original_flags = s.st_flags;
+          dupfile_original_tval[0].tv_sec = s.st_atime;
+          dupfile_original_tval[1].tv_sec = s.st_mtime;
+          dupfile_original_tval[0].tv_usec = 0;
+          dupfile_original_tval[1].tv_usec = 0;
+        }
+#endif
 
         /* Make sure the name will fit in the buffer before trying */
         name_len = strlen(dupelist[x]->d_name) + 14;
@@ -210,7 +249,7 @@
         /* Assemble a temporary file name */
         strcpy(tempname, dupelist[x]->d_name);
         strcat(tempname, ".__jdupes__.tmp");
-        /* Rename the source file to the temporary name */
+        /* Rename the destination file to the temporary name */
 #ifdef UNICODE
         if (!M2W(tempname, wname2)) {
           fprintf(stderr, "error: MultiByteToWideChar failed: "); 
fwprint(stderr, srcfile->d_name, 1);
@@ -248,12 +287,35 @@
 #else /* ON_WINDOWS */
         if (linktype == 1) {
           if (link(srcfile->d_name, dupelist[x]->d_name) == 0) success = 1;
-#ifdef ENABLE_CLONEFILE_LINK
+ #ifdef ENABLE_CLONEFILE_LINK
         } else if (linktype == 2) {
-          if (clonefile(srcfile->d_name, dupelist[x]->d_name, 0) == 0) success 
= 1;
-         /* Preserve all file metadata on macOS */
-          copyfile(tempname, dupelist[x]->d_name, NULL, COPYFILE_METADATA);
-#endif /* ENABLE_CLONEFILE_LINK */
+          if (clonefile(srcfile->d_name, dupelist[x]->d_name, 0) == 0) {
+            if (copyfile(tempname, dupelist[x]->d_name, NULL, 
COPYFILE_METADATA) == 0) {
+              /* If the preserved flags match what we just copied from the 
original dupfile, we're done.
+               * Otherwise, we need to update the flags to avoid data loss due 
to differing compression flags */
+              if (dupfile_original_flags == (srcfile_preserved_flags | 
dupfile_preserved_flags)) {
+                success = 1;
+              } else if (chflags(dupelist[x]->d_name, srcfile_preserved_flags 
| dupfile_preserved_flags) == 0) {
+                /* chflags overrides the timestamps that were restored by 
copyfile, so we need to reapply those as well */
+                if (utimes(dupelist[x]->d_name, dupfile_original_tval) == 0) {
+                  success = 1;
+                } else {
+                  fprintf(stderr, "warning: utimes() failed for destination 
file, reverting:\n-##-> ");
+                  fwprint(stderr, dupelist[x]->d_name, 1);
+                }
+              } else {
+                fprintf(stderr, "warning: chflags() failed for destination 
file, reverting:\n-##-> ");
+                fwprint(stderr, dupelist[x]->d_name, 1);
+              }
+            } else {
+              fprintf(stderr, "warning: copyfile() failed for destination 
file, reverting:\n-##-> ");
+              fwprint(stderr, dupelist[x]->d_name, 1);
+            }
+          } else {
+            fprintf(stderr, "warning: clonefile() failed for destination file, 
reverting:\n-##-> ");
+            fwprint(stderr, dupelist[x]->d_name, 1);
+          }
+ #endif /* ENABLE_CLONEFILE_LINK */
         }
  #ifndef NO_SYMLINKS
         else {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/jdupes-1.20.2/chroot_build.sh 
new/jdupes-1.21.1/chroot_build.sh
--- old/jdupes-1.20.2/chroot_build.sh   2021-11-03 03:54:09.000000000 +0100
+++ new/jdupes-1.21.1/chroot_build.sh   2022-12-01 18:46:17.000000000 +0100
@@ -24,20 +24,24 @@
 do_build () {
        test -z "$WD" && echo "WD not set, aborting" && exit 1
        test -z "$PKG" && echo "PKG not set, aborting" && exit 1
-       make clean
-       PN="${NAME}_$VER-$ARCH.pkg.tar.xz"
-       if ! make -j$JOBS all
-               then echo "Build failed"; exit 1
+       if [ -e ./generate_packages.sh ]
+               then ./generate_packages.sh
                else
-               echo "WD/PKG: $WD/$PKG"
-               test -d $WD/$PKG && rm -rf $WD/$PKG
-               mkdir $WD/$PKG
-               make DESTDIR=$WD/$PKG install && \
-                       tar -C pkg -c usr | xz -e > "$PN"
-               # Set ownership to current directory ownership
-               chown "$(stat -c '%u:%g' .)" "$PN"
-               echo "Built $PN"
                make clean
+               PN="${NAME}_$VER-$ARCH.pkg.tar.xz"
+               if ! make -j$JOBS all
+                       then echo "Build failed"; exit 1
+                       else
+                       echo "WD/PKG: $WD/$PKG"
+                       test -d $WD/$PKG && rm -rf $WD/$PKG
+                       mkdir $WD/$PKG
+                       make DESTDIR=$WD/$PKG install && \
+                               tar -C pkg -c usr | xz -e > "$PN"
+                       # Set ownership to current directory ownership
+                       chown "$(stat -c '%u:%g' .)" "$PN"
+                       echo "Built $PN"
+                       make clean
+               fi
        fi
 }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/jdupes-1.20.2/docker/alpine.Dockerfile 
new/jdupes-1.21.1/docker/alpine.Dockerfile
--- old/jdupes-1.20.2/docker/alpine.Dockerfile  1970-01-01 01:00:00.000000000 
+0100
+++ new/jdupes-1.21.1/docker/alpine.Dockerfile  2022-12-01 18:46:17.000000000 
+0100
@@ -0,0 +1,11 @@
+FROM alpine:latest as builder
+RUN apk update && apk add --no-cache gcc make musl-dev
+
+COPY . .
+RUN make && make install
+
+FROM alpine:latest as runner
+
+COPY --from=builder /usr/local/bin/jdupes /usr/local/bin/jdupes
+
+ENTRYPOINT [ "/usr/local/bin/jdupes" ]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/jdupes-1.20.2/docker/slim.Dockerfile 
new/jdupes-1.21.1/docker/slim.Dockerfile
--- old/jdupes-1.20.2/docker/slim.Dockerfile    1970-01-01 01:00:00.000000000 
+0100
+++ new/jdupes-1.21.1/docker/slim.Dockerfile    2022-12-01 18:46:17.000000000 
+0100
@@ -0,0 +1,10 @@
+FROM gcc:bullseye as builder
+
+COPY . .
+RUN make && make install
+
+FROM debian:bullseye-slim as runner
+
+COPY --from=builder /usr/local/bin/jdupes /usr/local/bin/jdupes
+
+ENTRYPOINT [ "/usr/local/bin/jdupes" ]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/jdupes-1.20.2/generate_packages.sh 
new/jdupes-1.21.1/generate_packages.sh
--- old/jdupes-1.20.2/generate_packages.sh      2021-11-03 03:54:09.000000000 
+0100
+++ new/jdupes-1.21.1/generate_packages.sh      2022-12-01 18:46:17.000000000 
+0100
@@ -35,7 +35,9 @@
 
 # Detect Linux
 if [ "$UNAME_S" = "linux" ]
-       then TA="linux-$UNAME_M"
+       then
+       TA="linux-$UNAME_M"
+       [ ! -z "$ARCH" ] && TA="linux-$ARCH"
        PKGTYPE=xz
 fi
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/jdupes-1.20.2/jdupes.1 new/jdupes-1.21.1/jdupes.1
--- old/jdupes-1.20.2/jdupes.1  2021-11-03 03:54:09.000000000 +0100
+++ new/jdupes-1.21.1/jdupes.1  2022-12-01 18:46:17.000000000 +0100
@@ -207,6 +207,9 @@
 .B -@@->
 This file was successfully symlinked to the first file in the chain
 .TP
+.B -##->
+This file was successfully cloned from the first file in the chain
+.TP
 .B -==->
 This file was already a hard link to the first file in the chain
 .TP
@@ -342,7 +345,7 @@
 
 The MIT License (MIT)
 
-Copyright (C) 2015-2021 Jody Lee Bruchon and contributors
+Copyright (C) 2015-2022 Jody Lee Bruchon and contributors
 Forked from fdupes 1.51, Copyright (C) 1999-2014 Adrian Lopez and contributors
 
 Permission is hereby granted, free of charge, to any person obtaining a copy of
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/jdupes-1.20.2/jdupes.c new/jdupes-1.21.1/jdupes.c
--- old/jdupes-1.20.2/jdupes.c  2021-11-03 03:54:09.000000000 +0100
+++ new/jdupes-1.21.1/jdupes.c  2022-12-01 18:46:17.000000000 +0100
@@ -1,4 +1,4 @@
-/* jdupes (C) 2015-2021 Jody Bruchon <j...@jodybruchon.com>
+/* jdupes (C) 2015-2022 Jody Bruchon <j...@jodybruchon.com>
    Forked from fdupes 1.51 (C) 1999-2014 Adrian Lopez
 
    Permission is hereby granted, free of charge, to any person
@@ -65,7 +65,7 @@
 #include "act_summarize.h"
 
 /* Detect Windows and modify as needed */
-#if defined _WIN32 || defined __CYGWIN__
+#if defined _WIN32 || defined __MINGW32__
  const char dir_sep = '\\';
  #ifdef UNICODE
   const wchar_t *FILE_MODE_RO = L"rbS";
@@ -80,7 +80,7 @@
   #error Do not define UNICODE on non-Windows platforms.
   #undef UNICODE
  #endif
-#endif /* _WIN32 || __CYGWIN__ */
+#endif /* _WIN32 || __MINGW32__ */
 
 /* Windows + Unicode compilation */
 #ifdef UNICODE
@@ -493,8 +493,10 @@
   if (file->inode != s.st_ino) return 1;
   if (file->size != s.st_size) return 1;
   if (file->device != s.st_dev) return 1;
-  if (file->mtime != s.st_mtime) return 1;
   if (file->mode != s.st_mode) return 1;
+#ifndef NO_MTIME
+  if (file->mtime != s.st_mtime) return 1;
+#endif
 #ifndef NO_PERMS
   if (file->uid != s.st_uid) return 1;
   if (file->gid != s.st_gid) return 1;
@@ -508,7 +510,7 @@
 }
 
 
-extern inline int getfilestats(file_t * const restrict file)
+int getfilestats(file_t * const restrict file)
 {
   if (file == NULL || file->d_name == NULL) nullptr("getfilestats()");
   LOUD(fprintf(stderr, "getfilestats('%s')\n", file->d_name);)
@@ -518,10 +520,15 @@
   SETFLAG(file->flags, FF_VALID_STAT);
 
   if (STAT(file->d_name, &s) != 0) return -1;
-  file->inode = s.st_ino;
   file->size = s.st_size;
+  file->inode = s.st_ino;
   file->device = s.st_dev;
+#ifndef NO_MTIME
   file->mtime = s.st_mtime;
+#endif
+#ifndef NO_ATIME
+  file->atime = s.st_atime;
+#endif
   file->mode = s.st_mode;
 #ifndef NO_HARDLINKS
   file->nlink = s.st_nlink;
@@ -771,17 +778,19 @@
       LOUD(fprintf(stderr, "check_singlefile: extfilter check: %08x %ld %ld 
%s\n", sflag, newfile->size, extf->size, newfile->d_name);)
       if (
            /* Any line that passes will result in file exclusion */
-           ((sflag == XF_SIZE_EQ) && (newfile->size != extf->size)) ||
-           ((sflag == XF_SIZE_LTEQ) && (newfile->size > extf->size)) ||
-           ((sflag == XF_SIZE_GTEQ) && (newfile->size < extf->size)) ||
-           ((sflag == XF_SIZE_GT) && (newfile->size <= extf->size)) ||
-           ((sflag == XF_SIZE_LT) && (newfile->size >= extf->size)) ||
-           ((sflag == XF_EXCL_EXT) && match_extensions(newfile->d_name, 
extf->param)) ||
-           ((sflag == XF_ONLY_EXT) && !match_extensions(newfile->d_name, 
extf->param)) ||
-           ((sflag == XF_EXCL_STR) && strstr(newfile->d_name, extf->param)) ||
-           ((sflag == XF_ONLY_STR) && !strstr(newfile->d_name, extf->param)) ||
-           ((sflag == XF_DATE_NEWER) && (newfile->mtime < extf->size)) ||
-           ((sflag == XF_DATE_OLDER) && (newfile->mtime >= extf->size))
+           ((sflag == XF_SIZE_EQ) && (newfile->size != extf->size))
+           || ((sflag == XF_SIZE_LTEQ) && (newfile->size > extf->size))
+           || ((sflag == XF_SIZE_GTEQ) && (newfile->size < extf->size))
+           || ((sflag == XF_SIZE_GT) && (newfile->size <= extf->size))
+           || ((sflag == XF_SIZE_LT) && (newfile->size >= extf->size))
+           || ((sflag == XF_EXCL_EXT) && match_extensions(newfile->d_name, 
extf->param))
+           || ((sflag == XF_ONLY_EXT) && !match_extensions(newfile->d_name, 
extf->param))
+           || ((sflag == XF_EXCL_STR) && strstr(newfile->d_name, extf->param))
+           || ((sflag == XF_ONLY_STR) && !strstr(newfile->d_name, extf->param))
+#ifndef NO_MTIME
+           || ((sflag == XF_DATE_NEWER) && (newfile->mtime < extf->size))
+           || ((sflag == XF_DATE_OLDER) && (newfile->mtime >= extf->size))
+#endif
       ) excluded = 1;
     }
     if (excluded) {
@@ -1556,6 +1565,7 @@
 #endif
 
 
+#ifndef NO_MTIME
 static int sort_pairs_by_mtime(file_t *f1, file_t *f2)
 {
   if (f1 == NULL || f2 == NULL) nullptr("sort_pairs_by_mtime()");
@@ -1571,6 +1581,7 @@
   /* If the mtimes match, use the names to break the tie */
   return numeric_sort(f1->d_name, f2->d_name, sort_direction);
 }
+#endif
 
 
 static int sort_pairs_by_filename(file_t *f1, file_t *f2)
@@ -1685,8 +1696,10 @@
   printf(" -N --no-prompt   \ttogether with --delete, preserve the first file 
in\n");
   printf("                  \teach set of duplicates and delete the rest 
without\n");
   printf("                  \tprompting the user\n");
+#ifndef NO_MTIME
   printf(" -o --order=BY    \tselect sort order for output, linking and 
deleting; by\n");
   printf("                  \tmtime (BY=time) or filename (BY=name, the 
default)\n");
+#endif
 #ifndef NO_USER_ORDER
   printf(" -O --param-order  \tParameter order is more important than selected 
-o sort\n");
 #endif
@@ -1732,9 +1745,6 @@
   printf("Detailed help for jdupes -X/--ext-filter options\n");
   printf("General format: jdupes -X filter[:value][size_suffix]\n\n");
 
-  /* FIXME: Remove after v1.19.0 */
-  printf("****** WARNING: THE MEANINGS HAVE CHANGED IN v1.19.0 - READ 
CAREFULLY ******\n\n");
-
   printf("noext:ext1[,ext2,...]   \tExclude files with certain 
extension(s)\n\n");
   printf("onlyext:ext1[,ext2,...] \tOnly include files with certain 
extension(s)\n\n");
   printf("size[+-=]:size[suffix]  \tOnly Include files matching size 
criteria\n");
@@ -1778,7 +1788,9 @@
   static int opt;
   static int pm = 1;
   static int partialonly_spec = 0;
+#ifndef NO_MTIME  /* Remove if new order types are added! */
   static ordertype_t ordertype = ORDER_NAME;
+#endif
   static long manual_chunk_size = 0;
 #ifdef __linux__
   static struct proc_cacheinfo pci;
@@ -2095,7 +2107,7 @@
           c++;
         }
       } else printf(" none");
-      printf("\nCopyright (C) 2015-2021 by Jody Bruchon and contributors\n");
+      printf("\nCopyright (C) 2015-2022 by Jody Bruchon and contributors\n");
       printf("Forked from fdupes 1.51, (C) 1999-2014 Adrian Lopez and 
contributors\n\n");
       printf("Permission is hereby granted, free of charge, to any person 
obtaining a copy of\n");
       printf("this software and associated documentation files (the 
\"Software\"), to deal in\n");
@@ -2118,6 +2130,7 @@
       printf("\nReport bugs and get the latest releases: 
https://github.com/jbruchon/jdupes\n";);
       exit(EXIT_SUCCESS);
     case 'o':
+#ifndef NO_MTIME  /* Remove if new order types are added! */
       if (!strncasecmp("name", optarg, 5)) {
         ordertype = ORDER_NAME;
       } else if (!strncasecmp("time", optarg, 5)) {
@@ -2126,6 +2139,7 @@
         fprintf(stderr, "invalid value for --order: '%s'\n", optarg);
         exit(EXIT_FAILURE);
       }
+#endif /* NO_MTIME */
       break;
     case 'B':
 #ifdef ENABLE_DEDUPE
@@ -2295,8 +2309,11 @@
            (curfile->device == (*match)->device))
          ) {
         LOUD(fprintf(stderr, "MAIN: notice: hard linked, quick, or 
partial-only match (-H/-Q/-T)\n"));
-        registerpair(match, curfile,
-            (ordertype == ORDER_TIME) ? sort_pairs_by_mtime : 
sort_pairs_by_filename);
+#ifndef NO_MTIME
+        registerpair(match, curfile, (ordertype == ORDER_TIME) ? 
sort_pairs_by_mtime : sort_pairs_by_filename);
+#else
+        registerpair(match, curfile, sort_pairs_by_filename);
+#endif
         dupecount++;
         goto skip_full_check;
       }
@@ -2328,8 +2345,11 @@
 
       if (confirmmatch(file1, file2, curfile->size)) {
         LOUD(fprintf(stderr, "MAIN: registering matched file pair\n"));
-        registerpair(match, curfile,
-            (ordertype == ORDER_TIME) ? sort_pairs_by_mtime : 
sort_pairs_by_filename);
+#ifndef NO_MTIME
+        registerpair(match, curfile, (ordertype == ORDER_TIME) ? 
sort_pairs_by_mtime : sort_pairs_by_filename);
+#else
+        registerpair(match, curfile, sort_pairs_by_filename);
+#endif
         dupecount++;
       } DBG(else hash_fail++;)
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/jdupes-1.20.2/jdupes.h new/jdupes-1.21.1/jdupes.h
--- old/jdupes-1.20.2/jdupes.h  2021-11-03 03:54:09.000000000 +0100
+++ new/jdupes-1.21.1/jdupes.h  2022-12-01 18:46:17.000000000 +0100
@@ -9,7 +9,7 @@
 #endif
 
 /* Detect Windows and modify as needed */
-#if defined _WIN32 || defined __CYGWIN__
+#if defined _WIN32 || defined __MINGW32__
  #ifndef ON_WINDOWS
   #define ON_WINDOWS 1
  #endif
@@ -58,7 +58,7 @@
   #error Do not define UNICODE on non-Windows platforms.
   #undef UNICODE
  #endif
-#endif /* _WIN32 || __CYGWIN__ */
+#endif /* _WIN32 || __MINGW32__ */
 
 /* Windows + Unicode compilation */
 #ifdef UNICODE
@@ -182,14 +182,19 @@
   struct _file *duplicates;
   struct _file *next;
   char *d_name;
-  dev_t device;
+  uint32_t flags;  /* Status flags */
   jdupes_mode_t mode;
   off_t size;
+  dev_t device;
   jdupes_ino_t inode;
   jdupes_hash_t filehash_partial;
   jdupes_hash_t filehash;
+#ifndef NO_MTIME
   time_t mtime;
-  uint32_t flags;  /* Status flags */
+#endif
+#ifndef NO_ATIME
+  time_t atime;
+#endif
 #ifndef NO_USER_ORDER
   unsigned int user_order; /* Order of the originating command-line parameter 
*/
 #endif
@@ -274,7 +279,6 @@
 
 extern void nullptr(const char * restrict func);
 extern int file_has_changed(file_t * const restrict file);
-extern int getfilestats(file_t * const restrict file);
 extern int getdirstats(const char * const restrict name,
         jdupes_ino_t * const restrict inode, dev_t * const restrict dev,
        jdupes_mode_t * const restrict mode);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/jdupes-1.20.2/jody_cacheinfo.c 
new/jdupes-1.21.1/jody_cacheinfo.c
--- old/jdupes-1.20.2/jody_cacheinfo.c  2021-11-03 03:54:09.000000000 +0100
+++ new/jdupes-1.21.1/jody_cacheinfo.c  2022-12-01 18:46:17.000000000 +0100
@@ -1,6 +1,6 @@
 /* Detect and report size of CPU caches
  *
- * Copyright (C) 2017-2021 by Jody Bruchon <j...@jodybruchon.com>
+ * Copyright (C) 2017-2022 by Jody Bruchon <j...@jodybruchon.com>
  * Distributed under The MIT License
  *
  * If an error occurs or a cache is missing, zeroes are returned
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/jdupes-1.20.2/jody_paths.c 
new/jdupes-1.21.1/jody_paths.c
--- old/jdupes-1.20.2/jody_paths.c      2021-11-03 03:54:09.000000000 +0100
+++ new/jdupes-1.21.1/jody_paths.c      2022-12-01 18:46:17.000000000 +0100
@@ -1,6 +1,6 @@
 /* Jody Bruchon's path manipulation code library
  *
- * Copyright (C) 2014-2021 by Jody Bruchon <j...@jodybruchon.com>
+ * Copyright (C) 2014-2022 by Jody Bruchon <j...@jodybruchon.com>
  * Released under The MIT License
  */
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/jdupes-1.20.2/jody_sort.c 
new/jdupes-1.21.1/jody_sort.c
--- old/jdupes-1.20.2/jody_sort.c       2021-11-03 03:54:09.000000000 +0100
+++ new/jdupes-1.21.1/jody_sort.c       2022-12-01 18:46:17.000000000 +0100
@@ -1,6 +1,6 @@
 /* Jody Bruchon's sorting code library
  *
- * Copyright (C) 2014-2021 by Jody Bruchon <j...@jodybruchon.com>
+ * Copyright (C) 2014-2022 by Jody Bruchon <j...@jodybruchon.com>
  * Released under The MIT License
  */
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/jdupes-1.20.2/jody_strtoepoch.c 
new/jdupes-1.21.1/jody_strtoepoch.c
--- old/jdupes-1.20.2/jody_strtoepoch.c 2021-11-03 03:54:09.000000000 +0100
+++ new/jdupes-1.21.1/jody_strtoepoch.c 2022-12-01 18:46:17.000000000 +0100
@@ -1,6 +1,6 @@
 /* Jody Bruchon's datetime-to-epoch conversion function
  *
- * Copyright (C) 2020-2021 by Jody Bruchon <j...@jodybruchon.com>
+ * Copyright (C) 2020-2022 by Jody Bruchon <j...@jodybruchon.com>
  * Released under The MIT License
  */
 
@@ -11,8 +11,13 @@
 #define REQ_NUM(a) { if (a < '0' || a > '9') return -1; }
 #define ATONUM(a,b) (a = b - '0')
 /* Fast multiplies by 100 (*64 + *32 + *4) and 10 (*8 + *2) */
-#define MUL100(a) ((a << 6) + (a << 5) + (a << 2))
-#define MUL10(a) ((a << 3) + a + a)
+#ifndef STRTOEPOCH_USE_REAL_MULTIPLY
+ #define MUL100(a) ((a << 6) + (a << 5) + (a << 2))
+ #define MUL10(a) ((a << 3) + a + a)
+#else
+ #define MUL100(a) (a * 100)
+ #define MUL10(a) (a * 10)
+#endif /* STRTOEPOCH_USE_REAL_MULTIPLY */
 
 /* Accepts date[time] strings "YYYY-MM-DD" or "YYYY-MM-DD HH:MM:SS"
  * and returns the number of seconds since the Unix Epoch a la mktime()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/jdupes-1.20.2/jody_strtoepoch.h 
new/jdupes-1.21.1/jody_strtoepoch.h
--- old/jdupes-1.20.2/jody_strtoepoch.h 2021-11-03 03:54:09.000000000 +0100
+++ new/jdupes-1.21.1/jody_strtoepoch.h 2022-12-01 18:46:17.000000000 +0100
@@ -1,6 +1,6 @@
 /* Jody Bruchon's datetime-to-epoch conversion function
  *
- * Copyright (C) 2020-2021 by Jody Bruchon <j...@jodybruchon.com>
+ * Copyright (C) 2020-2022 by Jody Bruchon <j...@jodybruchon.com>
  * Released under The MIT License
  */
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/jdupes-1.20.2/jody_win_unicode.c 
new/jdupes-1.21.1/jody_win_unicode.c
--- old/jdupes-1.20.2/jody_win_unicode.c        2021-11-03 03:54:09.000000000 
+0100
+++ new/jdupes-1.21.1/jody_win_unicode.c        2022-12-01 18:46:17.000000000 
+0100
@@ -1,6 +1,6 @@
 /* Jody Bruchon's Windows Unicode helper routines
  *
- * Copyright (C) 2014-2021 by Jody Bruchon <j...@jodybruchon.com>
+ * Copyright (C) 2014-2022 by Jody Bruchon <j...@jodybruchon.com>
  * Released under The MIT License
  */
 #include "jody_win_unicode.h"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/jdupes-1.20.2/linux-dedupe-static.h 
new/jdupes-1.21.1/linux-dedupe-static.h
--- old/jdupes-1.20.2/linux-dedupe-static.h     2021-11-03 03:54:09.000000000 
+0100
+++ new/jdupes-1.21.1/linux-dedupe-static.h     2022-12-01 18:46:17.000000000 
+0100
@@ -1,58 +1,24 @@
-/*
- * Copyright (C) 2007 Oracle.  All rights reserved.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public
- * License v2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public
- * License along with this program; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 021110-1307, USA.
- */
-
-#ifndef JDUPES_BTRFS_H
-#define JDUPES_BTRFS_H
+/* Bare header for Linux dedupe API */
+#ifndef JDUPES_DEDUPESTATIC_H
+#define JDUPES_DEDUPESTATIC_H
 #include <linux/types.h>
 #include <linux/ioctl.h>
-
-#define BTRFS_IOCTL_MAGIC 0x94
-
-#define BTRFS_DEVICE_PATH_NAME_MAX 1024
-
 #define FILE_DEDUPE_RANGE_SAME    0
 #define FILE_DEDUPE_RANGE_DIFFERS 1
-
-/* For extent-same ioctl */
 struct file_dedupe_range_info {
-       __s64 dest_fd;          /* in - destination file */
-       __u64 dest_offset;      /* in - start of extent in destination */
-       __u64 bytes_deduped;    /* out - total # of bytes we were able
-                                * to dedupe from this file */
-       /* status of this dedupe operation:
-        * 0 if dedup succeeds
-        * < 0 for error
-        * == FILE_DEDUPE_RANGE_DIFFERS if data differs
-        */
-       __s32 status;           /* out - see above description */
+       __s64 dest_fd;
+       __u64 dest_offset;
+       __u64 bytes_deduped;
+       __s32 status;
        __u32 reserved;
 };
-
 struct file_dedupe_range {
-       __u64 src_offset;       /* in - start of extent in source */
-       __u64 src_length;       /* in - length of extent */
-       __u16 dest_count;       /* in - total elements in info array */
+       __u64 src_offset;
+       __u64 src_length;
+       __u16 dest_count;
        __u16 reserved1;
        __u32 reserved2;
        struct file_dedupe_range_info info[0];
 };
-
-#define FIDEDUPERANGE _IOWR(BTRFS_IOCTL_MAGIC, 54, \
-                                        struct file_dedupe_range)
-
-#endif /* JDUPES_BTRFS_H */
+#define FIDEDUPERANGE _IOWR(0x94, 54, struct file_dedupe_range)
+#endif /* JDUPES_DEDUPESTATIC_H */
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/jdupes-1.20.2/string_malloc.c 
new/jdupes-1.21.1/string_malloc.c
--- old/jdupes-1.20.2/string_malloc.c   2021-11-03 03:54:09.000000000 +0100
+++ new/jdupes-1.21.1/string_malloc.c   2022-12-01 18:46:17.000000000 +0100
@@ -2,7 +2,7 @@
  * String table allocator
  * A replacement for malloc() for tables of fixed strings
  *
- * Copyright (C) 2015-2021 by Jody Bruchon <j...@jodybruchon.com>
+ * Copyright (C) 2015-2022 by Jody Bruchon <j...@jodybruchon.com>
  * Released under The MIT License
  */
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/jdupes-1.20.2/stupid_dupes.sh 
new/jdupes-1.21.1/stupid_dupes.sh
--- old/jdupes-1.20.2/stupid_dupes.sh   2021-11-03 03:54:09.000000000 +0100
+++ new/jdupes-1.21.1/stupid_dupes.sh   2022-12-01 18:46:17.000000000 +0100
@@ -1,7 +1,7 @@
 #!/bin/bash
 
 # stupid_dupes: find duplicates like jdupes but more slowly with a shell script
-# Copyright (C) 2020-2021 by Jody Bruchon <j...@jodybruchon.com>
+# Copyright (C) 2020-2022 by Jody Bruchon <j...@jodybruchon.com>
 #
 # The MIT License (MIT)
 #
@@ -245,7 +245,7 @@
 }
 
 show_help () {
-       COPYTEXT="Copyright (C) 2020-2021 by Jody Bruchon 
<j...@jodybruchon.com> and contributors\n"
+       COPYTEXT="Copyright (C) 2020-2022 by Jody Bruchon 
<j...@jodybruchon.com> and contributors\n"
        echo "$PROGNAME $VER ($VERDATE)"
        if [ "$2" = "full" ]
                then
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/jdupes-1.20.2/version.h new/jdupes-1.21.1/version.h
--- old/jdupes-1.20.2/version.h 2021-11-03 03:54:09.000000000 +0100
+++ new/jdupes-1.21.1/version.h 2022-12-01 18:46:17.000000000 +0100
@@ -4,7 +4,7 @@
 #ifndef JDUPES_VERSION_H
 #define JDUPES_VERSION_H
 
-#define VER "1.20.2"
-#define VERDATE "2021-11-02"
+#define VER "1.21.1"
+#define VERDATE "2022-12-01"
 
 #endif /* JDUPES_VERSION_H */
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/jdupes-1.20.2/win_stat.c new/jdupes-1.21.1/win_stat.c
--- old/jdupes-1.20.2/win_stat.c        2021-11-03 03:54:09.000000000 +0100
+++ new/jdupes-1.21.1/win_stat.c        2022-12-01 18:46:17.000000000 +0100
@@ -1,7 +1,7 @@
 /*
  * Windows-native code for getting stat()-like information
  *
- * Copyright (C) 2016-2021 by Jody Bruchon <j...@jodybruchon.com>
+ * Copyright (C) 2016-2022 by Jody Bruchon <j...@jodybruchon.com>
  * Released under The MIT License
  */
 
@@ -14,7 +14,7 @@
 #include <stdint.h>
 
 /* Convert NT epoch to UNIX epoch */
-static time_t nttime_to_unixtime(const uint64_t * const restrict timestamp)
+time_t nttime_to_unixtime(const uint64_t * const restrict timestamp)
 {
        uint64_t newstamp;
 
@@ -25,6 +25,18 @@
        return (time_t)newstamp;
 }
 
+/* Convert UNIX epoch to NT epoch */
+time_t unixtime_to_nttime(const uint64_t * const restrict timestamp)
+{
+       uint64_t newstamp;
+
+       memcpy(&newstamp, timestamp, sizeof(uint64_t));
+       newstamp += 11644473600LL;
+       newstamp *= 10000000LL;
+       if (newstamp <= 11644473600LL) return 0;
+       return (time_t)newstamp;
+}
+
 /* Get stat()-like extra information for a file on Windows */
 int win_stat(const char * const filename, struct winstat * const restrict buf)
 {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/jdupes-1.20.2/win_stat.h new/jdupes-1.21.1/win_stat.h
--- old/jdupes-1.20.2/win_stat.h        2021-11-03 03:54:09.000000000 +0100
+++ new/jdupes-1.21.1/win_stat.h        2022-12-01 18:46:17.000000000 +0100
@@ -45,6 +45,8 @@
  #define M2W(a,b) MultiByteToWideChar(CP_UTF8, 0, a, -1, (LPWSTR)b, WPATH_MAX)
 #endif
 
+extern time_t nttime_to_unixtime(const uint64_t * const restrict timestamp);
+extern time_t unixtime_to_nttime(const uint64_t * const restrict timestamp);
 extern int win_stat(const char * const filename, struct winstat * const 
restrict buf);
 
 #ifdef __cplusplus
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/jdupes-1.20.2/winres.manifest.xml 
new/jdupes-1.21.1/winres.manifest.xml
--- old/jdupes-1.20.2/winres.manifest.xml       2021-11-03 03:54:09.000000000 
+0100
+++ new/jdupes-1.21.1/winres.manifest.xml       2022-12-01 18:46:17.000000000 
+0100
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
 <assembly xmlns="urn:schemas-microsoft-com:asm.v3" manifestVersion="1.0">
-  <assemblyIdentity type="win32" name="jdupes" version="1.20.2.0"/>
+  <assemblyIdentity type="win32" name="jdupes" version="1.21.1.0"/>
   <application xmlns="urn:schemas-microsoft-com:asm.v3">
     <windowsSettings 
xmlns:ws2="http://schemas.microsoft.com/SMI/2016/WindowsSettings";>
       <ws2:longPathAware>true</ws2:longPathAware>
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/jdupes-1.20.2/winres.rc new/jdupes-1.21.1/winres.rc
--- old/jdupes-1.20.2/winres.rc 2021-11-03 03:54:09.000000000 +0100
+++ new/jdupes-1.21.1/winres.rc 2022-12-01 18:46:17.000000000 +0100
@@ -3,8 +3,8 @@
 1 24 winres.manifest.xml
 
 VS_VERSION_INFO VERSIONINFO
- FILEVERSION 1,20,2,0
- PRODUCTVERSION 1,20,2,0
+ FILEVERSION 1,21,1,0
+ PRODUCTVERSION 1,21,1,0
  FILEFLAGSMASK 0x3fL
  FILEFLAGS 0x0L
  FILEOS 0x40004L
@@ -15,15 +15,15 @@
     BEGIN
                BLOCK "040904b0"
                BEGIN
-                   VALUE "Comments", "(C) 2015-2021 Jody Bruchon and 
contributors, published under The MIT License"
+                   VALUE "Comments", "(C) 2015-2022 Jody Bruchon and 
contributors, published under The MIT License"
                    VALUE "CompanyName", "Jody Bruchon"
                    VALUE "FileDescription", "jdupes Duplicate File Finder Tool"
-                   VALUE "FileVersion", "1,20,2,0"
+                   VALUE "FileVersion", "1,21,1,0"
                    VALUE "InternalName", "jdupes"
-                   VALUE "LegalCopyright", "(C) 2015-2021 Jody Bruchon and 
contributors"
+                   VALUE "LegalCopyright", "(C) 2015-2022 Jody Bruchon and 
contributors"
                    VALUE "OriginalFilename", "jdupes.exe"
                    VALUE "ProductName", "jdupes"
-                   VALUE "ProductVersion", "1,20,2,0"
+                   VALUE "ProductVersion", "1,21,1,0"
                END
     END
     BLOCK "VarFileInfo"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/jdupes-1.20.2/winres_xp.rc 
new/jdupes-1.21.1/winres_xp.rc
--- old/jdupes-1.20.2/winres_xp.rc      2021-11-03 03:54:09.000000000 +0100
+++ new/jdupes-1.21.1/winres_xp.rc      2022-12-01 18:46:17.000000000 +0100
@@ -1,8 +1,8 @@
 #include "winver.h"
 
 VS_VERSION_INFO VERSIONINFO
- FILEVERSION 1,20,2,0
- PRODUCTVERSION 1,20,2,0
+ FILEVERSION 1,21,1,0
+ PRODUCTVERSION 1,21,1,0
  FILEFLAGSMASK 0x3fL
  FILEFLAGS 0x0L
  FILEOS 0x40004L
@@ -13,15 +13,15 @@
     BEGIN
                BLOCK "040904b0"
                BEGIN
-                   VALUE "Comments", "(C) 2015-2021 Jody Bruchon and 
contributors, published under The MIT License"
+                   VALUE "Comments", "(C) 2015-2022 Jody Bruchon and 
contributors, published under The MIT License"
                    VALUE "CompanyName", "Jody Bruchon"
                    VALUE "FileDescription", "jdupes Duplicate File Finder Tool"
-                   VALUE "FileVersion", "1,20,2,0"
+                   VALUE "FileVersion", "1,21,1,0"
                    VALUE "InternalName", "jdupes"
-                   VALUE "LegalCopyright", "(C) 2015-2021 Jody Bruchon and 
contributors"
+                   VALUE "LegalCopyright", "(C) 2015-2022 Jody Bruchon and 
contributors"
                    VALUE "OriginalFilename", "jdupes.exe"
                    VALUE "ProductName", "jdupes"
-                   VALUE "ProductVersion", "1,20,2,0"
+                   VALUE "ProductVersion", "1,21,1,0"
                END
     END
     BLOCK "VarFileInfo"

Reply via email to