@@ -161,6 +161,34 @@ derive_context_config_group() {
161
161
fi
162
162
}
163
163
164
+ # Internal function that returns a list of filenames for encrypted files in the
165
+ # repo, where the filenames are verbatim and not quoted in any way even if they
166
+ # contain unusual characters like double-quotes, backslash and control
167
+ # characters. We must avoid quoting of filenames to support names containing
168
+ # double quotes. #173
169
+ _list_encrypted_files () {
170
+ local strict_context=${1:- }
171
+
172
+ IFS=$' \n '
173
+ # List files with -z option to disable quoting of filenames, then
174
+ # immediately convert NUL-delimited filenames to be newline-delimited to be
175
+ # compatibility with bash variables
176
+ for file in $( git ls-files -z | tr ' \0' ' \n' ) ; do
177
+ # Check for the suffix ': filter: crypt' that identifies encrypted file
178
+ local check
179
+ check=$( git check-attr filter " $file " 2> /dev/null)
180
+
181
+ # Only output names of encrypted files matching the context, either
182
+ # strictly (if $1 = "true") or loosely (if $1 is false or unset)
183
+ if [[ " $strict_context " == " true" ]] &&
184
+ [[ " $check " == * " : filter: crypt${CONTEXT_CRYPT_SUFFIX:- } " ]]; then
185
+ echo " $file "
186
+ elif [[ " $check " == * " : filter: crypt${CONTEXT_CRYPT_SUFFIX:- } " * ]]; then
187
+ echo " $file "
188
+ fi
189
+ done
190
+ }
191
+
164
192
# Detect OpenSSL major version 3 or later which requires a compatibility
165
193
# work-around to include the prefix 'Salted__' and salt value when encrypting.
166
194
#
@@ -325,7 +353,7 @@ git_pre_commit() {
325
353
tmp=$( mktemp)
326
354
IFS=$' \n '
327
355
slow_mode_if_failed () {
328
- for secret_file in $( git -c core.quotePath=false ls-files | git -c core.quotePath=false check-attr --stdin filter | awk ' BEGIN { FS = ":" }; /crypt$/{ print $1 } ' ) ; do
356
+ for secret_file in $( _list_encrypted_files ) ; do
329
357
# Skip symlinks, they contain the linked target file path not plaintext
330
358
if [[ -L $secret_file ]]; then
331
359
continue
@@ -373,7 +401,7 @@ git_pre_commit() {
373
401
if [[ " ${BASH_VERSINFO[0]} " -ge 4 ]] && [[ " ${BASH_VERSINFO[1]} " -ge 4 ]]; then
374
402
num_procs=$( nproc)
375
403
num_jobs=" \j"
376
- for secret_file in $( git -c core.quotePath=false ls-files | git -c core.quotePath=false check-attr --stdin filter | awk ' BEGIN { FS = ":" }; /crypt$/{ print $1 } ' ) ; do
404
+ for secret_file in $( _list_encrypted_files ) ; do
377
405
while (( ${num_jobs@ P} >= num_procs)) ; do
378
406
wait -n
379
407
done
@@ -679,15 +707,15 @@ save_configuration() {
679
707
git config merge.crypt.name ' Merge transcrypt secret files'
680
708
681
709
# add git alias for listing ALL encrypted files regardless of context
682
- git config alias.ls-crypt " !git -c core.quotePath=false ls-files | git -c core.quotePath=false check-attr --stdin filter | awk 'BEGIN { FS = \" : \" }; / crypt/{ print \$ 1 }' "
710
+ git config alias.ls-crypt " !$transcrypt_path --list "
683
711
684
712
# add a git alias for listing encrypted files in specific context, including 'default'
685
713
if [[ " $CONTEXT " = ' default' ]]; then
686
714
# List files with gitattribute 'filter=crypt'
687
- git config alias.ls-crypt-default " !git -c core.quotePath=false ls-files | git -c core.quotePath=false check-attr --stdin filter | awk 'BEGIN { FS = \" : \" }; / crypt$/{ print \$ 1 }' "
715
+ git config alias.ls-crypt-default " !$transcrypt_path --list "
688
716
else
689
717
# List files with gitattribute 'filter=crypt-<CONTEXT>'
690
- git config " alias.ls-crypt-${CONTEXT} " " !git -c core.quotePath=false ls-files | git -c core.quotePath=false check-attr --stdin filter | awk 'BEGIN { FS = \" : \" }; / crypt- ${CONTEXT} $/{ print \$ 1 }' "
718
+ git config " alias.ls-crypt-${CONTEXT} " " !$transcrypt_path --context= ${CONTEXT} --list "
691
719
fi
692
720
}
693
721
@@ -832,6 +860,15 @@ uninstall_transcrypt() {
832
860
remove_cached_plaintext
833
861
fi
834
862
863
+ # touch all encrypted files to prevent stale stat info
864
+ local encrypted_files
865
+ encrypted_files=$( git ls-crypt)
866
+ if [[ $encrypted_files ]] && [[ $IS_BARE == ' false' ]]; then
867
+ cd " $REPO " > /dev/null || die 1 ' could not change into the "%s" directory' " $REPO "
868
+ # shellcheck disable=SC2086
869
+ touch $encrypted_files
870
+ fi
871
+
835
872
# remove helper scripts
836
873
# Keep obsolete clean,smudge,textconv,merge refs here to remove them on upgrade
837
874
for script in {transcrypt,clean,smudge,textconv,merge}; do
@@ -853,15 +890,6 @@ uninstall_transcrypt() {
853
890
fi
854
891
[[ -f " $pre_commit_hook_installed " ]] && rm " $pre_commit_hook_installed "
855
892
856
- # touch all encrypted files to prevent stale stat info
857
- local encrypted_files
858
- encrypted_files=$( git ls-crypt)
859
- if [[ $encrypted_files ]] && [[ $IS_BARE == ' false' ]]; then
860
- cd " $REPO " > /dev/null || die 1 ' could not change into the "%s" directory' " $REPO "
861
- # shellcheck disable=SC2086
862
- touch $encrypted_files
863
- fi
864
-
865
893
# remove context settings: cipher & password config, ls-crypt alias variant,
866
894
# crypt filter/diff/merge attributes. We do it here instead of `clean_gitconfig`
867
895
# to avoid interfering with flushing of credentials
@@ -1005,7 +1033,7 @@ upgrade_transcrypt() {
1005
1033
list_files () {
1006
1034
if [[ $IS_BARE == ' false' ]]; then
1007
1035
cd " $REPO " > /dev/null || die 1 ' could not change into the "%s" directory' " $REPO "
1008
- git -c core.quotePath=false ls-files | git -c core.quotePath=false check-attr --stdin filter | awk ' BEGIN { FS = ":" }; /crypt/{ print $1 } '
1036
+ _list_encrypted_files true
1009
1037
fi
1010
1038
}
1011
1039
@@ -1014,13 +1042,12 @@ show_raw_file() {
1014
1042
if [[ -f $show_file ]]; then
1015
1043
# ensure the file is currently being tracked
1016
1044
local escaped_file=${show_file// \/ / \\\/ }
1017
- if git -c core.quotePath=false ls-files --others -- " $show_file " | awk " /${escaped_file} /{ exit 1 }" ; then
1018
- file_paths=$( git -c core.quotePath=false ls-tree --name-only --full-name HEAD " $show_file " )
1019
- else
1045
+ file_paths=$( _list_encrypted_files | grep " $escaped_file " )
1046
+ if [[ -z " $file_paths " ]]; then
1020
1047
die 1 ' the file "%s" is not currently being tracked by git' " $show_file "
1021
1048
fi
1022
1049
elif [[ $show_file == ' *' ]]; then
1023
- file_paths=$( git ls-crypt )
1050
+ file_paths=$( _list_encrypted_files )
1024
1051
else
1025
1052
die 1 ' the file "%s" does not exist' " $show_file "
1026
1053
fi
0 commit comments