-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathcp-l
99 lines (87 loc) · 2.5 KB
/
cp-l
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
#!/bin/bash
# cp-l: Determines if we are doing the cp job in the same fs.
# If so, add '-l' to cp.
# Arguments from cp (GNU coreutils) 8.23, therefore:
# @license GPL-3.0+
shopt -s extglob
declare -A mount_state
# initialization: mtab
while IFS=' ' read -r fs mpoint type opts dump pass; do
# hey printf eat the escapes
mpoint="$(printf %b- "${mpoint%/}")"
mpoint="${mpoint%-}"
# hey wut is dis
# [[ $fs == *fs ]] || fs="$(readlink -e "$fs")"
mount_state["$mpoint"]="${fs%/} $type $opts $dump $pass"
done < /etc/mtab
# argument processing
gopt="$(getopt -o abdfiHlLnPpRrsStTuvxZ \
--long archive,attributes-only,backup:,copy-contents,force,interactive,link,dereference,no-clobber,no-dereference,\
preserve:,no-preserve:,parents,recursive,reflink:,remove-destination,sparse:,strip-trailing-slashes,\
symbolic-link,suffix:,target-directory:,no-target-directory,update,verbose,one-file-system,context:,help,version \
-n "$0" -- "$@")" || exit $?
eval gopt="($gopt)"
gargc=${#gopt[@]}
target_is_dir=0
for ((f=0; f<gargc; f++)); do
case "${gopt[f]}" in
--) break;;
-t|--target-directory) # target dir
target_is_dir=1
target="${gopt[f+1]}";; # only consider last one
--target-directory=*) # ditto
target_is_dir=1
target="${gopt[f]#--target-directory=}";;
esac
done
srcf=("${gopt[@]:f+1}")
gopt=("${gopt[@]:0:f}")
if [[ $target == '' ]]; then
target=${srcf[-1]}
unset srcf[-1]
fi
fs_name_maybe(){
fs=$1
fs=$(readlink -m "$f"; echo x) o=${ofx}
fs=${f/#'//'+(/)/'/'} # normalize abs path
if [[ $fs == //* ]]; then # don't do the stupid thing on //
fs=//
return
fi
local components=() IFS=/
read -a components <<< "$fs"
while ((${#components[@]})); do
fs="${components[*]}"
if [[ "${mount_state[$fs]}" != '' ]]; then
return
fi
unset components[-1]
done
false
}
files_link=()
files_norm=()
fs_name_maybe "$target" &&
target_fs=$fs && # if we fail target_fs, then it's pointless to do the check.
for f in "${srcf[@]}"; do
if fs_name_maybe "$f"; then
files_link+=("$f")
else
files_norm+=("$f")
fi
done
# moral dilemma: should we try the linked cp first, or the normal cp first?
# go for the linked one.
if ((target_is_dir)); then
gopt+=(--target-directory="$target")
else
files_link+=("$target")
files_norm+=("$target")
fi
# note: when target_is_dir=true; we cmp w/ 0; otherwise 1.
if ((${#files_link[@]} > (!target_is_dir) )); then
cp "${gopt[@]}" --link -- "${files_link[@]}"
fi &&
if ((${#files_norm[@]} > (!target_is_dir) )); then
cp "${gopt[@]}" -- "${files_norm[@]}"
fi