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
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
|
#!/bin/bash -
# libguestfs
# Copyright (C) 2009 Red Hat Inc.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
unset CDPATH
set -e
#set -v
if [ -z "$top_builddir" ]; then
echo "$0: error: environment variable \$top_builddir must be set"
exit 1
fi
nr_stages=$(grep "^stage " $0 | wc -l)
# Allow top_builddir to be a relative path, but also make it absolute,
# and move to that directory for the initial phase of the script.
top_builddir=$(cd "$top_builddir" > /dev/null; pwd)
# Set libguestfs up for running locally.
export LIBGUESTFS_PATH="$top_builddir/appliance"
# Paths to the other programs and files. NB: Must be absolute paths.
guestfish="$top_builddir/fish/guestfish"
guestmount="$top_builddir/fuse/guestmount"
image="$top_builddir/fuse/test.img"
mp="$top_builddir/fuse/test-mp"
if [ ! -x "$guestfish" -o ! -x "$guestmount" ]; then
echo "$0: error: guestfish or guestmount are not available"
exit 1
fi
# Ensure everything is cleaned up on exit.
rm -f "$image"
mkdir -p "$mp"
fusermount -u "$mp" >/dev/null 2>&1 ||:
function cleanup ()
{
status=$?
set +e
[ $status = 0 ] || echo "*** FAILED ***"
echo "Unmounting filesystem and cleaning up."
# Move out of the mountpoint (otherwise our cwd will prevent the
# mountpoint from being unmounted).
cd "$top_builddir"
# Who's using this? Should be no one, but see below.
if [ -x /sbin/fuser ]; then /sbin/fuser "$mp"; fi
# If you run this and you have GNOME running at the same time,
# then randomly /usr/libexec/gvfs-gdu-volume-monitor will decide
# to do whatever it does in the mountpoint directory, preventing
# you from unmounting it! Hence the need for this loop.
count=10
while ! fusermount -u "$mp" && [ $count -gt 0 ]; do
sleep 1
((count--))
done
rm -f "$image"
rm -rf "$mp"
exit $status
}
trap cleanup INT TERM QUIT EXIT
s=1
function stage ()
{
echo "test-fuse: $s/$nr_stages:" "$@" "..."
((s++))
}
stage Create filesystem with some initial content
$guestfish <<EOF
sparse "$image" 10M
run
part-disk /dev/sda mbr
mkfs ext2 /dev/sda1
mount /dev/sda1 /
write /hello.txt hello
write /world.txt "hello world"
touch /empty
EOF
stage Mounting the filesystem
$guestmount -a "$image" -m /dev/sda1 "$mp"
stage Changing into mounted directory
cd "$mp"
stage Checking initial files exist
[ -n "$(echo *)" ]
[ "$(ls empty hello.txt world.txt)" = "empty
hello.txt
world.txt" ]
stage Checking initial files contain expected content
[ "$(cat hello.txt)" = "hello" ]
[ "$(cat world.txt)" = "hello world" ]
cat empty ;# should print nothing
[ -z "$(cat empty)" ]
stage Checking file modes of initial content
[ "$(stat -c %a empty)" = "644" ]
[ "$(stat -c %a hello.txt)" = "644" ]
[ "$(stat -c %a world.txt)" = "644" ]
stage Checking sizes of initial content
[ "$(stat -c %s empty)" -eq 0 ]
[ "$(stat -c %s hello.txt)" -eq 5 ]
[ "$(stat -c %s world.txt)" -eq 11 ]
stage Checking unlink
touch new
rm -f new ;# force because file is "owned" by root
stage Checking symbolic link
ln -s hello.txt symlink
[ -L symlink ]
stage Checking readlink
[ "$(readlink symlink)" = "hello.txt" ]
stage Checking hard link
[ "$(stat -c %h hello.txt)" -eq 1 ]
ln hello.txt link
[ "$(stat -c %h link)" -eq 2 ]
[ "$(stat -c %h hello.txt)" -eq 2 ]
rm -f link
[ ! -e link ]
# This fails because of caching. The problem is that the linked file
# ("hello.txt") is cached with a link count of 2. unlink("link")
# invalidates the cache for "link", but _not_ for "hello.txt" which
# still has the now-incorrect cached value. However there's not much
# we can do about this since searching for all linked inodes of a file
# is an O(n) operation.
#[ "$(stat -c %h hello.txt)" -eq 1 ]
stage Checking mkdir
mkdir newdir
[ -d newdir ]
stage Checking rmdir
rmdir newdir
[ ! -e newdir ]
stage Checking rename
touch old
mv old new
[ -f new ]
[ ! -e old ]
rm -f new
stage Checking chmod
touch new
chmod a+x new
[ -x new ]
chmod a-x new
[ ! -x new ]
chmod a-w new
[ ! -w new ]
chmod a+w new
[ -w new ]
chmod a-r new
[ ! -r new ]
chmod a+r new
[ -r new ]
rm -f new
stage Checking truncate
truncate -s 10000 truncated
[ "$(stat -c %s truncated)" -eq 10000 ]
truncate -c -s 1000 truncated
[ "$(stat -c %s truncated)" -eq 1000 ]
truncate -c -s 10 truncated
[ "$(stat -c %s truncated)" -eq 10 ]
truncate -c -s 0 truncated
[ "$(stat -c %s truncated)" -eq 0 ]
rm -f truncated
stage Checking utimens and timestamps
for ts in 12345 1234567 987654321; do
# NB: It's not possible to set the ctime with touch.
touch -a -d @$ts timestamp
[ "$(stat -c %X timestamp)" -eq $ts ]
touch -m -d @$ts timestamp
[ "$(stat -c %Y timestamp)" -eq $ts ]
touch -d @$ts timestamp
[ "$(stat -c %X timestamp)" -eq $ts ]
[ "$(stat -c %Y timestamp)" -eq $ts ]
done
stage Checking writes
cp hello.txt copy.txt
echo >> copy.txt
echo world >> copy.txt
echo bigger >> copy.txt
echo biggest >> copy.txt
[ "$(cat copy.txt)" = "hello
world
bigger
biggest" ]
# These ones are not yet tested by the current script:
#stage XXX statfs/statvfs
#stage XXX xattr operations
# These ones cannot easily be tested by the current script, eg because
# this script doesn't run as root:
#stage XXX fsync
#stage XXX chown
#stage XXX mknod
|