]> pd.if.org Git - scripts/blob - evensplit
added program to find consecutive partitions
[scripts] / evensplit
1 #!/bin/sh
2
3 # public domain by Nathan Wagner <nw@hydaspes.if.org>
4
5 # Assume N bytes total.
6 # Assume L is the lowest number of files allowable.
7 # H is the highest number of files allowable.
8 # F is the actual number of files used
9 # B is the minimum bytes per file
10 # R is the remaining bytes if all files are of size B
11 # K is the maximum number of files allowed to be one byte larger than the
12 # minimum, K < F
13
14 # So, you need to determine if there is some L <= F <= H such that R <= K.
15
16 # For a given candidate F:
17 # B = floor(N / F)
18 # R = N % B
19 # if R <= K then the candidate F is allowable, F files will be used,
20 # R of them will be of size B+1 and F-R of them will be of size B.
21
22 N=
23 L=
24 H=
25 K=
26 ECHO=
27 VERBOSE=0
28
29 set -e
30
31 while getopts l:h:k:n:ev flag ; do
32         case $flag in
33                 l) L="$OPTARG" ;;
34                 h) H="$OPTARG" ;;
35                 k) K="$OPTARG" ;;
36                 n) N="$OPTARG" ;;
37                 e) ECHO=echo ;;
38                 v) VERBOSE=1 ;;
39                 ?) printf "Usage: evensplit [-lhknev] <file>\n" 1>&2; exit 2 ;;
40         esac
41 done
42 shift $(($OPTIND - 1))
43
44 INPUT=$1
45
46 N=$(stat -c '%s' $INPUT)
47 : ${L:=$((N/65536))} # default to at least 65536 bytes per split
48 if [ $L -lt 1 ]; then L=1; fi
49
50 : ${H:=$N} # use one byte per file if needed
51 if [ $H -lt $L ]; then H=$L; fi
52
53 : ${K:=$((H-1))} # by default K can by any number of the files
54
55 status=1
56
57 if [ $VERBOSE -ne 0 ]; then
58         echo '#' F files: $L '<= F <=' $H, at most $K files one byte larger 1>&2
59 fi
60
61 for F in $(seq $L $H); do
62         B=$(($N / $F))
63         R=$(($N % $B))
64         if [ $R -le $K ]; then
65                 if [ $VERBOSE -ne 0 ]; then
66                         printf "# Usable: %u files, size %u" $((F-R)) $B 1>&2
67                         if [ $R -gt 0 ]; then
68                                 printf ", %u size %u", $R $((B+1)) 1>&2
69                         fi
70                         printf "\n" 1>&2
71                 fi
72                 status=0;
73                 break;
74         fi
75 done
76 if [ $? -ne 0 ]; then
77         echo "no usable splits found" 1>&2;
78         exit $status
79 fi
80
81 DD="dd if=$INPUT count=1"
82
83 # ok, at this point we want F-R files of size $B
84 for ext in $(seq -w 1 $F); do
85         x=$(echo $ext | sed -e 's/^0\+//')
86         if [ $x -gt $((F-R)) ]; then
87         ${ECHO} $DD of=${INPUT}.$ext bs=$((B+1)) skip=$(((F-R) * B)) iflag=skip_bytes
88         else
89         ${ECHO} $DD of=${INPUT}.$ext bs=$B skip=$((x-1))
90         fi
91 done