experimental old/new eatmydata support switch
[shellsnippets/shellsnippets.git] / mksh / gened2k
1 #!/bin/mksh
2 # $MirOS: contrib/code/Snippets/gened2k,v 1.4 2008/05/03 01:09:23 tg Exp $
3 #-
4 # Copyright (c) 2004
5 #       Thorsten "mirabilos" Glaser <tg@mirbsd.de>
6 #
7 # Provided that these terms and disclaimer and all copyright notices
8 # are retained or reproduced in an accompanying document, permission
9 # is granted to deal in this work without restriction, including un-
10 # limited rights to use, publicly perform, distribute, sell, modify,
11 # merge, give away, or sublicence.
12 #
13 # This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to
14 # the utmost extent permitted by applicable law, neither express nor
15 # implied; without malicious intent or gross negligence. In no event
16 # may a licensor, author or contributor be held liable for indirect,
17 # direct, other damage, loss, or other issues arising in any way out
18 # of dealing in the work, even if advised of the possibility of such
19 # damage or existence of a defect, except proven that it results out
20 # of said person's immediate fault when using the work as intended.
21 #-
22 # This script produces an "ed2k" type URI for a given existing file.
23 # It is by no means normative, but developed by reverse engineering.
24 #
25 # Structure of an "ed2k" type URI:
26 #  ed2k://|file|<filename>|<size>|<hash>|[/]
27 # where the trailing slash is optional, "filename" is posix, except
28 # that no pipe sign can occur, size in octets (decimal) and hash...
29 # well, that's the hard part below. It's hexadecimal lowercase.
30
31
32 # Functions
33
34 getsize() {
35         typeset o
36
37         set -A o -- $(/bin/ls -l "$1")
38         print ${o[4]}
39 }
40
41 constructuri() {
42         typeset name="${1##*/}"
43         typeset -i size=$2
44         # I can't use integer here because it's limited to 32 bit signed :(
45         typeset -l hash=$3
46
47         # This equals a s/\|//g regexp...
48         while [[ $name = *\|* ]]; do
49                 name="${name##*\|}${name%\|*}"
50         done
51
52         # Now put it
53         print -r "ed2k://|file|${name}|${size}|${hash}|/"
54 }
55
56 getmd4() {
57         typeset o
58         typeset h=""
59
60         if [[ -z "$1" ]]; then
61                 h=$(cksum -a md4)
62         else
63                 for i in "$@"; do
64                         set -A o -- $(cksum -a md4 "$i")
65                         h="${h}${o[3]}"
66                 done
67         fi
68         print -n $h
69 }
70
71 gethash() {
72         typeset fn="$1"
73         typeset -i sz=$(getsize "$fn")
74         typeset hash=""
75         typeset fullhash=""
76         typeset -i nr
77
78         if ((sz == 0)); then
79                 hash=0
80         elif ((sz < 9728000)); then
81                 hash=$(getmd4 "$fn")
82         else
83                 let nr=0
84                 while (((nr * 9728000) < sz)); do
85                         hash=$(dd if="$fn" bs=9728000 count=1 skip=$nr \
86                             2>/dev/null | getmd4)
87                         let nr+=1
88                         fullhash="$fullhash$hash"
89                 done
90                 hash=$(printf "$(print $fullhash \
91                     | sed -e 's/\(..\)/\\x\1/g')" | getmd4)
92         fi
93         print $hash
94 }
95
96 # Main Programme
97
98 if [[ $# -lt 1 || $1 == -@(h|H|?) ]]; then
99         print "Usage:"
100         print " $0 [-h | file ...]"
101         exit 1
102 fi
103
104 for fn in "$@"; do
105         test -r "$fn" && continue
106         print -r "Error: '$fn' not readable."
107         exit 1
108 done
109
110 for fn in "$@"; do
111         size=$(getsize "$fn")
112         hash=$(gethash "$fn")
113         constructuri "$fn" $size $hash
114 done
115
116 exit 0