summaryrefslogtreecommitdiffstats
path: root/tests/stddirs.sh
blob: acc23dc5e5972a89397877c911b211dbe02e6fec (plain)
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
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
#!/hint/bash

# Copyright © Tavian Barnes <tavianator@tavianator.com>
# SPDX-License-Identifier: 0BSD

## Standard directory trees for tests

# Creates a simple file+directory structure for tests
make_basic() {
    "$XTOUCH" -p "$1"/{a,b,c/d,e/f,g/h/,i/}
    "$XTOUCH" -p "$1"/{j/foo,k/foo/bar,l/foo/bar/baz}
    echo baz >"$1/l/foo/bar/baz"
}

# Creates a file+directory structure with various permissions for tests
make_perms() {
    "$XTOUCH" -p -M000 "$1/0"
    "$XTOUCH" -p -M444 "$1/r"
    "$XTOUCH" -p -M222 "$1/w"
    "$XTOUCH" -p -M644 "$1/rw"
    "$XTOUCH" -p -M555 "$1/rx"
    "$XTOUCH" -p -M311 "$1/wx"
    "$XTOUCH" -p -M755 "$1/rwx"
}

# Creates a file+directory structure with various symbolic and hard links
make_links() {
    "$XTOUCH" -p "$1/file"
    ln -s file "$1/symlink"
    ln "$1/file" "$1/hardlink"
    ln -s nowhere "$1/broken"
    ln -s symlink/file "$1/notdir"
    "$XTOUCH" -p "$1/deeply/nested"/{dir/,file}
    ln -s file "$1/deeply/nested/link"
    ln -s nowhere "$1/deeply/nested/broken"
    ln -s deeply/nested "$1/skip"
}

# Creates a file+directory structure with symbolic link loops
make_loops() {
    "$XTOUCH" -p "$1/file"
    ln -s file "$1/symlink"
    ln -s nowhere "$1/broken"
    ln -s symlink/file "$1/notdir"
    ln -s loop "$1/loop"
    mkdir -p "$1/deeply/nested/dir"
    ln -s ../../deeply "$1/deeply/nested/loop"
    ln -s deeply/nested/loop/nested "$1/skip"
}

# Creates a file+directory structure with varying timestamps
make_times() {
    "$XTOUCH" -p -t "1991-12-14 00:00" "$1/a"
    "$XTOUCH" -p -t "1991-12-14 00:01" "$1/b"
    "$XTOUCH" -p -t "1991-12-14 00:02" "$1/c"
    ln -s a "$1/l"
    "$XTOUCH" -p -h -t "1991-12-14 00:03" "$1/l"
    "$XTOUCH" -p -t "1991-12-14 00:04" "$1"
}

# Creates a file+directory structure with various weird file/directory names
make_weirdnames() {
    "$XTOUCH" -p "$1/-/a"
    "$XTOUCH" -p "$1/(/b"
    "$XTOUCH" -p "$1/(-/c"
    "$XTOUCH" -p "$1/!/d"
    "$XTOUCH" -p "$1/!-/e"
    "$XTOUCH" -p "$1/,/f"
    "$XTOUCH" -p "$1/)/g"
    "$XTOUCH" -p "$1/.../h"
    "$XTOUCH" -p "$1/\\/i"
    "$XTOUCH" -p "$1/ /j"
    "$XTOUCH" -p "$1/[/k"
}

# Creates a very deep directory structure for testing PATH_MAX handling
make_deep() {
    mkdir -p "$1"

    # $name will be 255 characters, aka _XOPEN_NAME_MAX
    local name="0123456789ABCDEF"
    name="$name$name$name$name"
    name="$name$name$name$name"
    name="${name:0:255}"

    # 4 * 4 * 256 == 4096 >= PATH_MAX
    local path="$name/$name/$name/$name"
    path="$path/$path/$path/$path"

    "$XTOUCH" -p "$1"/{{0..9},A,B,C,D,E,F}/"$path/$name"
}

# Creates a directory structure with many different types, and therefore colors
make_rainbow() {
    "$XTOUCH" -p "$1/file.txt"
    "$XTOUCH" -p "$1/file.dat"
    "$XTOUCH" -p "$1/lower".{gz,tar,tar.gz}
    "$XTOUCH" -p "$1/upper".{GZ,TAR,TAR.GZ}
    "$XTOUCH" -p "$1/lu.tar.GZ" "$1/ul.TAR.gz"
    ln -s file.txt "$1/link.txt"
    "$XTOUCH" -p "$1/mh1"
    ln "$1/mh1" "$1/mh2"
    mkfifo "$1/pipe"
    # TODO: block
    ln -s /dev/null "$1/chardev_link"
    ln -s nowhere "$1/broken"
    "$MKSOCK" "$1/socket"
    "$XTOUCH" -p "$1"/s{u,g,ug}id
    chmod u+s "$1"/su{,g}id
    chmod g+s "$1"/s{u,}gid
    mkdir "$1/ow" "$1"/sticky{,_ow}
    chmod o+w "$1"/*ow
    chmod +t "$1"/sticky*
    "$XTOUCH" -p "$1"/exec.sh
    chmod +x "$1"/exec.sh
    "$XTOUCH" -p "$1/"$'\e[1m/\e[0m'
}

# Create all standard directory trees
make_stddirs() {
    TMP=$(mktemp -d "${TMPDIR:-/tmp}"/bfs.XXXXXXXXXX)

    if ((CLEAN)); then
        defer clean_stddirs
    else
        printf "Test files saved to ${BLD}%s${RST}\n" "$TMP"
    fi

    chown "$(id -u):$(id -g)" "$TMP"

    make_basic "$TMP/basic"
    make_perms "$TMP/perms"
    make_links "$TMP/links"
    make_loops "$TMP/loops"
    make_times "$TMP/times"
    make_weirdnames "$TMP/weirdnames"
    make_deep "$TMP/deep"
    make_rainbow "$TMP/rainbow"
    mkdir "$TMP/scratch"
}

# Clean whatever was left in the scratch directory
clean_scratch() {
    if [ -e "$TMP/scratch" ]; then
        # Try to unmount anything left behind
        if ((${#SUDO[@]})) && command -v mountpoint &>/dev/null; then
            for path in "$TMP/scratch"/*; do
                if mountpoint -q "$path"; then
                    sudo umount "$path"
                fi
            done
        fi

        # Reset any modified permissions
        chmod -R +rX "$TMP/scratch"

        rm -rf "$TMP/scratch"
    fi

    mkdir "$TMP/scratch"
}

# Clean up temporary directories on exit
clean_stddirs() {
    # Don't force rm to deal with long paths
    for dir in "$TMP"/deep/*/*; do
        if [ -d "$dir" ]; then
            (cd "$dir" && rm -rf *)
        fi
    done

    # In case a test left anything weird in scratch/
    clean_scratch

    rm -rf "$TMP"
}