├── .gitignore ├── .version ├── ChangeLog ├── README.md ├── bin ├── crccp ├── crcmv └── crcsum ├── build-secure-copy ├── create-patch-files ├── src ├── copy.c.patch ├── copy.h.patch ├── crc64.c ├── crc64.h ├── crccp.c.patch ├── crccp.x ├── crcmv.c.patch ├── crcmv.x ├── crcsum.c ├── crcsum.h ├── crcsum.x ├── crcsum_cli.c ├── cu-progs.m4.patch ├── cu-progs.mk.patch └── local.mk.patch └── test └── test.sh /.gitignore: -------------------------------------------------------------------------------- 1 | *.tar.xz 2 | coreutils-8.31/* 3 | coreutils-8.32/* 4 | coreutils-*/* 5 | notes.txt 6 | build-beta 7 | -------------------------------------------------------------------------------- /.version: -------------------------------------------------------------------------------- 1 | 9.3.0 2 | -------------------------------------------------------------------------------- /ChangeLog: -------------------------------------------------------------------------------- 1 | 2021-11-14 2 | Version 9.0.0 3 | 4 | - Upgraded to coreutils version 9.0 5 | - Changed version numbering. x.y.z: x.y refer to coreutils version. z to securecopy increment version. 6 | 7 | 2020-06-14 8 | version 8.32 (coreutiles) - 2.1.1 (securecopy) 9 | 10 | - Upgraded coreutils 11 | - Add -e flag (ignore extension) 12 | 13 | 2020-01-26 Hans IJntema 14 | 15 | version 8.31 (coreutils) - 2.0.7 (securecopy) 16 | 17 | - Fixed 2GB limitation on 32bit systems; 18 | This is tested on 32bit x86 19 | To be tested on Raspbian for Raspberry Pi 20 | Credits to Jim Cruise for identifying the issue and testing 21 | 22 | 23 | 2020-01-19 Hans IJntema 24 | 25 | version 8.31 (coreutils) - 2.0.6 (securecopy) 26 | 27 | - Updated README 28 | 29 | 30 | 2020-01-18 Hans IJntema 31 | 32 | version 8.31 (coreutils) - 2.0.5 (securecopy) 33 | 34 | - Updated README 35 | - Verified that crcmv does work. 36 | 37 | 38 | 2020-01-17 Hans IJntema 39 | 40 | version 8.31 (coreutils) - 2.0.4 (securecopy) 41 | 42 | - Fixed -cx argument parsing; 43 | - NOTE: crcmv -cx does not work currently; crccp -cx is fine 44 | 45 | 46 | 2020-01-14 Hans IJntema 47 | 48 | version 8.31 (coreutils) - 2.0.3 (securecopy) 49 | 50 | - Fixed compiler warnings on asprintf (credits Jim Cruse) 51 | 52 | 53 | 2020-01-11 Hans IJntema 54 | 55 | version 8.31 (coreutils) - 2.0.2 (securecopy) 56 | 57 | - Added securecopy version number to reporting (eg crccp --version) 58 | 59 | 60 | 2020-01-11 Hans IJntema 61 | 62 | version 8.31 (coreutils) - 2.0.1 (securecopy) 63 | 64 | - Fix -c argument parsing; 65 | 66 | 67 | 2020-01-01 Hans IJntema 68 | 69 | version 8.31 (coreutils) - 2.0.0 (securecopy) 70 | 71 | - Upgraded to be based on coreutils 8.31 72 | - Moved from sf.net to github 73 | 74 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SecureCopy 2 | crccp and crcmv are based on GNU coreutils and add crc checksum functionality to cp and mv commands. 3 | Checksums can optionally be stored in the file's xattr. 4 | Checksum is generated on source file and verified agains destination file 5 | 6 | The command crcsum can be used for further checksum analysis/verification, or for storing a checksum in the xattr of all files in a directory or filesystem. 7 | I mount my filesystems with `mount -t ext4 -o noatime -o user_xattr ` or specify user_xattr in `/etc/fstab` under options. 8 | 9 | 10 | A use case: 11 | - I run `crcsum -u -r .` on my home directory before daily backup; I have xattr enabled on my filesystems, checksums are embedded in all files and stored in the backup. 12 | - I run once a month (cronjob) `crcsum -c -r ` to verify if backup is healthy 13 | - And yes, I do run once or twice a year into a corrupt file (bit rot?); ofcourse your luck varies with quality of HD's and size of your backups 14 | 15 | 16 | ## Getting Started 17 | This package is tested on Debian buster & bullseye 18 | 19 | ### Prerequisites 20 | * Test if [GNU Coreutils 9.3](https://ftp.gnu.org/gnu/coreutils/coreutils-9.3.tar.xz) can be build and fix any build issues 21 | * automake-1.15 22 | 23 | ### Installing 24 | * Download securecopy sources 25 | * Adapt `TARGETDIR="/opt"` in `build-secure-copy`, point to location where crccp, crcmv and crcsum should be located 26 | * `sudo ./build-secure-copy`: this will download coreutils package, apply patch files, build and copy target files to "TARGETDIR" 27 | * The other coreutils tools are not installed! 28 | * "build-secure-copy" works for Debian OS-ses; adapt for other distributions (specifically, install required packages) 29 | 30 | ## Deployment 31 | Add to `~/.bashrc:` 32 | * alias cp='TARGETDIR/crccp -cx' 33 | * alias mv='TARGETDIR/crcmv -cx' 34 | * alias crcsum='TARGETDIR/crcsum' 35 | * (replace TARGETDIR with actual location) 36 | 37 | ## Usage 38 | * `cp -c sourcefile destination` # will re-use crc stored with sourcefile (if any) 39 | * `cp -cx sourcefile destination` # will re-created crc of sourcefile befie copy is started 40 | 41 | ## Versioning 42 | * V9.3.0: based on coreutils v9.3; Added simple test 43 | * V9.0.0: based on coreutils v9.0; First 2 decimals of version number refer to coreutils version 44 | * V2.1: based on coreutils v8.32 45 | * V2.0: based on coreutils v8.31 46 | * [Previous versions](https://sourceforge.net/projects/crcsum/https://sourceforge.net/projects/crcsum/) 47 | 48 | ## Authors 49 | Hans IJntema 50 | 51 | CRC64 routine: 52 | The checksum routine is the crc-64-jones created by Salvatore Sanfilippo. 53 | Coreutils authors: see coreutils documentation. 54 | 55 | ## License 56 | This project is licensed under the GNU General Public License 57 | 58 | ## Details 59 | ``` 60 | crcsum -h 61 | CRCSUM stores a CRC checksum and file mtime as an extended attribute. 62 | CRCSUM checks stored CRC checksum against actual CRC checksum 63 | CRCSUM allows for CRC updates, only when mtime has changed 64 | ZERO size files will not be checksum-ed. 65 | Directory & File SYMLINKS will not be followed. 66 | NOTE: Some programs do change file content (even w/o saving), 67 | while mtime is not update. Example, some Microsoft Excel versions 68 | This will result in false positves when checking file against CRC. 69 | ``` 70 | 71 | ``` 72 | Options : 73 | -a Calculate and Add checksum (no overwrite) 74 | -u As -a, and Update stale checksum 75 | -f As -a, Force overwrite existing checksum 76 | -c Check file against stored checksum; stale CRC's are omitted 77 | -e Assumes -c; omit files with specified extension; one extension per option; eg -e xls -e xlt 78 | -p Print CRC64 checksum; stale CRC's are omitted; Add -d to print stale and missing CRC's 79 | -v Verbose. Print more information 80 | -x Remove stored CRC64 checksum 81 | -r Recurse through directories 82 | -d Print Debug info. Implies -v 83 | ``` 84 | 85 | ``` 86 | Relevant additional or extended flags for crccp and crcmv (compared to cp, mv) 87 | -c, --crc Check whether copy was successfull with checksum comparison 88 | -cx, --crc=x As -c and checksum is stored in xattr of src and dest file (if file is writeable and if filesystem supports xattr); 89 | Stored crc can be used in a next cp/mv or integrity check with crcsum...bitrot check); 90 | Implies --preserve=all 91 | -v, --verbose Explain what is being done and display crc's created 92 | ``` 93 | After a copy or move, integrity of file can be checked (again) with `crcsum -c -r \` 94 | If a file with crc stored in its xattr has been changed afterwards, the crc is flagged as stale, and ignored (based on timestamps) 95 | Note: Microsoft Excel files (on Windows) are known to change the file content but not the timestamp if you just open the excel file for reading and close without saving. You can use `crcsum -e xls` to ignore Excel files. 96 | -------------------------------------------------------------------------------- /bin/crccp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hansij66/securecopy/f55557e39d3e82294088b8bac0ab420f89ce1dba/bin/crccp -------------------------------------------------------------------------------- /bin/crcmv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hansij66/securecopy/f55557e39d3e82294088b8bac0ab420f89ce1dba/bin/crcmv -------------------------------------------------------------------------------- /bin/crcsum: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hansij66/securecopy/f55557e39d3e82294088b8bac0ab420f89ce1dba/bin/crcsum -------------------------------------------------------------------------------- /build-secure-copy: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | #set -e 4 | 5 | # run as root 6 | 7 | # assumption is that coreutils-X.Y.tar.xz is located in current directory 8 | 9 | # TODO https://www.tecmint.com/advanced-copy-command-shows-progress-bar-while-copying-files/ 10 | 11 | 12 | # local system directory where crccp, crcmv and crcsum will be copied 13 | # remainder of core utils will not be installed! 14 | # Change to meet local system 15 | TARGETDIR="/opt/ansible/roles/cron-files/files/system/bin/" 16 | LOCALTARGETDIR="/opt/bin/" 17 | 18 | # Internal for this script 19 | CURRENTDIR=${PWD} 20 | 21 | # bin dir after build 22 | BINDIR="${CURRENTDIR}/bin" 23 | 24 | # Target coreutils (tested version) 25 | COREUTILS="coreutils-9.3" 26 | 27 | # required on debian 28 | # Can be commented-out after first run 29 | apt-get update && apt-get install -y --no-install-recommends -qq \ 30 | procps \ 31 | git \ 32 | build-essential \ 33 | automake \ 34 | texinfo \ 35 | ca-certificates \ 36 | wget \ 37 | libattr1-dev 38 | 39 | # Coreutils 40 | # Can be commented-out after first run 41 | wget -v -O ${CURRENTDIR}/${COREUTILS}.tar.xz https://ftp.gnu.org/gnu/coreutils/${COREUTILS}.tar.xz 42 | 43 | # Clean source directory 44 | rm -rf ${CURRENTDIR}/${COREUTILS} 45 | 46 | rm ${CURRENTDIR}/bin/* 47 | 48 | 49 | # Extract Coreutils 50 | cd ${CURRENTDIR} 51 | tar -xvf ${COREUTILS}.tar.xz 52 | 53 | 54 | # PRE-REQUISITE - CAN I BUILD STOCK CORE UTILS? 55 | # COMMENT WHEN SUCCESSFULL 56 | #cd ${CURRENTDIR}/${COREUTILS} 57 | #export FORCE_UNSAFE_CONFIGURE=1 58 | #./bootstrap 59 | #./configure 60 | #make 61 | #exit 62 | 63 | ############################################################################################# 64 | ## START SECURE COPY 65 | 66 | 67 | # Install Securecopy files 68 | cd ${CURRENTDIR}/src 69 | cp crc64.* crcsum.* crcsum_cli.c ${CURRENTDIR}/${COREUTILS}/src/ 70 | cp *.x ${CURRENTDIR}/${COREUTILS}/man/ 71 | 72 | cd ${CURRENTDIR}/${COREUTILS}/src 73 | cp mv.c crcmv.c 74 | cp cp.c crccp.c 75 | cp copy.c copy.c.org 76 | cp copy.h copy.h.org 77 | cp cu-progs.mk cu-progs.mk.org 78 | cp local.mk local.mk.org 79 | 80 | 81 | cd ${CURRENTDIR}/${COREUTILS}/src 82 | patch copy.c ${CURRENTDIR}/src/copy.c.patch 83 | patch copy.h ${CURRENTDIR}/src/copy.h.patch 84 | patch crccp.c ${CURRENTDIR}/src/crccp.c.patch 85 | patch crcmv.c ${CURRENTDIR}/src/crcmv.c.patch 86 | patch cu-progs.mk ${CURRENTDIR}/src/cu-progs.mk.patch 87 | patch local.mk ${CURRENTDIR}/src/local.mk.patch 88 | 89 | cd ${CURRENTDIR}/${COREUTILS}/m4 90 | cp cu-progs.m4 cu-progs.m4.org 91 | patch cu-progs.m4 ${CURRENTDIR}/src/cu-progs.m4.patch 92 | 93 | #exit 94 | 95 | # Combine version number from coreutils and securecopy 96 | version_crc=$( cat ${CURRENTDIR}/.version ) 97 | version_gnu=$( cat ${CURRENTDIR}/${COREUTILS}/.version ) 98 | version="[${version_gnu}-${version_crc}]" 99 | 100 | echo "${version_gnu}-${version_crc}" > ${CURRENTDIR}/${COREUTILS}/.version 101 | sed -i "s/m4_esyscmd(\[build-aux\/git-version-gen .tarball-version\])/${version}/g" ${CURRENTDIR}/${COREUTILS}/configure.ac 102 | 103 | # Sometimes required: 104 | #cd ${CURRENTDIR}/${COREUTILS} 105 | #make distclean 106 | 107 | # Configure 108 | cd ${CURRENTDIR}/${COREUTILS} 109 | export FORCE_UNSAFE_CONFIGURE=1 110 | ./configure 111 | make 112 | 113 | cd ${CURRENTDIR}/${COREUTILS}/src 114 | cp crccp crcmv crcsum ${BINDIR}/ 115 | chmod 555 ${BINDIR}/* 116 | chown root.root ${BINDIR}/* 117 | echo "crccp crcmv and crcsum copied to ${BINDIR}" 118 | 119 | 120 | #ADD TEST TEST TEST 121 | while true; do 122 | read -p "Do you wish to install securecopy tools in ${TARGETDIR}?" yn 123 | case $yn in 124 | [Yy]* ) sudo /bin/cp ${BINDIR}/* ${TARGETDIR} ; break;; 125 | [Nn]* ) exit;; 126 | * ) echo "Please answer yes or no.";; 127 | esac 128 | done 129 | 130 | while true; do 131 | read -p "Do you wish to install securecopy tools in ${LOCALTARGETDIR}?" yn 132 | case $yn in 133 | [Yy]* ) sudo /bin/cp ${BINDIR}/* ${LOCALTARGETDIR} ; break;; 134 | [Nn]* ) exit;; 135 | * ) echo "Please answer yes or no.";; 136 | esac 137 | done 138 | 139 | 140 | 141 | echo "++++++++++++++++++++++++++++++++++++" 142 | echo "OPTIONAL: Add to ~/.bashrc:" 143 | echo "alias cp='${TARGETDIR}/crccp -cx'" 144 | echo "alias mv='${TARGETDIR}/crcmv -cx'" 145 | echo "alias crcsum='${TARGETDIR}/crcsum'" 146 | -------------------------------------------------------------------------------- /create-patch-files: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Target coreutils (tested version) 4 | COREUTILS="coreutils-9.3" 5 | 6 | # Internal for this script 7 | CURRENTDIR=${PWD} 8 | 9 | PATCHDIR="${CURRENTDIR}/src" 10 | COREUTILSSRCDIR="${CURRENTDIR}/${COREUTILS}/src" 11 | 12 | echo ${PATCHDIR} 13 | echo ${COREUTILSSRCDIR} 14 | 15 | diff -U 10 ${COREUTILSSRCDIR}/copy.h.org ${COREUTILSSRCDIR}/copy.h > ${PATCHDIR}/copy.h.patch 16 | diff -U 10 ${COREUTILSSRCDIR}/copy.c.org ${COREUTILSSRCDIR}/copy.c > ${PATCHDIR}/copy.c.patch 17 | diff -U 10 ${COREUTILSSRCDIR}/cp.c ${COREUTILSSRCDIR}/crccp.c > ${PATCHDIR}/crccp.c.patch 18 | diff -U 10 ${COREUTILSSRCDIR}/mv.c ${COREUTILSSRCDIR}/crcmv.c > ${PATCHDIR}/crcmv.c.patch 19 | diff -U 10 ${COREUTILSSRCDIR}/cu-progs.mk.org ${COREUTILSSRCDIR}/cu-progs.mk > ${PATCHDIR}/cu-progs.mk.patch 20 | diff -U 10 ${COREUTILSSRCDIR}/local.mk.org ${COREUTILSSRCDIR}/local.mk > ${PATCHDIR}/local.mk.patch 21 | diff -U 10 ${CURRENTDIR}/${COREUTILS}/m4/cu-progs.m4.org ${CURRENTDIR}/${COREUTILS}/m4/cu-progs.m4 > ${PATCHDIR}/cu-progs.m4.patch 22 | -------------------------------------------------------------------------------- /src/copy.c.patch: -------------------------------------------------------------------------------- 1 | --- /home/ijntema/programming/securecopy/core-utils-based/V9.3.0-beta/coreutils-9.3/src/copy.c.org 2023-04-29 19:28:37.708015264 +0200 2 | +++ /home/ijntema/programming/securecopy/core-utils-based/V9.3.0-beta/coreutils-9.3/src/copy.c 2023-04-29 19:28:37.716015014 +0200 3 | @@ -57,20 +57,22 @@ 4 | #include "same.h" 5 | #include "savedir.h" 6 | #include "stat-size.h" 7 | #include "stat-time.h" 8 | #include "utimecmp.h" 9 | #include "utimens.h" 10 | #include "write-any-file.h" 11 | #include "areadlink.h" 12 | #include "yesno.h" 13 | #include "selinux.h" 14 | +/* HIJN */ 15 | +#include "crcsum.h" 16 | 17 | #ifndef USE_XATTR 18 | # define USE_XATTR false 19 | #endif 20 | 21 | #if USE_XATTR 22 | # include 23 | # include 24 | # include 25 | # include "verror.h" 26 | @@ -1242,28 +1244,88 @@ 27 | int dest_errno; 28 | int source_desc; 29 | mode_t src_mode = src_sb->st_mode; 30 | mode_t extra_permissions; 31 | struct stat sb; 32 | struct stat src_open_sb; 33 | union scan_inference scan_inference; 34 | bool return_val = true; 35 | bool data_copy_required = x->data_copy_required; 36 | bool preserve_xattr = USE_XATTR & x->preserve_xattr; 37 | + /* HIJN */ 38 | + t_crc64 crc_src = 0; 39 | 40 | copy_debug.offload = COPY_DEBUG_UNKNOWN; 41 | copy_debug.reflink = x->reflink_mode ? COPY_DEBUG_UNKNOWN : COPY_DEBUG_NO; 42 | copy_debug.sparse_detection = COPY_DEBUG_UNKNOWN; 43 | 44 | source_desc = open (src_name, 45 | (O_RDONLY | O_BINARY 46 | | (x->dereference == DEREF_NEVER ? O_NOFOLLOW : 0))); 47 | + 48 | +/* HIJN */ 49 | +// Checksum 50 | + if (x->crc) 51 | + { 52 | + crc_src = CalculateCRC64(src_name); 53 | + if (x->verbose) 54 | + { 55 | + char* szCRC; 56 | + int ret; 57 | + ret = asprintf(&szCRC, "%016llX", crc_src); 58 | + 59 | + if ( ret != -1) 60 | + { 61 | + printf("[%s]", szCRC); 62 | + } 63 | + } 64 | + } 65 | + 66 | + if (x->crc_with_xattr) 67 | + { 68 | + if ( !IsFreshCRC(src_name) ) // UPDATE CRC when stale 69 | + { 70 | + // suppress errors writing crc in source xattr, as file can be read only or filesystem might not support xattr 71 | + bool bError = false; 72 | + 73 | + // CRC is stale & get new CRC 74 | + if ( !bPutCRC(src_name, &crc_src, bError) ) 75 | + { 76 | + // Don't print an error, as source file can be a read only file, which is a legitimate use case 77 | + printStatus(src_name, "WARNING: FAILED to update CRC; file is read-only?", YELLOW); 78 | + } 79 | + else if (x->verbose) 80 | + { 81 | + textcolor(BRIGHT,YELLOW,BLACK); 82 | + printf("Updated CRC"); 83 | + RESET_TEXT(); 84 | + } 85 | + } 86 | + else 87 | + { 88 | + crc_src = getCRC(src_name); 89 | + } 90 | + 91 | + if (x->verbose) 92 | + { 93 | + char* szCRC; 94 | + int ret; 95 | + ret = asprintf(&szCRC, "%016llX", crc_src); 96 | + 97 | + if ( ret != -1) 98 | + { 99 | + printf("[%s]", szCRC); 100 | + } 101 | + } 102 | + } 103 | + /* END HIJN */ 104 | + 105 | if (source_desc < 0) 106 | { 107 | error (0, errno, _("cannot open %s for reading"), quoteaf (src_name)); 108 | return false; 109 | } 110 | 111 | if (fstat (source_desc, &src_open_sb) != 0) 112 | { 113 | error (0, errno, _("cannot fstat %s"), quoteaf (src_name)); 114 | return_val = false; 115 | @@ -1708,20 +1770,119 @@ 116 | error (0, errno, _("failed to close %s"), quoteaf (dst_name)); 117 | return_val = false; 118 | } 119 | close_src_desc: 120 | if (close (source_desc) < 0) 121 | { 122 | error (0, errno, _("failed to close %s"), quoteaf (src_name)); 123 | return_val = false; 124 | } 125 | 126 | + /* HIJN */ 127 | + // Checksum 128 | + // only if copy itself is successfull 129 | + if (( return_val != false ) && ( ( x->crc ) || (x->crc_with_xattr) )) 130 | + { 131 | + t_crc64 crc_des = 0; 132 | + 133 | + // ONLY for testing 134 | + // 135 | + // printf("WAIT\n"); 136 | + // getchar(); 137 | + 138 | + crc_des = CalculateCRC64(dst_name); 139 | + 140 | + if (crc_des != crc_src) 141 | + { 142 | + if (!x->verbose) 143 | + { 144 | + printf("%s ", src_name); 145 | + } 146 | + textcolor(BRIGHT,RED,BLACK); 147 | + if (x->verbose) 148 | + { 149 | + char* szCRC; 150 | + int ret; 151 | + ret = asprintf(&szCRC, "%016llX", crc_des); 152 | + if ( ret != -1) 153 | + { 154 | + printf("[%s]", szCRC); 155 | + } 156 | + } 157 | + 158 | + // when using crc from stored xattr, it can happen that in very specific cases 159 | + // that src_file CRC is not flagged as stale, but file did change. 160 | + // Either by disk faults (bad) or file has been changed w/o updating mtime (not so bad) 161 | + // Example: Office 2003 is known to update Excel files even when they are not saved 162 | + // Office 2003 does update an internal atime in the excel file w/o updating file's mtime 163 | + if (x->crc_with_xattr) 164 | + { 165 | + crc_src = CalculateCRC64(src_name); 166 | + 167 | + // initially, there was a crc mismath based on stored crc in xattr. We have re-calculated the source crc 168 | + if (crc_des == crc_src) 169 | + { 170 | + textcolor(BRIGHT,YELLOW,BLACK); 171 | + printf("\nWARNING: SRC == DES (based on actual CRC), but, stored CRC of SRC (and DES) file does not match actual CRC of SRC file; SRC file is corrupted?\n"); 172 | + 173 | + // setting to false ensures that when called from crcmv, SRC will not be removed 174 | + return_val = false; 175 | + } 176 | + else 177 | + { 178 | + printf(":Checksum FAILED\n"); 179 | + return_val = false; 180 | + } 181 | + } 182 | + else 183 | + { 184 | + printf(":Checksum FAILED\n"); 185 | + return_val = false; 186 | + } 187 | + } 188 | + else if (x->verbose) 189 | + { 190 | + char* szCRC; 191 | + int ret; 192 | + ret = asprintf(&szCRC, "%016llX", crc_des); 193 | + 194 | + if ( ret != -1) 195 | + { 196 | + textcolor(BRIGHT,GREEN,BLACK); 197 | + printf("[%s]\n", szCRC); 198 | + } 199 | + } 200 | + RESET_TEXT(); 201 | + 202 | + // check if crc is stored in DES xattr (as SRC might be read only) 203 | + if ( return_val == true && x->crc_with_xattr ) 204 | + { 205 | + if ( !IsFreshCRC(dst_name) ) // UPDATE CRC when stale 206 | + { 207 | + // suppress errors writing crc in destination xattr, as destination filesystem might not support xattr 208 | + bool bError = false; 209 | + 210 | + // CRC is stale, write the already calculated crc 211 | + if ( !bPutCRC(dst_name, &crc_des, bError) ) 212 | + { 213 | + if (x->verbose) 214 | + { 215 | + // as this is not a fatal error, mark it as yellow 216 | + printStatus(dst_name, "INFO: Cannot store/update destination CRC in xattr; xattr not supported on filesystem?", GREEN); 217 | + RESET_TEXT(); 218 | + } 219 | + } 220 | + } 221 | + } 222 | + } 223 | + /* END HIJN */ 224 | + 225 | /* Output debug info for data copying operations. */ 226 | if (x->debug) 227 | emit_debug (x); 228 | 229 | alignfree (buf); 230 | return return_val; 231 | } 232 | 233 | /* Return whether it's OK that two files are the "same" by some measure. 234 | The first file is SRC_NAME and has status SRC_SB. 235 | -------------------------------------------------------------------------------- /src/copy.h.patch: -------------------------------------------------------------------------------- 1 | --- /home/ijntema/programming/securecopy/core-utils-based/V9.3.0-beta/coreutils-9.3/src/copy.h.org 2023-04-29 19:28:37.712015139 +0200 2 | +++ /home/ijntema/programming/securecopy/core-utils-based/V9.3.0-beta/coreutils-9.3/src/copy.h 2023-04-29 19:28:37.716015014 +0200 3 | @@ -110,20 +110,28 @@ 4 | following programs: mv (when rename doesn't work), cp, install. 5 | So, if you add a new member, be sure to initialize it in 6 | mv.c, cp.c, and install.c. */ 7 | struct cp_options 8 | { 9 | enum backup_type backup_type; 10 | 11 | /* How to handle symlinks in the source. */ 12 | enum Dereference_symlink dereference; 13 | 14 | + /* HIJN */ 15 | + /* Use CRC checksum to verify whether destination copy is same as source */ 16 | + bool crc; 17 | + 18 | + /* HIJN */ 19 | + /* As crc, nut use xattr to get (fresh) crc or if empty/stale, update crc */ 20 | + bool crc_with_xattr; 21 | + 22 | /* This value is used to determine whether to prompt before removing 23 | each existing destination file. It works differently depending on 24 | whether move_mode is set. See code/comments in copy.c. */ 25 | enum Interactive interactive; 26 | 27 | /* Control creation of sparse files. */ 28 | enum Sparse_type sparse_mode; 29 | 30 | /* Set the mode of the destination file to exactly this value 31 | if SET_MODE is nonzero. */ 32 | -------------------------------------------------------------------------------- /src/crc64.c: -------------------------------------------------------------------------------- 1 | /* Redis uses the CRC64 variant with "Jones" coefficients and init value of 0. 2 | * 3 | * Specification of this CRC64 variant follows: 4 | * Name: crc-64-jones 5 | * Width: 64 bites 6 | * Poly: 0xad93d23594c935a9 7 | * Reflected In: True 8 | * Xor_In: 0xffffffffffffffff 9 | * Reflected_Out: True 10 | * Xor_Out: 0x0 11 | * Check("123456789"): 0xe9c6d914c4b8d9ca 12 | * 13 | * Copyright (c) 2012, Salvatore Sanfilippo 14 | * All rights reserved. 15 | * 16 | * Redistribution and use in source and binary forms, with or without 17 | * modification, are permitted provided that the following conditions are met: 18 | * 19 | * * Redistributions of source code must retain the above copyright notice, 20 | * this list of conditions and the following disclaimer. 21 | * * Redistributions in binary form must reproduce the above copyright 22 | * notice, this list of conditions and the following disclaimer in the 23 | * documentation and/or other materials provided with the distribution. 24 | * * Neither the name of Redis nor the names of its contributors may be used 25 | * to endorse or promote products derived from this software without 26 | * specific prior written permission. 27 | * 28 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 29 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 30 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 31 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 32 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 33 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 34 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 35 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 36 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 37 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 38 | * POSSIBILITY OF SUCH DAMAGE. */ 39 | 40 | 41 | #include 42 | #include "crc64.h" 43 | 44 | static const uint64_t crc64_tab[256] = { 45 | UINT64_C(0x0000000000000000), UINT64_C(0x7ad870c830358979), 46 | UINT64_C(0xf5b0e190606b12f2), UINT64_C(0x8f689158505e9b8b), 47 | UINT64_C(0xc038e5739841b68f), UINT64_C(0xbae095bba8743ff6), 48 | UINT64_C(0x358804e3f82aa47d), UINT64_C(0x4f50742bc81f2d04), 49 | UINT64_C(0xab28ecb46814fe75), UINT64_C(0xd1f09c7c5821770c), 50 | UINT64_C(0x5e980d24087fec87), UINT64_C(0x24407dec384a65fe), 51 | UINT64_C(0x6b1009c7f05548fa), UINT64_C(0x11c8790fc060c183), 52 | UINT64_C(0x9ea0e857903e5a08), UINT64_C(0xe478989fa00bd371), 53 | UINT64_C(0x7d08ff3b88be6f81), UINT64_C(0x07d08ff3b88be6f8), 54 | UINT64_C(0x88b81eabe8d57d73), UINT64_C(0xf2606e63d8e0f40a), 55 | UINT64_C(0xbd301a4810ffd90e), UINT64_C(0xc7e86a8020ca5077), 56 | UINT64_C(0x4880fbd87094cbfc), UINT64_C(0x32588b1040a14285), 57 | UINT64_C(0xd620138fe0aa91f4), UINT64_C(0xacf86347d09f188d), 58 | UINT64_C(0x2390f21f80c18306), UINT64_C(0x594882d7b0f40a7f), 59 | UINT64_C(0x1618f6fc78eb277b), UINT64_C(0x6cc0863448deae02), 60 | UINT64_C(0xe3a8176c18803589), UINT64_C(0x997067a428b5bcf0), 61 | UINT64_C(0xfa11fe77117cdf02), UINT64_C(0x80c98ebf2149567b), 62 | UINT64_C(0x0fa11fe77117cdf0), UINT64_C(0x75796f2f41224489), 63 | UINT64_C(0x3a291b04893d698d), UINT64_C(0x40f16bccb908e0f4), 64 | UINT64_C(0xcf99fa94e9567b7f), UINT64_C(0xb5418a5cd963f206), 65 | UINT64_C(0x513912c379682177), UINT64_C(0x2be1620b495da80e), 66 | UINT64_C(0xa489f35319033385), UINT64_C(0xde51839b2936bafc), 67 | UINT64_C(0x9101f7b0e12997f8), UINT64_C(0xebd98778d11c1e81), 68 | UINT64_C(0x64b116208142850a), UINT64_C(0x1e6966e8b1770c73), 69 | UINT64_C(0x8719014c99c2b083), UINT64_C(0xfdc17184a9f739fa), 70 | UINT64_C(0x72a9e0dcf9a9a271), UINT64_C(0x08719014c99c2b08), 71 | UINT64_C(0x4721e43f0183060c), UINT64_C(0x3df994f731b68f75), 72 | UINT64_C(0xb29105af61e814fe), UINT64_C(0xc849756751dd9d87), 73 | UINT64_C(0x2c31edf8f1d64ef6), UINT64_C(0x56e99d30c1e3c78f), 74 | UINT64_C(0xd9810c6891bd5c04), UINT64_C(0xa3597ca0a188d57d), 75 | UINT64_C(0xec09088b6997f879), UINT64_C(0x96d1784359a27100), 76 | UINT64_C(0x19b9e91b09fcea8b), UINT64_C(0x636199d339c963f2), 77 | UINT64_C(0xdf7adabd7a6e2d6f), UINT64_C(0xa5a2aa754a5ba416), 78 | UINT64_C(0x2aca3b2d1a053f9d), UINT64_C(0x50124be52a30b6e4), 79 | UINT64_C(0x1f423fcee22f9be0), UINT64_C(0x659a4f06d21a1299), 80 | UINT64_C(0xeaf2de5e82448912), UINT64_C(0x902aae96b271006b), 81 | UINT64_C(0x74523609127ad31a), UINT64_C(0x0e8a46c1224f5a63), 82 | UINT64_C(0x81e2d7997211c1e8), UINT64_C(0xfb3aa75142244891), 83 | UINT64_C(0xb46ad37a8a3b6595), UINT64_C(0xceb2a3b2ba0eecec), 84 | UINT64_C(0x41da32eaea507767), UINT64_C(0x3b024222da65fe1e), 85 | UINT64_C(0xa2722586f2d042ee), UINT64_C(0xd8aa554ec2e5cb97), 86 | UINT64_C(0x57c2c41692bb501c), UINT64_C(0x2d1ab4dea28ed965), 87 | UINT64_C(0x624ac0f56a91f461), UINT64_C(0x1892b03d5aa47d18), 88 | UINT64_C(0x97fa21650afae693), UINT64_C(0xed2251ad3acf6fea), 89 | UINT64_C(0x095ac9329ac4bc9b), UINT64_C(0x7382b9faaaf135e2), 90 | UINT64_C(0xfcea28a2faafae69), UINT64_C(0x8632586aca9a2710), 91 | UINT64_C(0xc9622c4102850a14), UINT64_C(0xb3ba5c8932b0836d), 92 | UINT64_C(0x3cd2cdd162ee18e6), UINT64_C(0x460abd1952db919f), 93 | UINT64_C(0x256b24ca6b12f26d), UINT64_C(0x5fb354025b277b14), 94 | UINT64_C(0xd0dbc55a0b79e09f), UINT64_C(0xaa03b5923b4c69e6), 95 | UINT64_C(0xe553c1b9f35344e2), UINT64_C(0x9f8bb171c366cd9b), 96 | UINT64_C(0x10e3202993385610), UINT64_C(0x6a3b50e1a30ddf69), 97 | UINT64_C(0x8e43c87e03060c18), UINT64_C(0xf49bb8b633338561), 98 | UINT64_C(0x7bf329ee636d1eea), UINT64_C(0x012b592653589793), 99 | UINT64_C(0x4e7b2d0d9b47ba97), UINT64_C(0x34a35dc5ab7233ee), 100 | UINT64_C(0xbbcbcc9dfb2ca865), UINT64_C(0xc113bc55cb19211c), 101 | UINT64_C(0x5863dbf1e3ac9dec), UINT64_C(0x22bbab39d3991495), 102 | UINT64_C(0xadd33a6183c78f1e), UINT64_C(0xd70b4aa9b3f20667), 103 | UINT64_C(0x985b3e827bed2b63), UINT64_C(0xe2834e4a4bd8a21a), 104 | UINT64_C(0x6debdf121b863991), UINT64_C(0x1733afda2bb3b0e8), 105 | UINT64_C(0xf34b37458bb86399), UINT64_C(0x8993478dbb8deae0), 106 | UINT64_C(0x06fbd6d5ebd3716b), UINT64_C(0x7c23a61ddbe6f812), 107 | UINT64_C(0x3373d23613f9d516), UINT64_C(0x49aba2fe23cc5c6f), 108 | UINT64_C(0xc6c333a67392c7e4), UINT64_C(0xbc1b436e43a74e9d), 109 | UINT64_C(0x95ac9329ac4bc9b5), UINT64_C(0xef74e3e19c7e40cc), 110 | UINT64_C(0x601c72b9cc20db47), UINT64_C(0x1ac40271fc15523e), 111 | UINT64_C(0x5594765a340a7f3a), UINT64_C(0x2f4c0692043ff643), 112 | UINT64_C(0xa02497ca54616dc8), UINT64_C(0xdafce7026454e4b1), 113 | UINT64_C(0x3e847f9dc45f37c0), UINT64_C(0x445c0f55f46abeb9), 114 | UINT64_C(0xcb349e0da4342532), UINT64_C(0xb1eceec59401ac4b), 115 | UINT64_C(0xfebc9aee5c1e814f), UINT64_C(0x8464ea266c2b0836), 116 | UINT64_C(0x0b0c7b7e3c7593bd), UINT64_C(0x71d40bb60c401ac4), 117 | UINT64_C(0xe8a46c1224f5a634), UINT64_C(0x927c1cda14c02f4d), 118 | UINT64_C(0x1d148d82449eb4c6), UINT64_C(0x67ccfd4a74ab3dbf), 119 | UINT64_C(0x289c8961bcb410bb), UINT64_C(0x5244f9a98c8199c2), 120 | UINT64_C(0xdd2c68f1dcdf0249), UINT64_C(0xa7f41839ecea8b30), 121 | UINT64_C(0x438c80a64ce15841), UINT64_C(0x3954f06e7cd4d138), 122 | UINT64_C(0xb63c61362c8a4ab3), UINT64_C(0xcce411fe1cbfc3ca), 123 | UINT64_C(0x83b465d5d4a0eece), UINT64_C(0xf96c151de49567b7), 124 | UINT64_C(0x76048445b4cbfc3c), UINT64_C(0x0cdcf48d84fe7545), 125 | UINT64_C(0x6fbd6d5ebd3716b7), UINT64_C(0x15651d968d029fce), 126 | UINT64_C(0x9a0d8ccedd5c0445), UINT64_C(0xe0d5fc06ed698d3c), 127 | UINT64_C(0xaf85882d2576a038), UINT64_C(0xd55df8e515432941), 128 | UINT64_C(0x5a3569bd451db2ca), UINT64_C(0x20ed197575283bb3), 129 | UINT64_C(0xc49581ead523e8c2), UINT64_C(0xbe4df122e51661bb), 130 | UINT64_C(0x3125607ab548fa30), UINT64_C(0x4bfd10b2857d7349), 131 | UINT64_C(0x04ad64994d625e4d), UINT64_C(0x7e7514517d57d734), 132 | UINT64_C(0xf11d85092d094cbf), UINT64_C(0x8bc5f5c11d3cc5c6), 133 | UINT64_C(0x12b5926535897936), UINT64_C(0x686de2ad05bcf04f), 134 | UINT64_C(0xe70573f555e26bc4), UINT64_C(0x9ddd033d65d7e2bd), 135 | UINT64_C(0xd28d7716adc8cfb9), UINT64_C(0xa85507de9dfd46c0), 136 | UINT64_C(0x273d9686cda3dd4b), UINT64_C(0x5de5e64efd965432), 137 | UINT64_C(0xb99d7ed15d9d8743), UINT64_C(0xc3450e196da80e3a), 138 | UINT64_C(0x4c2d9f413df695b1), UINT64_C(0x36f5ef890dc31cc8), 139 | UINT64_C(0x79a59ba2c5dc31cc), UINT64_C(0x037deb6af5e9b8b5), 140 | UINT64_C(0x8c157a32a5b7233e), UINT64_C(0xf6cd0afa9582aa47), 141 | UINT64_C(0x4ad64994d625e4da), UINT64_C(0x300e395ce6106da3), 142 | UINT64_C(0xbf66a804b64ef628), UINT64_C(0xc5bed8cc867b7f51), 143 | UINT64_C(0x8aeeace74e645255), UINT64_C(0xf036dc2f7e51db2c), 144 | UINT64_C(0x7f5e4d772e0f40a7), UINT64_C(0x05863dbf1e3ac9de), 145 | UINT64_C(0xe1fea520be311aaf), UINT64_C(0x9b26d5e88e0493d6), 146 | UINT64_C(0x144e44b0de5a085d), UINT64_C(0x6e963478ee6f8124), 147 | UINT64_C(0x21c640532670ac20), UINT64_C(0x5b1e309b16452559), 148 | UINT64_C(0xd476a1c3461bbed2), UINT64_C(0xaeaed10b762e37ab), 149 | UINT64_C(0x37deb6af5e9b8b5b), UINT64_C(0x4d06c6676eae0222), 150 | UINT64_C(0xc26e573f3ef099a9), UINT64_C(0xb8b627f70ec510d0), 151 | UINT64_C(0xf7e653dcc6da3dd4), UINT64_C(0x8d3e2314f6efb4ad), 152 | UINT64_C(0x0256b24ca6b12f26), UINT64_C(0x788ec2849684a65f), 153 | UINT64_C(0x9cf65a1b368f752e), UINT64_C(0xe62e2ad306bafc57), 154 | UINT64_C(0x6946bb8b56e467dc), UINT64_C(0x139ecb4366d1eea5), 155 | UINT64_C(0x5ccebf68aecec3a1), UINT64_C(0x2616cfa09efb4ad8), 156 | UINT64_C(0xa97e5ef8cea5d153), UINT64_C(0xd3a62e30fe90582a), 157 | UINT64_C(0xb0c7b7e3c7593bd8), UINT64_C(0xca1fc72bf76cb2a1), 158 | UINT64_C(0x45775673a732292a), UINT64_C(0x3faf26bb9707a053), 159 | UINT64_C(0x70ff52905f188d57), UINT64_C(0x0a2722586f2d042e), 160 | UINT64_C(0x854fb3003f739fa5), UINT64_C(0xff97c3c80f4616dc), 161 | UINT64_C(0x1bef5b57af4dc5ad), UINT64_C(0x61372b9f9f784cd4), 162 | UINT64_C(0xee5fbac7cf26d75f), UINT64_C(0x9487ca0fff135e26), 163 | UINT64_C(0xdbd7be24370c7322), UINT64_C(0xa10fceec0739fa5b), 164 | UINT64_C(0x2e675fb4576761d0), UINT64_C(0x54bf2f7c6752e8a9), 165 | UINT64_C(0xcdcf48d84fe75459), UINT64_C(0xb71738107fd2dd20), 166 | UINT64_C(0x387fa9482f8c46ab), UINT64_C(0x42a7d9801fb9cfd2), 167 | UINT64_C(0x0df7adabd7a6e2d6), UINT64_C(0x772fdd63e7936baf), 168 | UINT64_C(0xf8474c3bb7cdf024), UINT64_C(0x829f3cf387f8795d), 169 | UINT64_C(0x66e7a46c27f3aa2c), UINT64_C(0x1c3fd4a417c62355), 170 | UINT64_C(0x935745fc4798b8de), UINT64_C(0xe98f353477ad31a7), 171 | UINT64_C(0xa6df411fbfb21ca3), UINT64_C(0xdc0731d78f8795da), 172 | UINT64_C(0x536fa08fdfd90e51), UINT64_C(0x29b7d047efec8728), 173 | }; 174 | 175 | uint64_t crc64(uint64_t crc, const unsigned char *s, uint64_t l) { 176 | uint64_t j; 177 | 178 | for (j = 0; j < l; j++) { 179 | uint8_t byte = s[j]; 180 | crc = crc64_tab[(uint8_t)crc ^ byte] ^ (crc >> 8); 181 | } 182 | return crc; 183 | } 184 | 185 | 186 | #ifdef TEST_MAIN 187 | #include 188 | int main(void) { 189 | printf("e9c6d914c4b8d9ca == %016llx\n", 190 | (unsigned long long) crc64(0,(unsigned char*)"123456789",9)); 191 | return 0; 192 | } 193 | #endif 194 | -------------------------------------------------------------------------------- /src/crc64.h: -------------------------------------------------------------------------------- 1 | static const uint64_t crc64_tab[256]; 2 | uint64_t crc64(uint64_t crc, const unsigned char *s, uint64_t l) __attribute__((pure)); 3 | -------------------------------------------------------------------------------- /src/crccp.c.patch: -------------------------------------------------------------------------------- 1 | --- /home/ijntema/programming/securecopy/core-utils-based/V9.3.0-beta/coreutils-9.3/src/cp.c 2023-04-10 12:14:08.000000000 +0200 2 | +++ /home/ijntema/programming/securecopy/core-utils-based/V9.3.0-beta/coreutils-9.3/src/crccp.c 2023-04-29 19:42:51.173332110 +0200 3 | @@ -31,26 +31,28 @@ 4 | #include "error.h" 5 | #include "filenamecat.h" 6 | #include "ignore-value.h" 7 | #include "quote.h" 8 | #include "stat-time.h" 9 | #include "targetdir.h" 10 | #include "utimens.h" 11 | #include "acl.h" 12 | 13 | /* The official name of this program (e.g., no 'g' prefix). */ 14 | -#define PROGRAM_NAME "cp" 15 | +/* HIJN */ 16 | +#define PROGRAM_NAME "crccp" 17 | 18 | #define AUTHORS \ 19 | proper_name ("Torbjorn Granlund"), \ 20 | proper_name ("David MacKenzie"), \ 21 | - proper_name ("Jim Meyering") 22 | + proper_name ("Jim Meyering"), \ 23 | + proper_name ("Checksum functionality only: Hans IJntema") 24 | 25 | /* Used by do_copy, make_dir_parents_private, and re_protect 26 | to keep a list of leading directories whose protections 27 | need to be fixed after copying. */ 28 | struct dir_attr 29 | { 30 | struct stat st; 31 | bool restore_mode; 32 | size_t slash_offset; 33 | struct dir_attr *next; 34 | @@ -111,20 +113,22 @@ 35 | UPDATE_ALL, UPDATE_NONE, UPDATE_OLDER, 36 | }; 37 | ARGMATCH_VERIFY (update_type_string, update_type); 38 | 39 | static struct option const long_opts[] = 40 | { 41 | {"archive", no_argument, NULL, 'a'}, 42 | {"attributes-only", no_argument, NULL, ATTRIBUTES_ONLY_OPTION}, 43 | {"backup", optional_argument, NULL, 'b'}, 44 | {"copy-contents", no_argument, NULL, COPY_CONTENTS_OPTION}, 45 | + /* HIJN */ 46 | + {"crc", optional_argument, NULL, 'c'}, 47 | {"debug", no_argument, NULL, DEBUG_OPTION}, 48 | {"dereference", no_argument, NULL, 'L'}, 49 | {"force", no_argument, NULL, 'f'}, 50 | {"interactive", no_argument, NULL, 'i'}, 51 | {"link", no_argument, NULL, 'l'}, 52 | {"no-clobber", no_argument, NULL, 'n'}, 53 | {"no-dereference", no_argument, NULL, 'P'}, 54 | {"no-preserve", required_argument, NULL, NO_PRESERVE_ATTRIBUTES_OPTION}, 55 | {"no-target-directory", no_argument, NULL, 'T'}, 56 | {"one-file-system", no_argument, NULL, 'x'}, 57 | @@ -166,20 +170,25 @@ 58 | 59 | emit_mandatory_arg_note (); 60 | 61 | fputs (_("\ 62 | -a, --archive same as -dR --preserve=all\n\ 63 | --attributes-only don't copy the file data, just the attributes\n\ 64 | --backup[=CONTROL] make a backup of each existing destination file\ 65 | \n\ 66 | -b like --backup but does not accept an argument\n\ 67 | --copy-contents copy contents of special files when recursive\n\ 68 | + -c --crc[=x] check whether copy was successfull with checksum comparison\n\ 69 | + x: use (fresh) checksum stored in xattr or if not present,\n\ 70 | + store checksum in xattr of src and des\n\ 71 | + See also tool in same secure copy package\n\ 72 | + implies --preserve=all\n\ 73 | -d same as --no-dereference --preserve=links\n\ 74 | "), stdout); 75 | fputs (_("\ 76 | --debug explain how a file is copied. Implies -v\n\ 77 | "), stdout); 78 | fputs (_("\ 79 | -f, --force if an existing destination file cannot be\n\ 80 | opened, remove it and try again (this option\n\ 81 | is ignored when the -n option is also used)\n\ 82 | -i, --interactive prompt before overwrite (overrides a previous -n\ 83 | @@ -806,20 +815,24 @@ 84 | } 85 | 86 | return ok; 87 | } 88 | 89 | static void 90 | cp_option_init (struct cp_options *x) 91 | { 92 | cp_options_default (x); 93 | x->copy_as_regular = true; 94 | + /* HIJN */ 95 | + x->crc = false; 96 | + x->crc_with_xattr = false; 97 | + /* END HIJN */ 98 | x->dereference = DEREF_UNDEFINED; 99 | x->unlink_dest_before_opening = false; 100 | x->unlink_dest_after_failed_open = false; 101 | x->hard_link = false; 102 | x->interactive = I_UNSPECIFIED; 103 | x->move_mode = false; 104 | x->install_mode = false; 105 | x->one_file_system = false; 106 | x->reflink_mode = REFLINK_AUTO; 107 | 108 | @@ -971,21 +984,22 @@ 109 | set_program_name (argv[0]); 110 | setlocale (LC_ALL, ""); 111 | bindtextdomain (PACKAGE, LOCALEDIR); 112 | textdomain (PACKAGE); 113 | 114 | atexit (close_stdin); 115 | 116 | selinux_enabled = (0 < is_selinux_enabled ()); 117 | cp_option_init (&x); 118 | 119 | - while ((c = getopt_long (argc, argv, "abdfHilLnprst:uvxPRS:TZ", 120 | + /* HIJN */ 121 | + while ((c = getopt_long (argc, argv, "abc::dfHilLnprst:uvxPRS:TZ", 122 | long_opts, NULL)) 123 | != -1) 124 | { 125 | switch (c) 126 | { 127 | case SPARSE_OPTION: 128 | x.sparse_mode = XARGMATCH ("--sparse", optarg, 129 | sparse_type_string, sparse_type); 130 | break; 131 | 132 | @@ -1011,20 +1025,48 @@ 133 | x.reduce_diagnostics = true; 134 | x.recursive = true; 135 | break; 136 | 137 | case 'b': 138 | make_backups = true; 139 | if (optarg) 140 | version_control_string = optarg; 141 | break; 142 | 143 | + /* HIJN */ 144 | + case 'c': 145 | + if (optarg) 146 | + { 147 | + if ( strcmp( optarg, "x") == 0 ) 148 | + { 149 | + x.crc_with_xattr = true; 150 | + x.crc = false; 151 | + 152 | + // will this stick if --no-preserve=xattr? 153 | + x.preserve_mode = true; 154 | + x.preserve_timestamps = true; 155 | + x.preserve_ownership = true; 156 | + x.preserve_links = true; 157 | + x.explicit_no_preserve_mode = false; 158 | + if (selinux_enabled) 159 | + x.preserve_security_context = true; 160 | + x.preserve_xattr = true; 161 | + } 162 | + } 163 | + else 164 | + { 165 | + x.crc = true; 166 | + x.crc_with_xattr = false; 167 | + } 168 | + break; 169 | + /* END HIJN */ 170 | + 171 | case ATTRIBUTES_ONLY_OPTION: 172 | x.data_copy_required = false; 173 | break; 174 | 175 | case DEBUG_OPTION: 176 | x.debug = x.verbose = true; 177 | break; 178 | 179 | case COPY_CONTENTS_OPTION: 180 | copy_contents = true; 181 | -------------------------------------------------------------------------------- /src/crccp.x: -------------------------------------------------------------------------------- 1 | [NAME] 2 | crccp \- copy files and directories 3 | [DESCRIPTION] 4 | .\" Add any additional description here 5 | -------------------------------------------------------------------------------- /src/crcmv.c.patch: -------------------------------------------------------------------------------- 1 | --- /home/ijntema/programming/securecopy/core-utils-based/V9.3.0-beta/coreutils-9.3/src/mv.c 2023-04-10 12:14:08.000000000 +0200 2 | +++ /home/ijntema/programming/securecopy/core-utils-based/V9.3.0-beta/coreutils-9.3/src/crcmv.c 2023-04-29 19:43:02.116990278 +0200 3 | @@ -30,27 +30,32 @@ 4 | #include "cp-hash.h" 5 | #include "die.h" 6 | #include "error.h" 7 | #include "filenamecat.h" 8 | #include "remove.h" 9 | #include "renameatu.h" 10 | #include "root-dev-ino.h" 11 | #include "targetdir.h" 12 | #include "priv-set.h" 13 | 14 | +/* HIJN */ 15 | +#include "crcsum.h" 16 | + 17 | /* The official name of this program (e.g., no 'g' prefix). */ 18 | -#define PROGRAM_NAME "mv" 19 | +/* HIJN */ 20 | +#define PROGRAM_NAME "crcmv" 21 | 22 | #define AUTHORS \ 23 | proper_name ("Mike Parker"), \ 24 | proper_name ("David MacKenzie"), \ 25 | - proper_name ("Jim Meyering") 26 | + proper_name ("Jim Meyering"), \ 27 | + proper_name ("Checksum functionality only: Hans IJntema") 28 | 29 | /* For long options that have no equivalent short option, use a 30 | non-character as a pseudo short option, starting with CHAR_MAX + 1. */ 31 | enum 32 | { 33 | DEBUG_OPTION = CHAR_MAX + 1, 34 | NO_COPY_OPTION, 35 | STRIP_TRAILING_SLASHES_OPTION 36 | }; 37 | 38 | @@ -60,20 +65,22 @@ 39 | }; 40 | static enum Update_type const update_type[] = 41 | { 42 | UPDATE_ALL, UPDATE_NONE, UPDATE_OLDER, 43 | }; 44 | ARGMATCH_VERIFY (update_type_string, update_type); 45 | 46 | static struct option const long_options[] = 47 | { 48 | {"backup", optional_argument, NULL, 'b'}, 49 | + /* HIJN */ 50 | + {"crc", optional_argument, NULL, 'c'}, 51 | {"context", no_argument, NULL, 'Z'}, 52 | {"debug", no_argument, NULL, DEBUG_OPTION}, 53 | {"force", no_argument, NULL, 'f'}, 54 | {"interactive", no_argument, NULL, 'i'}, 55 | {"no-clobber", no_argument, NULL, 'n'}, 56 | {"no-copy", no_argument, NULL, NO_COPY_OPTION}, 57 | {"no-target-directory", no_argument, NULL, 'T'}, 58 | {"strip-trailing-slashes", no_argument, NULL, STRIP_TRAILING_SLASHES_OPTION}, 59 | {"suffix", required_argument, NULL, 'S'}, 60 | {"target-directory", required_argument, NULL, 't'}, 61 | @@ -116,20 +123,24 @@ 62 | x->preserve_all_root = false; 63 | } 64 | 65 | static void 66 | cp_option_init (struct cp_options *x) 67 | { 68 | bool selinux_enabled = (0 < is_selinux_enabled ()); 69 | 70 | cp_options_default (x); 71 | x->copy_as_regular = false; /* FIXME: maybe make this an option */ 72 | + /* HIJN */ 73 | + x->crc = false; 74 | + x->crc_with_xattr = false; 75 | + /* END HIJN */ 76 | x->reflink_mode = REFLINK_AUTO; 77 | x->dereference = DEREF_NEVER; 78 | x->unlink_dest_before_opening = false; 79 | x->unlink_dest_after_failed_open = false; 80 | x->hard_link = false; 81 | x->interactive = I_UNSPECIFIED; 82 | x->move_mode = true; 83 | x->install_mode = false; 84 | x->one_file_system = false; 85 | x->preserve_ownership = true; 86 | @@ -262,20 +273,25 @@ 87 | fputs (_("\ 88 | Rename SOURCE to DEST, or move SOURCE(s) to DIRECTORY.\n\ 89 | "), stdout); 90 | 91 | emit_mandatory_arg_note (); 92 | 93 | fputs (_("\ 94 | --backup[=CONTROL] make a backup of each existing destination file\ 95 | \n\ 96 | -b like --backup but does not accept an argument\n\ 97 | + -c --crc[=x] check whether copy was successfull with checksum comparison\n\ 98 | + x: use (fresh) checksum stored in xattr or if not present,\n\ 99 | + store checksum in xattr of src and des\n\ 100 | + See also tool in same secure copy package\n\ 101 | + implies --preserve=xattr\n\ 102 | "), stdout); 103 | fputs (_("\ 104 | --debug explain how a file is copied. Implies -v\n\ 105 | "), stdout); 106 | fputs (_("\ 107 | -f, --force do not prompt before overwriting\n\ 108 | -i, --interactive prompt before overwrite\n\ 109 | -n, --no-clobber do not overwrite an existing file\n\ 110 | If you specify more than one of -i, -f, -n, only the final one takes effect.\n\ 111 | "), stdout); 112 | @@ -330,30 +346,60 @@ 113 | bindtextdomain (PACKAGE, LOCALEDIR); 114 | textdomain (PACKAGE); 115 | 116 | atexit (close_stdin); 117 | 118 | cp_option_init (&x); 119 | 120 | /* Try to disable the ability to unlink a directory. */ 121 | priv_set_remove_linkdir (); 122 | 123 | - while ((c = getopt_long (argc, argv, "bfint:uvS:TZ", long_options, NULL)) 124 | + /* HIJN */ 125 | + while ((c = getopt_long (argc, argv, "bc::fint:uvS:TZ", long_options, NULL)) 126 | != -1) 127 | { 128 | switch (c) 129 | { 130 | case 'b': 131 | make_backups = true; 132 | if (optarg) 133 | version_control_string = optarg; 134 | break; 135 | + 136 | + /* HIJN */ 137 | + case 'c': 138 | + if (optarg) 139 | + { 140 | + if ( strcmp( optarg, "x") == 0 ) 141 | + { 142 | + x.crc_with_xattr = true; 143 | + x.crc = false; 144 | + 145 | + // will this stick if --no-preserve=xattr? 146 | + x.preserve_mode = true; 147 | + x.preserve_timestamps = true; 148 | + x.preserve_ownership = true; 149 | + x.preserve_links = true; 150 | + x.explicit_no_preserve_mode = false; 151 | + if (selinux_enabled) 152 | + x.preserve_security_context = true; 153 | + x.preserve_xattr = true; 154 | + } 155 | + } 156 | + else 157 | + { 158 | + x.crc = true; 159 | + x.crc_with_xattr = false; 160 | + } 161 | + break; 162 | + /* END HIJN */ 163 | + 164 | case 'f': 165 | x.interactive = I_ALWAYS_YES; 166 | break; 167 | case 'i': 168 | x.interactive = I_ASK_USER; 169 | break; 170 | case 'n': 171 | x.interactive = I_ALWAYS_NO; 172 | break; 173 | case DEBUG_OPTION: 174 | -------------------------------------------------------------------------------- /src/crcmv.x: -------------------------------------------------------------------------------- 1 | [NAME] 2 | crcmv \- move (rename) files 3 | [DESCRIPTION] 4 | .\" Add any additional description here 5 | [SEE ALSO] 6 | rename(2) 7 | -------------------------------------------------------------------------------- /src/crcsum.c: -------------------------------------------------------------------------------- 1 | /* 2 | This program is free software: you can redistribute it and/or modify 3 | it under the terms of the GNU General Public License as published by 4 | the Free Software Foundation, version 3 of the License. 5 | 6 | This program is distributed in the hope that it will be useful, 7 | but WITHOUT ANY WARRANTY; without even the implied warranty of 8 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 9 | GNU General Public License for more details. 10 | 11 | You should have received a copy of the GNU General Public License 12 | along with this program. If not, see . 13 | 14 | This software is based on Checkit version 0.2.0 15 | Dennis Katsonis; E-Mail dennisk (at) netspace.net.au 16 | */ 17 | 18 | #define _GNU_SOURCE // asprintf 19 | 20 | // This caused build issues on Debian Jessie. Not sure why. Not sure if disabling is an issue too 21 | //#define _XOPEN_SOURCE 500 // nftw 22 | 23 | 24 | // to overcome issue with file size & stat limitations on 32 bit systems 25 | #define _FILE_OFFSET_BITS 64 26 | 27 | 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | 45 | #include "config.h" 46 | 47 | #include 48 | 49 | #include "crc64.h" 50 | #include "crcsum.h" 51 | 52 | int flags = 0; 53 | int processed = 0; 54 | int failed = 0; 55 | int ext_counter = 0; 56 | char arr_ext[MAXEXT][5]; 57 | 58 | 59 | 60 | //////////////////////////////////////////////////////////// 61 | // Check if CRC64 attribute is present. 62 | // Returns 63 | // true: success 64 | // false: if requested attribute is not present 65 | //////////////////////////////////////////////////////////// 66 | int IsPresentCRC64(const char *file) 67 | { 68 | char buf[4096]; 69 | char* current_attr; 70 | int x; 71 | 72 | // size = listxattr(file, buff, 0); 73 | // use to dynamically allocate buf size 74 | 75 | x = listxattr(file, buf, 4096); 76 | current_attr = buf; 77 | 78 | if (x > 0) 79 | { 80 | do 81 | { 82 | if (strcmp(current_attr, "user.crc64") == 0) 83 | { 84 | return true; 85 | } 86 | else 87 | { 88 | current_attr += (strlen(current_attr) + 1); 89 | } 90 | } 91 | while ((current_attr - buf) < x); 92 | } 93 | else if (x == -1) 94 | { 95 | perror("IsPresentCRC64:listxattr"); 96 | } 97 | return false; 98 | } 99 | 100 | 101 | //////////////////////////////////////////////////////////// 102 | // Check if CRC is fresh 103 | // RETURN 104 | // true: fresh 105 | // false: stale or CRC not present or on any stat(file) error 106 | //////////////////////////////////////////////////////////// 107 | int IsFreshCRC(const char *filename) 108 | { 109 | //int attribute_format; 110 | struct s_crc64 crc; //crc, t 111 | struct stat stat_file; 112 | 113 | if ( stat(filename, &stat_file) == -1 ) 114 | { 115 | printStatus(filename, "ERROR", RED); 116 | perror("IsFreshCRC:stat"); 117 | return false; 118 | } 119 | 120 | //attribute_format = IsPresentCRC64(filename); 121 | 122 | if ( IsPresentCRC64(filename) ) 123 | { 124 | if ((getxattr(filename, "user.crc64", &crc, sizeof(crc)) == -1)) 125 | { 126 | //printStatus(filename, "ERROR", RED); 127 | //perror("IsFreshCRC:getxattr"); 128 | return false; 129 | } 130 | else 131 | { 132 | return (crc.t == stat_file.st_mtime); 133 | } 134 | } 135 | return 0; 136 | } 137 | 138 | 139 | //////////////////////////////////////////////////////////// 140 | // Removes the CRC 141 | //////////////////////////////////////////////////////////// 142 | int removeCRC(const char *filename) 143 | { 144 | if ( IsPresentCRC64(filename) ) 145 | { 146 | if ((removexattr(filename, "user.crc64")) == -1) 147 | { 148 | printStatus(filename, "ERROR", RED); 149 | perror("removeCRC:removexattr"); 150 | failed++; 151 | return false; 152 | } 153 | else 154 | { 155 | if (flags & VERBOSE) 156 | { 157 | printStatus(filename,"CRC removed", GREEN); 158 | } 159 | } 160 | } 161 | processed++; 162 | return true; 163 | } 164 | 165 | //////////////////////////////////////////////////////////// 166 | // Write CRC - depending on flags 167 | // 168 | // filename: file under subject 169 | // *crc : pointer to a t_crc64 where crc value will be stored; pointer can be NULL (and value will not be stored) 170 | // if *crc != null (crc value), the provided crc value will be stored; otherwise it will be calculated 171 | // bError : ignore errors writing to xattr (in case of read only files) 172 | // 173 | // return: 174 | // false : failed 175 | // true : success 176 | int bPutCRC(const char *filename, t_crc64 *crc, bool bError) 177 | { 178 | struct stat stat_file; 179 | struct s_crc64 s_crc; //crc, t 180 | 181 | if ( stat(filename, &stat_file) == -1 ) 182 | { 183 | printStatus(filename, "ERROR", RED); 184 | perror("bPutCRC:stat"); 185 | return false; 186 | } 187 | 188 | if (crc != NULL && *crc != 0) 189 | { 190 | // pointer to a crc value is there AND a non zero crc value is provided 191 | // use provided crc value 192 | s_crc.crc = *crc; 193 | s_crc.t = stat_file.st_mtime; 194 | } 195 | 196 | if (crc != NULL && *crc == 0) 197 | { 198 | // pointer to a crc value is there AND a zero crc value is provided 199 | // Calculate crc value & return value 200 | s_crc.crc = CalculateCRC64(filename); 201 | s_crc.t = stat_file.st_mtime; 202 | *crc = s_crc.crc; 203 | } 204 | 205 | if (crc == NULL) 206 | { 207 | // Calculate crc value 208 | s_crc.crc = CalculateCRC64(filename); 209 | s_crc.t = stat_file.st_mtime; 210 | } 211 | 212 | if ( (setxattr(filename, "user.crc64", &s_crc, sizeof(s_crc), 0 )) == -1 ) 213 | { 214 | // print error when requested. In some cases (in expected read only file) it is OK to ignore error 215 | if (bError) 216 | { 217 | printStatus(filename, "ERROR", RED); 218 | perror("bPutCRC:setxattr"); 219 | } 220 | return false; 221 | } 222 | else 223 | { 224 | processed++; 225 | return true; 226 | } 227 | 228 | processed++; 229 | return true; 230 | } 231 | 232 | // This retreives the CRC, first by checking for an extended attribute 233 | // then by looking for a hidden file. Returns 0 if unsuccessful, otherwise 234 | // return the checksum.*/ 235 | t_crc64 getCRC(const char *filename) 236 | { 237 | //int attribute_format; 238 | struct s_crc64 crc; //crc, t 239 | 240 | //attribute_format = IsPresentCRC64(filename); 241 | 242 | if ( !IsPresentCRC64(filename) ) 243 | { 244 | //printf("%s: No CRC stored\n", filename); 245 | return false; 246 | } 247 | 248 | if ( IsPresentCRC64(filename) ) 249 | { 250 | if ((getxattr(filename, "user.crc64", &crc, sizeof(crc)) == -1)) 251 | { 252 | printStatus(filename, "ERROR", RED); 253 | perror("getCRC:getxattr"); 254 | return false; 255 | } 256 | else 257 | { 258 | return crc.crc; 259 | } 260 | } 261 | return false; 262 | } 263 | 264 | //////////////////////////////////////////////////////////// 265 | // Open file and calculate CRC 266 | //////////////////////////////////////////////////////////// 267 | t_crc64 CalculateCRC64(const char *filename) 268 | { 269 | unsigned char buf[MAX_BUF_LEN]; 270 | size_t bufread = MAX_BUF_LEN; 271 | int cont = 1; 272 | int fd; 273 | uint64_t tot = 0; 274 | uint64_t temp = 0; 275 | 276 | if ((fd = open(filename,O_RDONLY)) == -1) 277 | { 278 | printStatus(filename, "ERROR", RED); 279 | perror("CalculateCRC64:open"); 280 | return 0; 281 | } 282 | 283 | while (cont) 284 | { 285 | bufread = read(fd, buf, bufread); 286 | if (bufread == -1) 287 | { 288 | printStatus(filename, "ERROR", RED); 289 | perror("CalculateCRC64:read"); 290 | close(fd); 291 | return 0; 292 | } 293 | 294 | temp = (t_crc64) crc64(temp, buf, (unsigned int)bufread); 295 | tot = tot + bufread; 296 | 297 | if (bufread < MAX_BUF_LEN) 298 | { 299 | cont = 0; 300 | } 301 | } 302 | 303 | close(fd); 304 | return temp; 305 | } 306 | 307 | 308 | //////////////////////////////////////////////////////////// 309 | // Return: 310 | // 0: Continue next in tree walk on nftw() 311 | // !=0: Terminate tree walk 312 | //////////////////////////////////////////////////////////// 313 | int nftw_callback(const char *fpath, const struct stat *sb, int tflag, __attribute__((unused)) struct FTW *ftwbuf) 314 | { 315 | // FTW_F also includes PIPES; not sure about SOCKETS etc 316 | // Hence, use stat information to check whether it is a regular file 317 | // if ( tflag == FTW_F ) 318 | if S_ISREG(sb->st_mode) 319 | { 320 | //Process File 321 | // TODO return value 322 | processFile(fpath); 323 | return 0; 324 | } 325 | else 326 | { 327 | if (flags & VERBOSE) 328 | { 329 | switch (sb->st_mode & S_IFMT) 330 | { 331 | case S_IFBLK: printStatus(fpath, "Block Devioce", YELLOW); break; 332 | case S_IFCHR: printStatus(fpath, "Char Deviced", YELLOW); break; 333 | case S_IFDIR: printStatus(fpath, "Directory", RED); break; 334 | case S_IFIFO: printStatus(fpath, "FIFO/pipe", YELLOW); break; 335 | case S_IFLNK: printStatus(fpath, "Symlink", YELLOW); break; 336 | case S_IFSOCK: printStatus(fpath, "Socket", YELLOW); break; 337 | case S_ISVTX: printStatus(fpath, "S_ISVTX", YELLOW); break; 338 | default: printStatus(fpath, "Unknown?", RED); printf("%04X", (sb->st_mode & S_IFMT)); break; 339 | } 340 | } 341 | } 342 | 343 | // continue tree walk 344 | return 0; 345 | } 346 | 347 | 348 | //////////////////////////////////////////////////////////// 349 | // First entry after option flag processing for cmdline arguments procession 350 | // Separate files from directories 351 | //////////////////////////////////////////////////////////// 352 | int processCmdLine(const char *filename) 353 | { 354 | struct stat statbuf; 355 | 356 | if ( lstat(filename, &statbuf) == -1 ) 357 | { 358 | printStatus(filename, "ERROR", RED); 359 | perror("processCmdLine:stat"); 360 | return false; 361 | } 362 | 363 | // check if we are a directory AND need to process recursively 364 | if ( S_ISDIR(statbuf.st_mode) && (flags & RECURSE) ) 365 | { 366 | // Process Directory 367 | int typeflag = FTW_PHYS | FTW_MOUNT; //Symbolic links are not followed; stay in same FS 368 | const int maxDirs = 100; 369 | 370 | if ( nftw( filename, nftw_callback, maxDirs, typeflag) == -1 ) 371 | { 372 | printStatus(filename, "ERROR", RED); 373 | perror("processCmdLine:nftw"); 374 | return false; 375 | } 376 | 377 | return true; 378 | } 379 | 380 | // Check if we are a Regular file (symbolic links are excluded) 381 | if ( S_ISREG(statbuf.st_mode) && !S_ISLNK(statbuf.st_mode) ) 382 | { 383 | // Process File 384 | processFile(filename); 385 | return true; 386 | } 387 | else 388 | { 389 | if (flags & VERBOSE) 390 | { 391 | switch (statbuf.st_mode & S_IFMT) 392 | { 393 | case S_IFBLK: printStatus(filename, "Block Devioce", YELLOW); break; 394 | case S_IFCHR: printStatus(filename, "Char Deviced", YELLOW); break; 395 | case S_IFDIR: printStatus(filename, "Directory", RED); break; 396 | case S_IFIFO: printStatus(filename, "FIFO/pipe", YELLOW); break; 397 | case S_IFLNK: printStatus(filename, "Symlink", YELLOW); break; 398 | case S_IFSOCK: printStatus(filename, "Socket", YELLOW); break; 399 | case S_ISVTX: printStatus(filename, "S_ISVTX", YELLOW); break; 400 | default: printStatus(filename, "Unknown?", RED); printf("%04X", (statbuf.st_mode & S_IFMT)); break; 401 | } 402 | } 403 | } 404 | 405 | return false; 406 | } 407 | 408 | //////////////////////////////////////////////////////////// 409 | // Expects a Regular File 410 | //////////////////////////////////////////////////////////// 411 | int processFile(const char *filename) 412 | { 413 | struct stat statbuf; 414 | 415 | if ( lstat(filename, &statbuf) == -1 ) 416 | { 417 | printStatus(filename, "ERROR", RED); 418 | perror("processFile:lstat"); 419 | return false; 420 | } 421 | 422 | // Print CRC64 423 | // Red: CRC = stale 424 | // Green: CRC = fresh 425 | if (flags & PRINT) 426 | { 427 | t_crc64 crc; 428 | 429 | // print entries with fresh CRC in green text 430 | if ( (crc = getCRC(filename)) ) 431 | { 432 | if ( IsFreshCRC(filename) ) 433 | { 434 | char* szCRC; 435 | asprintf(&szCRC, "%016llX", crc); 436 | printStatus(filename, szCRC, GREEN); 437 | free(szCRC); szCRC = NULL; 438 | return true; 439 | } 440 | else if (flags & DEBUG) 441 | { 442 | char* szCRC; 443 | asprintf(&szCRC, "%016llX", crc); 444 | printStatus(filename, szCRC, RED); 445 | free(szCRC); szCRC = NULL; 446 | return true; 447 | } 448 | } 449 | 450 | // print entries without CRC in white text 451 | else if (flags & DEBUG) 452 | { 453 | if (statbuf.st_size == 0) 454 | { 455 | printStatus(filename," Zero File Size ", YELLOW); 456 | } 457 | else 458 | { 459 | printStatus(filename,"No CRC available", YELLOW); 460 | } 461 | return false; 462 | } 463 | else 464 | { 465 | return false; 466 | } 467 | } 468 | 469 | // STORE CRC but do not OVERWRITE or UPDATE existing CRC 470 | if ( (flags & STORE) && (!(flags & OVERWRITE)) && (!(flags & UPDATE)) ) 471 | { 472 | if(IsPresentCRC64(filename)) 473 | { 474 | if (flags & DEBUG) 475 | { 476 | printStatus(filename,"CRC already stored", YELLOW); 477 | } 478 | return false; 479 | } 480 | else if ( !bPutCRC(filename, NULL, true) ) 481 | { 482 | fprintf(stderr, "%s: Failed to store CRC.\n", filename); 483 | return false; 484 | } 485 | else if (flags & VERBOSE) 486 | { 487 | printStatus(filename, " CRC is saved ", GREEN); 488 | } 489 | return true; 490 | } 491 | 492 | // OVERWRITE CRC 493 | if (flags & OVERWRITE) 494 | { 495 | if ( !bPutCRC(filename, NULL, true) ) 496 | { 497 | //fprintf(stderr, "%s: Failed to overwrite CRC.\n", filename); 498 | return false; 499 | } 500 | else if (flags & VERBOSE) 501 | { 502 | printStatus(filename, " CRC is overwritten ", GREEN); 503 | } 504 | return true; 505 | } 506 | 507 | // UPDATE CRC when stale 508 | if (flags & UPDATE) 509 | { 510 | if ( !IsFreshCRC(filename) ) 511 | { 512 | // CRC is stale 513 | if ( !bPutCRC(filename, NULL, true) ) 514 | { 515 | //printStatus(filename, "FAILED to update CRC", RED); 516 | return false; 517 | } 518 | else if (flags & VERBOSE) 519 | { 520 | printStatus(filename, " Updated CRC ", GREEN); 521 | return true; 522 | } 523 | } 524 | else if (flags & DEBUG) 525 | { 526 | printStatus(filename, "No CRC Update", YELLOW); 527 | } 528 | return true; 529 | } 530 | 531 | // Check CRC only if CRC is not stale 532 | if (flags & CHECK) 533 | { 534 | if ( IsFreshCRC(filename) ) 535 | { 536 | // check if extension to be ommitted 537 | if (flags & OMIT) 538 | { 539 | // copy filename 540 | char *buffer; 541 | buffer = malloc(strlen(filename) + 1); 542 | strcpy(buffer, filename); 543 | 544 | char* p = NULL; 545 | char* prev_p = NULL; 546 | p = strtok(buffer, "."); 547 | while (p != NULL) 548 | { 549 | if (prev_p != NULL) 550 | free(prev_p); 551 | prev_p = NULL; 552 | 553 | prev_p = malloc(strlen(p) + 1); 554 | strcpy(prev_p, p); 555 | p = strtok (NULL, "."); 556 | } 557 | free(buffer); 558 | buffer = NULL; 559 | 560 | for (int i = 0; i < ext_counter; i++) 561 | { 562 | if (strcmp(arr_ext[i], prev_p) == 0) 563 | { 564 | if (flags & VERBOSE) 565 | { 566 | printStatus(filename, " OMIT ", GREEN); 567 | } 568 | processed++; 569 | free(prev_p); 570 | prev_p = NULL; 571 | return true; 572 | } 573 | } 574 | free(prev_p); 575 | prev_p = NULL; 576 | } 577 | if (CalculateCRC64(filename) == getCRC(filename)) 578 | { 579 | if (flags & VERBOSE) 580 | { 581 | printStatus(filename, " OK ", GREEN); 582 | } 583 | } 584 | else 585 | { 586 | printStatus(filename, "FAILED", RED); 587 | failed++; 588 | } 589 | processed++; 590 | } 591 | } // End of Check CRC routine 592 | 593 | // Remove CRC 594 | if (flags & REMOVE) 595 | { 596 | if ( removeCRC(filename) ) 597 | { 598 | return true; 599 | } 600 | else 601 | { 602 | char path[PATH_MAX]; 603 | getcwd(path, PATH_MAX); 604 | printf("%s/%s: Remove CRC failed\n", path, filename); 605 | return false; 606 | } 607 | } // End of Remove CRC routine 608 | return true; 609 | } 610 | 611 | 612 | // Print status message 613 | void printStatus(const char* filename, const char* status, int fg) 614 | { 615 | printf("[ "); 616 | textcolor(BRIGHT,fg,BLACK); 617 | printf("%s", status); 618 | RESET_TEXT(); 619 | printf(" ] "); 620 | printf(" %-20s\n", filename); 621 | } 622 | 623 | // Change text colour 624 | void textcolor(int attr, int fg, int bg) 625 | { 626 | char command[13]; 627 | 628 | // Command is the control command to the terminal 629 | sprintf(command, "%c[%d;%d;%dm", 0x1B, attr, fg + 30, bg + 40); 630 | printf("%s", command); 631 | } 632 | -------------------------------------------------------------------------------- /src/crcsum.h: -------------------------------------------------------------------------------- 1 | #ifndef _CRCSUM_H 2 | #define _CRCSUM_H 1 3 | 4 | #include 5 | 6 | #define MAX_BUF_LEN (65536) 7 | #define RESET_TEXT() printf("\033[0;0m") 8 | 9 | #define RESET 0 10 | #define BRIGHT 1 11 | #define DIM 2 12 | #define UNDERLINE 3 13 | #define BLINK 4 14 | #define REVERSE 7 15 | #define HIDDEN 8 16 | 17 | #define BLACK 0 18 | #define RED 1 19 | #define GREEN 2 20 | #define YELLOW 3 21 | #define BLUE 4 22 | #define MAGENTA 5 23 | #define CYAN 6 24 | 25 | #define VERBOSE 0x01 26 | #define STORE 0x02 27 | #define CHECK 0x04 28 | #define REMOVE 0x10 29 | #define RECURSE 0x20 30 | #define OVERWRITE 0x40 31 | #define PRINT 0x80 32 | #define UPDATE 0x100 33 | #define DEBUG 0x200 34 | #define OMIT 0x400 35 | 36 | // For option -e OMIT 37 | #define MAXEXT 20 38 | 39 | 40 | typedef unsigned long long t_crc64; 41 | //typedef uint64_t t_crc64; 42 | 43 | struct s_crc64 44 | { 45 | t_crc64 crc; 46 | t_crc64 t; 47 | // time_t t; this is not constant size accross 32 and 64bit OSses, resulting in xattr errors when copying files 48 | }; 49 | 50 | t_crc64 CalculateCRC64(const char *filename); 51 | int processFile(const char *filename); 52 | int nftw_callback(const char *, const struct stat *, int, struct FTW *); 53 | int processCmdLine(const char *filename); 54 | uint64_t crc64(uint64_t crc, const unsigned char *s, uint64_t l); 55 | t_crc64 getCRC(const char *filename); 56 | int presentCRC64(const char *filename); 57 | int removeCRC(const char *filename); 58 | int bPutCRC(const char *filename, t_crc64 *crc, bool bError); 59 | t_crc64 getCRC(const char *filename); 60 | void textcolor(int attr, int fg, int bg); 61 | void printStatus(const char* filename, const char* status, int fg); 62 | int IsPresentCRC64(const char *file); 63 | int IsFreshCRC(const char *filename); 64 | 65 | #endif //define _CRCSUM_H 66 | -------------------------------------------------------------------------------- /src/crcsum.x: -------------------------------------------------------------------------------- 1 | [NAME] 2 | crcsum \- check crc sum 3 | [DESCRIPTION] 4 | .\" Add any additional description here 5 | -------------------------------------------------------------------------------- /src/crcsum_cli.c: -------------------------------------------------------------------------------- 1 | /* 2 | This program is free software: you can redistribute it and/or modify 3 | it under the terms of the GNU General Public License as published by 4 | the Free Software Foundation, version 3 of the License. 5 | 6 | This program is distributed in the hope that it will be useful, 7 | but WITHOUT ANY WARRANTY; without even the implied warranty of 8 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 9 | GNU General Public License for more details. 10 | 11 | You should have received a copy of the GNU General Public License 12 | along with this program. If not, see . 13 | 14 | This software is based on Checkit version 0.2.0 15 | Dennis Katsonis; E-Mail dennisk (at) netspace.net.au 16 | */ 17 | 18 | #include "config.h" 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | // Provides: 26 | // extern char *optarg; 27 | // extern int optind, opterr, optopt; 28 | 29 | #include 30 | #include "crcsum.h" 31 | 32 | void print_help(void); 33 | 34 | extern int flags; 35 | extern int failed; 36 | extern int processed; 37 | extern int ext_counter; 38 | extern char arr_ext[MAXEXT][5]; 39 | 40 | 41 | void print_help(void) 42 | { 43 | printf("CRCSUM: A file checksum utility.\tVersion : %s\n",VERSION); 44 | puts("(C) Hans IJntema (2023)"); 45 | puts(""); 46 | puts("CRCSUM stores a CRC checksum and file mtime as an extended attribute."); 47 | puts("CRCSUM checks stored CRC checksum against actual CRC checksum"); 48 | puts("CRCSUM allows for CRC updates, only when mtime has changed"); 49 | puts("ZERO size files will not be checksum-ed."); 50 | puts("Directory & File SYMLINKS will not be followed."); 51 | puts("NOTE: Some programs do change file content (even w/o saving),"); 52 | puts("while mtime is not update. Example, some Microsoft Excel versions"); 53 | puts("This will result in false positves when checking file against CRC."); 54 | puts(""); 55 | puts("Options :"); 56 | puts(" -a Calculate and Add checksum (no overwrite)"); 57 | puts(" -u As -a, and Update stale checksum"); 58 | puts(" -f As -a, Force overwrite existing checksum"); 59 | puts(" -c Check file against stored checksum; stale CRC's are omitted"); 60 | puts(" -e Assumes -c; omit extension; one extension per option; eg -c -e xls -e xlt"); 61 | puts(" -p Print CRC64 checksum; stale CRC's are omitted; Add -d to print stale and missing CRC's"); 62 | puts(" -v Verbose. Print more information"); 63 | puts(" -x Remove stored CRC64 checksum"); 64 | puts(" -r Recurse through directories"); 65 | puts(" -d Print Debug info. Implies -v"); 66 | puts(""); 67 | printf("Report errors and requests at %s\n\n", PACKAGE_BUGREPORT); 68 | } 69 | 70 | 71 | int main(int argc, char *argv[]) 72 | { 73 | int optch = 0; 74 | extern char *optarg; 75 | 76 | // get option characters (returns -1 if all are retrieved) 77 | while (( optch = getopt(argc, argv,"ahe:ufcpvxrd") ) != -1) 78 | { 79 | switch (optch) 80 | { 81 | case 'h' : 82 | print_help(); 83 | return false; 84 | break; 85 | 86 | case 'a' : 87 | flags |= STORE; 88 | break; 89 | 90 | case 'c' : 91 | flags |= CHECK; 92 | break; 93 | 94 | case 'e' : 95 | flags |= OMIT; 96 | flags |= CHECK; 97 | if (ext_counter < MAXEXT) 98 | { 99 | strcpy(arr_ext[ext_counter++], optarg); 100 | } 101 | break; 102 | 103 | case 'v' : 104 | flags |= VERBOSE; 105 | break; 106 | 107 | case 'x' : 108 | flags |= REMOVE; 109 | break; 110 | 111 | case 'u' : 112 | flags |= UPDATE; 113 | break; 114 | 115 | case 'f' : 116 | flags |= OVERWRITE; 117 | break; 118 | 119 | case 'r' : 120 | flags |= RECURSE; 121 | break; 122 | 123 | case 'p' : 124 | flags |= PRINT; 125 | break; 126 | 127 | case 'd' : 128 | flags |= VERBOSE; 129 | flags |= DEBUG; 130 | break; 131 | 132 | case '?' : 133 | puts("Unknown option."); 134 | puts(""); 135 | print_help(); 136 | break; 137 | } //switch 138 | } //while 139 | 140 | 141 | /* for (int i = 0; i < ext_counter; i++) 142 | { 143 | printf("arg=%s\n", arr_ext[i]); 144 | }*/ 145 | 146 | 147 | // no arguments are passed 148 | if (argc <=1) 149 | { 150 | print_help(); 151 | return(0); 152 | } 153 | /* Check for conflicting options */ 154 | if (((flags & CHECK) && (flags & STORE)) || ((flags & CHECK) && (flags & OVERWRITE)) || ((flags & CHECK) && (flags & UPDATE)) ) 155 | { 156 | puts("Cannot store and check CRC at same time."); 157 | return EX_USAGE; 158 | } 159 | 160 | if ((flags & STORE) && (flags & OVERWRITE) && (flags & UPDATE)) 161 | { 162 | puts("Cannot store/update and refresh at same time."); 163 | return EX_USAGE; 164 | } 165 | 166 | if ((flags & STORE) && (flags & REMOVE)) 167 | { 168 | puts("Cannot remove and store CRC at same time."); 169 | return EX_USAGE; 170 | } 171 | if ((flags & CHECK) && (flags & REMOVE)) 172 | { 173 | puts("Cannot remove and check CRC at same time."); 174 | return EX_USAGE; 175 | } 176 | 177 | //optind is the index of the next element to be processed in argv 178 | optch = optind; 179 | 180 | if (optch < argc) 181 | { 182 | do 183 | { 184 | // printf("ARGUMENT = %s\n", argv[optch]); 185 | // processFile(argv[optch]); 186 | processCmdLine(argv[optch]); 187 | } 188 | while ( ++optch < argc); 189 | } 190 | 191 | printf("%d file(s) processed.\n", processed); 192 | if (failed && processed) 193 | { 194 | printf("%d file(s) failed.\n", failed); 195 | return EXIT_FAILURE; 196 | } /* Return the number of failed checks if any errors. */ 197 | else if ( processed && (flags & CHECK) ) 198 | { 199 | printf("All file(s) OK.\n"); 200 | } 201 | return EXIT_SUCCESS; 202 | } 203 | 204 | 205 | -------------------------------------------------------------------------------- /src/cu-progs.m4.patch: -------------------------------------------------------------------------------- 1 | --- /home/ijntema/programming/securecopy/core-utils-based/V9.3.0-beta/coreutils-9.3/m4/cu-progs.m4.org 2023-04-29 19:28:37.724014763 +0200 2 | +++ /home/ijntema/programming/securecopy/core-utils-based/V9.3.0-beta/coreutils-9.3/m4/cu-progs.m4 2023-04-29 19:28:37.724014763 +0200 3 | @@ -87,20 +87,23 @@ 4 | gl_ADD_PROG([optional_bin_progs], [tsort]) 5 | gl_ADD_PROG([optional_bin_progs], [tty]) 6 | gl_ADD_PROG([optional_bin_progs], [uname]) 7 | gl_ADD_PROG([optional_bin_progs], [unexpand]) 8 | gl_ADD_PROG([optional_bin_progs], [uniq]) 9 | gl_ADD_PROG([optional_bin_progs], [unlink]) 10 | gl_ADD_PROG([optional_bin_progs], [vdir]) 11 | gl_ADD_PROG([optional_bin_progs], [wc]) 12 | gl_ADD_PROG([optional_bin_progs], [whoami]) 13 | gl_ADD_PROG([optional_bin_progs], [yes]) 14 | +gl_ADD_PROG([optional_bin_progs], [crccp]) 15 | +gl_ADD_PROG([optional_bin_progs], [crcsum]) 16 | +gl_ADD_PROG([optional_bin_progs], [crcmv]) 17 | no_install_progs_default='arch coreutils hostname' 18 | # Given the name of a variable containing a space-separated 19 | # list of install-by-default programs and the actual list of 20 | # do-not-install-by-default programs, modify the former variable 21 | # to reflect any "do-install" and "don't-install" requests. 22 | # That is, add any program specified via --enable-install-program, 23 | # and remove any program specified via --enable-no-install-program. 24 | # Note how the second argument below is a literal, with "," 25 | # separators. That is required due to the way the macro works, 26 | # and since the corresponding ./configure option argument is 27 | -------------------------------------------------------------------------------- /src/cu-progs.mk.patch: -------------------------------------------------------------------------------- 1 | --- /home/ijntema/programming/securecopy/core-utils-based/V9.3.0-beta/coreutils-9.3/src/cu-progs.mk.org 2023-04-29 19:28:37.712015139 +0200 2 | +++ /home/ijntema/programming/securecopy/core-utils-based/V9.3.0-beta/coreutils-9.3/src/cu-progs.mk 2023-04-29 19:28:37.720014888 +0200 3 | @@ -105,10 +105,15 @@ 4 | default__progs += src/tsort 5 | default__progs += src/tty 6 | default__progs += src/uname 7 | default__progs += src/unexpand 8 | default__progs += src/uniq 9 | default__progs += src/unlink 10 | default__progs += src/vdir 11 | default__progs += src/wc 12 | default__progs += src/whoami 13 | default__progs += src/yes 14 | +# HIJN 15 | +default__progs += src/crccp 16 | +default__progs += src/crcsum 17 | +default__progs += src/crcmv 18 | +# END HIJN 19 | \ No newline at end of file 20 | -------------------------------------------------------------------------------- /src/local.mk.patch: -------------------------------------------------------------------------------- 1 | --- /home/ijntema/programming/securecopy/core-utils-based/V9.3.0-beta/coreutils-9.3/src/local.mk.org 2023-04-29 19:28:37.712015139 +0200 2 | +++ /home/ijntema/programming/securecopy/core-utils-based/V9.3.0-beta/coreutils-9.3/src/local.mk 2023-04-29 19:28:37.724014763 +0200 3 | @@ -212,27 +212,35 @@ 4 | src_wc_LDADD = $(LDADD) 5 | src_who_LDADD = $(LDADD) 6 | src_whoami_LDADD = $(LDADD) 7 | src_yes_LDADD = $(LDADD) 8 | 9 | # Synonyms. Recall that Automake transliterates '[' and '/' to '_'. 10 | src___LDADD = $(src_test_LDADD) 11 | src_dir_LDADD = $(src_ls_LDADD) 12 | src_vdir_LDADD = $(src_ls_LDADD) 13 | 14 | +src_crccp_LDADD = $(LDADD) 15 | +src_crcmv_LDADD = $(LDADD) 16 | +src_crcsum_LDADD = $(LDADD) 17 | + 18 | src_cp_LDADD += $(copy_ldadd) 19 | src_ginstall_LDADD += $(copy_ldadd) 20 | src_mv_LDADD += $(copy_ldadd) 21 | 22 | src_mv_LDADD += $(remove_ldadd) 23 | src_rm_LDADD += $(remove_ldadd) 24 | 25 | +src_crccp_LDADD += $(copy_ldadd) 26 | +src_crcmv_LDADD += $(copy_ldadd) 27 | +src_crcmv_LDADD += $(remove_ldadd) 28 | + 29 | # for eaccess, euidaccess 30 | copy_ldadd += $(EUIDACCESS_LIBGEN) 31 | remove_ldadd += $(EUIDACCESS_LIBGEN) 32 | src_sort_LDADD += $(EUIDACCESS_LIBGEN) 33 | src_test_LDADD += $(EUIDACCESS_LIBGEN) 34 | 35 | # for selinux use 36 | copy_ldadd += $(LIB_SELINUX) 37 | src_chcon_LDADD += $(LIB_SELINUX) 38 | src_ginstall_LDADD += $(LIB_SELINUX) 39 | @@ -331,20 +339,22 @@ 40 | `sed -n '/.*COPYRIGHT_YEAR = \([0-9][0-9][0-9][0-9]\) };/s//\1/p' \ 41 | $(top_srcdir)/lib/version-etc.c` 42 | 43 | selinux_sources = \ 44 | src/selinux.c \ 45 | src/selinux.h 46 | 47 | copy_sources = \ 48 | src/copy.c \ 49 | src/cp-hash.c \ 50 | + src/crcsum.c \ 51 | + src/crc64.c \ 52 | src/force-link.c \ 53 | src/force-link.h 54 | 55 | # Use 'ginstall' in the definition of PROGRAMS and in dependencies to avoid 56 | # confusion with the 'install' target. The install rule transforms 'ginstall' 57 | # to install before applying any user-specified name transformations. 58 | 59 | # Don't apply prefix transformations to libstdbuf shared lib 60 | # as that's not generally needed, and we need to reference the 61 | # name directly in LD_PRELOAD etc. In general it's surprising 62 | @@ -431,20 +441,24 @@ 63 | src_libcksum_pclmul_a_CFLAGS = -mavx -mpclmul $(AM_CFLAGS) 64 | endif 65 | 66 | src_base64_SOURCES = src/basenc.c 67 | src_base64_CPPFLAGS = -DBASE_TYPE=64 $(AM_CPPFLAGS) 68 | src_base32_SOURCES = src/basenc.c 69 | src_base32_CPPFLAGS = -DBASE_TYPE=32 $(AM_CPPFLAGS) 70 | src_basenc_SOURCES = src/basenc.c 71 | src_basenc_CPPFLAGS = -DBASE_TYPE=42 $(AM_CPPFLAGS) 72 | 73 | +src_crccp_SOURCES = src/crccp.c $(copy_sources) $(selinux_sources) 74 | +src_crcmv_SOURCES = src/crcmv.c src/remove.c $(copy_sources) $(selinux_sources) 75 | +src_crcsum_SOURCES = src/crcsum_cli.c src/crcsum.c src/crc64.c 76 | + 77 | src_expand_SOURCES = src/expand.c src/expand-common.c 78 | src_unexpand_SOURCES = src/unexpand.c src/expand-common.c 79 | 80 | src_wc_SOURCES = src/wc.c 81 | if USE_AVX2_WC_LINECOUNT 82 | noinst_LIBRARIES += src/libwc_avx2.a 83 | src_libwc_avx2_a_SOURCES = src/wc_avx2.c 84 | wc_avx2_ldadd = src/libwc_avx2.a 85 | src_wc_LDADD += $(wc_avx2_ldadd) 86 | src_libwc_avx2_a_CFLAGS = -mavx2 $(AM_CFLAGS) 87 | -------------------------------------------------------------------------------- /test/test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | CRCPATH="../bin" 4 | CHECKSUM="BE2C65AC2D090191" 5 | #CHECKSUM="BE2C65AC2D090192" 6 | TESTFILE="fileundertest.txt" 7 | CPFILE="copyfile.txt" 8 | 9 | 10 | echo "" 11 | echo "" 12 | echo "## Basic test for crcsum and crccp ##" 13 | echo "" 14 | 15 | rm -f ${TESTFILE} ${CPFILE} 16 | 17 | echo "TEST: Add CRC to file and compare with expected pre-calculated CRC" 18 | echo "Create test file without checksum..." 19 | dd if=<(yes foo) of=${TESTFILE} bs=1024 count=200 > /dev/null 2>&1 20 | 21 | echo "Add checksum..." 22 | ${CRCPATH}/crcsum -a ${TESTFILE} > /dev/null 2>&1 23 | echo "Display checksum..." 24 | OUTPUT=$(${CRCPATH}/crcsum -p ${TESTFILE}) > /dev/null 2>&1 25 | 26 | # https://www.regextester.com/107384 27 | # Extract calculated checksum 28 | [[ ${OUTPUT} =~ (\[ )(.*)(.* \]) ]] 29 | CHECKSUM_CALCULATED=(${BASH_REMATCH[2]}) 30 | 31 | echo "Test..." 32 | if [[ "$OUTPUT" =~ .*"$CHECKSUM".* ]]; then 33 | echo "SUCCESS: Checksum calculated = ${CHECKSUM_CALCULATED}; Checksum expected = ${CHECKSUM}" 34 | else 35 | echo "FAILURE: Checksum calculated = ${CHECKSUM_CALCULATED}; Checksum expected = ${CHECKSUM}" 36 | exit 1 37 | fi 38 | 39 | ################################################################################################## 40 | ################################################################################################## 41 | rm ${TESTFILE} 42 | echo "" 43 | echo "TEST: Copy file (crccp -cx) without source CRC and compare with expected pre-calculated CRC" 44 | echo "Create test file without checksum..." 45 | dd if=<(yes foo) of=${TESTFILE} bs=1024 count=200 > /dev/null 2>&1 46 | 47 | echo "Copy file and test checksum of destination..." 48 | ${CRCPATH}/crccp -cx ${TESTFILE} ${CPFILE} > /dev/null 2>&1 49 | 50 | echo "Display checksum..." 51 | OUTPUT=$(${CRCPATH}/crcsum -p ${CPFILE}) 52 | 53 | # Extract calculated checksum 54 | [[ ${OUTPUT} =~ (\[ )(.*)(.* \]) ]] 55 | CHECKSUM_CALCULATED=(${BASH_REMATCH[2]}) 56 | 57 | echo "Test..." 58 | if [[ "$OUTPUT" =~ .*"$CHECKSUM".* ]]; then 59 | echo "SUCCESS: Checksum calculated = ${CHECKSUM_CALCULATED}; Checksum expected = ${CHECKSUM}" 60 | else 61 | echo "FAILURE: Checksum calculated = ${CHECKSUM_CALCULATED}; Checksum expected = ${CHECKSUM}" 62 | exit 1 63 | fi 64 | 65 | ################################################################################################## 66 | ################################################################################################## 67 | echo "" 68 | echo "TEST: File corruption test..." 69 | # Add checksum to testfile 70 | ${CRCPATH}/crcsum -a ${TESTFILE} > /dev/null 2>&1 71 | OUTPUT=$(${CRCPATH}/crcsum -p ${TESTFILE}) 72 | 73 | echo "Simulate that ${TESTFILE} got corrupted..." 74 | # Change content of file but restore timestamp 75 | touch -r ${TESTFILE} time.stamp > /dev/null 2>&1 76 | 77 | # add 1 character 78 | echo "a" >> ${TESTFILE} 79 | touch -r time.stamp ${TESTFILE} > /dev/null 2>&1 80 | rm time.stamp > /dev/null 2>&1 81 | 82 | OUTPUT=$(${CRCPATH}/crcsum -c -v ${TESTFILE}) 83 | 84 | # Extract calculated checksum 85 | #regexp="\[[[:space:]]+(.*)[[:space:]]*\].*" 86 | regexp=".*(FAILED|OK).*" 87 | [[ ${OUTPUT} =~ ${regexp} ]] 88 | REMATCH=(${BASH_REMATCH[1]}) 89 | 90 | if [[ "$REMATCH" =~ .*"FAILED".* ]]; then 91 | echo "Success: corrupted file detected" 92 | else 93 | echo "Failure: corupted file not detected" 94 | exit 1 95 | fi 96 | 97 | rm -f ${TESTFILE} ${CPFILE} 98 | --------------------------------------------------------------------------------