2 # Routines for populating a scratch fs, and helpers to exercise an FS
3 # once it's been fuzzed.
4 #-----------------------------------------------------------------------
5 # Copyright (c) 2015 Oracle. All Rights Reserved.
6 # This program is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 2 of the License, or
9 # (at your option) any later version.
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
21 # Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane,
22 # Mountain View, CA 94043, USA, or: http://www.sgi.com
23 #-----------------------------------------------------------------------
25 _require_xfs_io_command "falloc"
26 _require_xfs_io_command "fpunch"
28 _require_xfs_db_blocktrash_z_command() {
29 test "${FSTYP}" = "xfs" || _notrun "cannot run xfs_db on ${FSTYP}"
30 $XFS_DB_PROG -x -f -c 'blocktrash -z' "${TEST_DEV}" | grep -q 'nothing on stack' || _notrun "blocktrash -z not supported"
33 # Attempt to make files of "every" format for data, dirs, attrs etc.
34 # (with apologies to Eric Sandeen for mutating xfser.sh)
36 # Create a large directory
37 __populate_create_dir() {
43 seq 0 "${nr}" | while read d; do
45 test "$((d % 20))" -eq 0 && creat=touch
46 $creat "${name}/$(printf "%.08d" "$d")"
49 test -z "${missing}" && return
50 seq 1 2 "${nr}" | while read d; do
51 rm -rf "${name}/$(printf "%.08d" "$d")"
55 # Add a bunch of attrs to a file
56 __populate_create_attr() {
62 seq 0 "${nr}" | while read d; do
63 setfattr -n "user.$(printf "%.08d" "$d")" -v "$(printf "%.08d" "$d")" "${name}"
66 test -z "${missing}" && return
67 seq 1 2 "${nr}" | while read d; do
68 setfattr -x "user.$(printf "%.08d" "$d")" "${name}"
72 # Fill up 60% of the remaining free space
73 __populate_fill_fs() {
76 test -z "${pct}" && pct=60
78 SRC_SZ="$(du -ks "${SRCDIR}" | cut -f 1)"
79 FS_SZ="$(( $(stat -f "${dir}" -c '%a * %S') / 1024 ))"
81 NR="$(( (FS_SZ * ${pct} / 100) / SRC_SZ ))"
82 test "${NR}" -lt 1 && NR=1
84 seq 1 "${NR}" | while read nr; do
85 cp -pRdu "${SRCDIR}" "${dir}/test.${nr}" >> $seqres.full 2>&1
89 # Populate an XFS on the scratch device with (we hope) all known
90 # types of metadata block
91 _scratch_xfs_populate() {
93 blksz="$(stat -f -c '%s' "${SCRATCH_MNT}")"
94 dblksz="$(xfs_info "${SCRATCH_MNT}" | grep naming.*bsize | sed -e 's/^.*bsize=//g' -e 's/\([0-9]*\).*$/\1/g')"
95 leaf_lblk="$((32 * 1073741824 / blksz))"
96 node_lblk="$((64 * 1073741824 / blksz))"
102 echo "+ extents file"
103 $XFS_IO_PROG -f -c "pwrite -S 0x61 0 ${blksz}" "${SCRATCH_MNT}/S_IFREG.FMT_EXTENTS"
106 echo "+ btree extents file"
107 nr="$((blksz * 2 / 16))"
108 $XFS_IO_PROG -f -c "pwrite -S 0x62 0 $((blksz * nr))" "${SCRATCH_MNT}/S_IFREG.FMT_BTREE"
109 for i in $(seq 1 2 ${nr}); do
110 $XFS_IO_PROG -f -c "fpunch $((i * blksz)) ${blksz}" "${SCRATCH_MNT}/S_IFREG.FMT_BTREE"
116 __populate_create_dir "${SCRATCH_MNT}/S_IFDIR.FMT_INLINE" 1
120 __populate_create_dir "${SCRATCH_MNT}/S_IFDIR.FMT_BLOCK" "$((dblksz / 40))"
124 __populate_create_dir "${SCRATCH_MNT}/S_IFDIR.FMT_LEAF" "$((dblksz / 12))"
128 __populate_create_dir "${SCRATCH_MNT}/S_IFDIR.FMT_NODE" "$((16 * dblksz / 40))" true
131 __populate_create_dir "${SCRATCH_MNT}/S_IFDIR.FMT_BTREE" "$((128 * dblksz / 40))" true
135 echo "+ inline symlink"
136 ln -s target "${SCRATCH_MNT}/S_IFLNK.FMT_LOCAL"
139 echo "+ extents symlink"
140 ln -s "$(perl -e 'print "x" x 1023;')" "${SCRATCH_MNT}/S_IFLNK.FMT_EXTENTS"
144 mknod "${SCRATCH_MNT}/S_IFCHR" c 1 1
145 mknod "${SCRATCH_MNT}/S_IFBLK" c 1 1
150 __populate_create_attr "${SCRATCH_MNT}/ATTR.FMT_LOCAL" 1
154 __populate_create_attr "${SCRATCH_MNT}/ATTR.FMT_LEAF" "$((blksz / 40))"
158 __populate_create_attr "${SCRATCH_MNT}/ATTR.FMT_NODE" "$((8 * blksz / 40))"
162 __populate_create_attr "${SCRATCH_MNT}/ATTR.FMT_BTREE" "$((64 * blksz / 40))" true
164 # FMT_EXTENTS with a remote less-than-a-block value
165 echo "+ attr extents with a remote less-than-a-block value"
166 touch "${SCRATCH_MNT}/ATTR.FMT_EXTENTS_REMOTE3K"
167 $XFS_IO_PROG -f -c "pwrite -S 0x43 0 3k" "${SCRATCH_MNT}/attrvalfile" > /dev/null
168 attr -q -s user.remotebtreeattrname "${SCRATCH_MNT}/ATTR.FMT_EXTENTS_REMOTE3K" < "${SCRATCH_MNT}/attrvalfile"
170 # FMT_EXTENTS with a remote block-size value
171 echo "+ attr extents with a remote one-block value"
172 touch "${SCRATCH_MNT}/ATTR.FMT_EXTENTS_REMOTE4K"
173 $XFS_IO_PROG -f -c "pwrite -S 0x44 0 4k" "${SCRATCH_MNT}/attrvalfile" > /dev/null
174 attr -q -s user.remotebtreeattrname "${SCRATCH_MNT}/ATTR.FMT_EXTENTS_REMOTE4K" < "${SCRATCH_MNT}/attrvalfile"
175 rm -rf "${SCRATCH_MNT}/attrvalfile"
177 # Make an unused inode
179 touch "${SCRATCH_MNT}/unused"
180 $XFS_IO_PROG -f -c 'fsync' "${SCRATCH_MNT}/unused"
181 rm -rf "${SCRATCH_MNT}/unused"
183 # Copy some real files (xfs tests, I guess...)
185 #__populate_fill_fs "${SCRATCH_MNT}" 40
186 cp -pRdu --reflink=always "${SCRATCH_MNT}/S_IFREG.FMT_BTREE" "${SCRATCH_MNT}/S_IFREG.FMT_BTREE.REFLINK" 2> /dev/null
188 umount "${SCRATCH_MNT}"
191 # Populate an ext4 on the scratch device with (we hope) all known
192 # types of metadata block
193 _scratch_ext4_populate() {
195 blksz="$(stat -f -c '%s' "${SCRATCH_MNT}")"
197 leaf_lblk="$((32 * 1073741824 / blksz))"
198 node_lblk="$((64 * 1073741824 / blksz))"
205 $XFS_IO_PROG -f -c "pwrite -S 0x61 0 1" "${SCRATCH_MNT}/S_IFREG.FMT_INLINE"
208 echo "+ extents file"
209 $XFS_IO_PROG -f -c "pwrite -S 0x61 0 ${blksz}" "${SCRATCH_MNT}/S_IFREG.FMT_EXTENTS"
212 echo "+ extent tree file"
213 nr="$((blksz * 2 / 12))"
214 $XFS_IO_PROG -f -c "pwrite -S 0x62 0 $((blksz * nr))" "${SCRATCH_MNT}/S_IFREG.FMT_ETREE"
215 for i in $(seq 1 2 ${nr}); do
216 $XFS_IO_PROG -f -c "fpunch $((i * blksz)) ${blksz}" "${SCRATCH_MNT}/S_IFREG.FMT_ETREE"
222 __populate_create_dir "${SCRATCH_MNT}/S_IFDIR.FMT_INLINE" 1
226 __populate_create_dir "${SCRATCH_MNT}/S_IFDIR.FMT_BLOCK" "$((dblksz / 24))"
230 __populate_create_dir "${SCRATCH_MNT}/S_IFDIR.FMT_HTREE" "$((4 * dblksz / 24))"
234 echo "+ inline symlink"
235 ln -s target "${SCRATCH_MNT}/S_IFLNK.FMT_LOCAL"
238 echo "+ extents symlink"
239 ln -s "$(perl -e 'print "x" x 1023;')" "${SCRATCH_MNT}/S_IFLNK.FMT_EXTENTS"
243 mknod "${SCRATCH_MNT}/S_IFCHR" c 1 1
244 mknod "${SCRATCH_MNT}/S_IFBLK" c 1 1
249 __populate_create_attr "${SCRATCH_MNT}/ATTR.FMT_LOCAL" 1
253 __populate_create_attr "${SCRATCH_MNT}/ATTR.FMT_BLOCK" "$((blksz / 40))"
255 # Make an unused inode
257 touch "${SCRATCH_MNT}/unused"
258 $XFS_IO_PROG -f -c 'fsync' "${SCRATCH_MNT}/unused"
259 rm -rf "${SCRATCH_MNT}/unused"
261 # Copy some real files (xfs tests, I guess...)
263 __populate_fill_fs "${SCRATCH_MNT}"
264 cp -pRdu --reflink=always "${SCRATCH_MNT}/S_IFREG.FMT_ETREE" "${SCRATCH_MNT}/S_IREG.FMT_ETREE.REFLINK" 2> /dev/null
266 umount "${SCRATCH_MNT}"
269 # Find the inode number of a file
270 __populate_find_inode() {
272 inode="$(stat -c '%i' "${name}")"
276 # Check data fork format of XFS file
277 __populate_check_xfs_dformat() {
281 fmt="$(_scratch_xfs_db -c "inode ${inode}" -c 'p core.format' | sed -e 's/^.*(\([a-z]*\)).*$/\1/g')"
282 test "${format}" = "${fmt}" || _fail "failed to create ino ${inode} dformat expected ${format} saw ${fmt}"
285 # Check attr fork format of XFS file
286 __populate_check_xfs_aformat() {
290 fmt="$(_scratch_xfs_db -c "inode ${inode}" -c 'p core.aformat' | sed -e 's/^.*(\([a-z]*\)).*$/\1/g')"
291 test "${format}" = "${fmt}" || _fail "failed to create ino ${inode} aformat expected ${format} saw ${fmt}"
294 # Check structure of XFS directory
295 __populate_check_xfs_dir() {
299 (test -n "${leaf_lblk}" && test -n "${node_lblk}") || _fail "must define leaf_lblk and node_lblk before calling __populate_check_xfs_dir"
303 #echo "== check dir ${inode} type ${dtype}" ; _scratch_xfs_db -x -c "inode ${inode}" -c "bmap"
304 _scratch_xfs_db -x -c "inode ${inode}" -c "dblock 0" -c "stack" | grep -q 'file data block is unmapped' || datab=1
305 _scratch_xfs_db -x -c "inode ${inode}" -c "dblock ${leaf_lblk}" -c "stack" | grep -q 'file data block is unmapped' || leafb=1
306 _scratch_xfs_db -x -c "inode ${inode}" -c "dblock ${node_lblk}" -c "stack" | grep -q 'file data block is unmapped' || freeb=1
309 "shortform"|"inline"|"local")
310 (test "${datab}" -eq 0 && test "${leafb}" -eq 0 && test "${freeb}" -eq 0) || _fail "failed to create ${dtype} dir ino ${inode} datab ${datab} leafb ${leafb} freeb ${freeb}"
313 (test "${datab}" -eq 1 && test "${leafb}" -eq 0 && test "${freeb}" -eq 0) || _fail "failed to create ${dtype} dir ino ${inode} datab ${datab} leafb ${leafb} freeb ${freeb}"
316 (test "${datab}" -eq 1 && test "${leafb}" -eq 1 && test "${freeb}" -eq 0) || _fail "failed to create ${dtype} dir ino ${inode} datab ${datab} leafb ${leafb} freeb ${freeb}"
319 (test "${datab}" -eq 1 && test "${leafb}" -eq 1 && test "${freeb}" -eq 1) || _fail "failed to create ${dtype} dir ino ${inode} datab ${datab} leafb ${leafb} freeb ${freeb}"
322 _fail "Unknown directory type ${dtype}"
326 # Check structure of XFS attr
327 __populate_check_xfs_attr() {
333 #echo "== check attr ${inode} type ${dtype}" ; _scratch_xfs_db -x -c "inode ${inode}" -c "bmap -a"
334 _scratch_xfs_db -x -c "inode ${inode}" -c "ablock 0" -c "stack" | grep -q 'file attr block is unmapped' || datab=1
335 _scratch_xfs_db -x -c "inode ${inode}" -c "ablock 1" -c "stack" | grep -q 'file attr block is unmapped' || leafb=1
338 "shortform"|"inline"|"local")
339 (test "${datab}" -eq 0 && test "${leafb}" -eq 0) || _fail "failed to create ${atype} attr ino ${inode} datab ${datab} leafb ${leafb}"
342 (test "${datab}" -eq 1 && test "${leafb}" -eq 0) || _fail "failed to create ${atype} attr ino ${inode} datab ${datab} leafb ${leafb}"
345 (test "${datab}" -eq 1 && test "${leafb}" -eq 1) || _fail "failed to create ${atype} attr ino ${inode} datab ${datab} leafb ${leafb}"
348 _fail "Unknown attribute type ${atype}"
352 # Check that populate created all the types of files we wanted
353 _scratch_xfs_populate_check() {
355 extents_file="$(__populate_find_inode "${SCRATCH_MNT}/S_IFREG.FMT_EXTENTS")"
356 btree_file="$(__populate_find_inode "${SCRATCH_MNT}/S_IFREG.FMT_BTREE")"
357 inline_dir="$(__populate_find_inode "${SCRATCH_MNT}/S_IFDIR.FMT_INLINE")"
358 block_dir="$(__populate_find_inode "${SCRATCH_MNT}/S_IFDIR.FMT_BLOCK")"
359 leaf_dir="$(__populate_find_inode "${SCRATCH_MNT}/S_IFDIR.FMT_LEAF")"
360 node_dir="$(__populate_find_inode "${SCRATCH_MNT}/S_IFDIR.FMT_NODE")"
361 btree_dir="$(__populate_find_inode "${SCRATCH_MNT}/S_IFDIR.FMT_BTREE")"
362 local_slink="$(__populate_find_inode "${SCRATCH_MNT}/S_IFLNK.FMT_LOCAL")"
363 extents_slink="$(__populate_find_inode "${SCRATCH_MNT}/S_IFLNK.FMT_EXTENTS")"
364 bdev="$(__populate_find_inode "${SCRATCH_MNT}/S_IFBLK")"
365 cdev="$(__populate_find_inode "${SCRATCH_MNT}/S_IFCHR")"
366 local_attr="$(__populate_find_inode "${SCRATCH_MNT}/ATTR.FMT_LOCAL")"
367 leaf_attr="$(__populate_find_inode "${SCRATCH_MNT}/ATTR.FMT_LEAF")"
368 node_attr="$(__populate_find_inode "${SCRATCH_MNT}/ATTR.FMT_NODE")"
369 btree_attr="$(__populate_find_inode "${SCRATCH_MNT}/ATTR.FMT_BTREE")"
371 blksz="$(stat -f -c '%s' "${SCRATCH_MNT}")"
372 dblksz="$(xfs_info "${SCRATCH_MNT}" | grep naming.*bsize | sed -e 's/^.*bsize=//g' -e 's/\([0-9]*\).*$/\1/g')"
373 leaf_lblk="$((32 * 1073741824 / blksz))"
374 node_lblk="$((64 * 1073741824 / blksz))"
375 umount "${SCRATCH_MNT}"
377 __populate_check_xfs_dformat "${extents_file}" "extents"
378 __populate_check_xfs_dformat "${btree_file}" "btree"
379 __populate_check_xfs_dir "${inline_dir}" "inline"
380 __populate_check_xfs_dir "${block_dir}" "block"
381 __populate_check_xfs_dir "${leaf_dir}" "leaf"
382 __populate_check_xfs_dir "${node_dir}" "node"
383 __populate_check_xfs_dir "${btree_dir}" "btree"
384 __populate_check_xfs_dformat "${btree_dir}" "btree"
385 __populate_check_xfs_dformat "${bdev}" "dev"
386 __populate_check_xfs_dformat "${cdev}" "dev"
387 __populate_check_xfs_attr "${local_attr}" "local"
388 __populate_check_xfs_attr "${leaf_attr}" "leaf"
389 __populate_check_xfs_attr "${node_attr}" "node"
390 __populate_check_xfs_attr "${btree_attr}" "btree"
391 __populate_check_xfs_aformat "${btree_attr}" "btree"
394 # Check data fork format of ext4 file
395 __populate_check_ext4_dformat() {
402 debugfs -R "stat <${inode}>" "${dev}" 2> /dev/null | grep 'ETB[0-9]' -q && etree=1
403 iflags="$(debugfs -R "stat <${inode}>" "${dev}" 2> /dev/null | grep 'Flags:' | sed -e 's/^.*Flags: \([0-9a-fx]*\).*$/\1/g')"
404 test "$(echo "${iflags}" | awk '{print and(strtonum($1), 0x80000);}')" -gt 0 && extents=1
408 test "${extents}" -eq 0 || _fail "failed to create ino ${inode} with blockmap"
411 test "${extents}" -eq 1 || _fail "failed to create ino ${inode} with extents"
414 (test "${extents}" -eq 1 && test "${etree}" -eq 1) || _fail "failed to create ino ${inode} with extent tree"
417 _fail "Unknown dformat ${format}"
421 # Check attr fork format of ext4 file
422 __populate_check_ext4_aformat() {
428 debugfs -R "stat <${inode}>" "${dev}" 2> /dev/null | grep 'File ACL: 0' -q && ablock=0
432 test "${ablock}" -eq 0 || _fail "failed to create inode ${inode} with ${format} xattr"
435 test "${extents}" -eq 1 || _fail "failed to create inode ${inode} with ${format} xattr"
438 _fail "Unknown aformat ${format}"
442 # Check structure of ext4 dir
443 __populate_check_ext4_dir() {
450 iflags="$(debugfs -R "stat <${inode}>" "${dev}" 2> /dev/null | grep 'Flags:' | sed -e 's/^.*Flags: \([0-9a-fx]*\).*$/\1/g')"
451 test "$(echo "${iflags}" | awk '{print and(strtonum($1), 0x1000);}')" -gt 0 && htree=1
452 test "$(echo "${iflags}" | awk '{print and(strtonum($1), 0x10000000);}')" -gt 0 && inline=1
456 (test "${inline}" -eq 1 && test "${htree}" -eq 0) || _fail "failed to create ${dtype} dir ino ${inode} htree ${htree} inline ${inline}"
459 (test "${inline}" -eq 0 && test "${htree}" -eq 0) || _fail "failed to create ${dtype} dir ino ${inode} htree ${htree} inline ${inline}"
462 (test "${inline}" -eq 0 && test "${htree}" -eq 1) || _fail "failed to create ${dtype} dir ino ${inode} htree ${htree} inline ${inline}"
465 _fail "Unknown directory type ${dtype}"
470 # Check that populate created all the types of files we wanted
471 _scratch_ext4_populate_check() {
473 extents_file="$(__populate_find_inode "${SCRATCH_MNT}/S_IFREG.FMT_EXTENTS")"
474 etree_file="$(__populate_find_inode "${SCRATCH_MNT}/S_IFREG.FMT_ETREE")"
475 block_dir="$(__populate_find_inode "${SCRATCH_MNT}/S_IFDIR.FMT_BLOCK")"
476 htree_dir="$(__populate_find_inode "${SCRATCH_MNT}/S_IFDIR.FMT_HTREE")"
477 extents_slink="$(__populate_find_inode "${SCRATCH_MNT}/S_IFLNK.FMT_EXTENTS")"
478 local_attr="$(__populate_find_inode "${SCRATCH_MNT}/ATTR.FMT_LOCAL")"
479 block_attr="$(__populate_find_inode "${SCRATCH_MNT}/ATTR.FMT_BLOCK")"
480 umount "${SCRATCH_MNT}"
482 __populate_check_ext4_dformat "${extents_file}" "extents"
483 __populate_check_ext4_dformat "${etree_file}" "etree"
484 __populate_check_ext4_dir "${block_dir}" "block"
485 __populate_check_ext4_dir "${htree_dir}" "htree"
486 __populate_check_ext4_dformat "${extents_slink}" "extents"
487 __populate_check_ext4_aformat "${local_attr}" "local"
488 __populate_check_ext4_aformat "${block_attr}" "block"
491 # Populate a scratch FS and check the contents to make sure we got that
492 _scratch_populate() {
495 _scratch_xfs_populate
496 _scratch_xfs_populate_check
499 _scratch_ext4_populate
500 _scratch_ext4_populate_check
503 _fail "Don't know how to populate a ${FSTYP} filesystem."
508 # Modify various files after a fuzzing operation
509 _scratch_fuzz_modify() {
512 test -z "${nr}" && nr=50000
513 echo "+++ touch ${nr} files"
514 $XFS_IO_PROG -f -c "pwrite -S 0x63 0 ${BLK_SZ}" "/tmp/afile" > /dev/null
516 find "${SCRATCH_MNT}/" -type f 2> /dev/null | head -n "${nr}" | while read f; do
517 setfattr -n "user.date" -v "${date}" "$f"
518 cat "/tmp/afile" >> "$f"
523 echo "+++ create files"
524 cp -pRdu "${SRCDIR}" "${SCRATCH_MNT}/test.moo"
527 echo "+++ remove files"
528 rm -rf "${SCRATCH_MNT}/test.moo"
529 rm -rf "${SCRATCH_MNT}/test.1"
532 # Try to access files after fuzzing
533 _scratch_fuzz_test() {
534 echo "+++ ls -laR" >> $seqres.full
535 ls -laR "${SCRATCH_MNT}/test.1/" >/dev/null 2>&1
537 echo "+++ cat files" >> $seqres.full
538 (find "${SCRATCH_MNT}/test.1/" -type f -size -1048576k -print0 | xargs -0 cat) >/dev/null 2>&1
541 # Fill a file system by repeatedly creating files in the given folder
542 # starting with the given file size. Files are reduced in size when
543 # they can no longer fit until no more files can be created.
551 local bytes_written=0
554 if [ $# -ne 4 ]; then
555 echo "Usage: _fill_fs filesize dir blocksize switch_user"
559 if [ $switch_user -eq 0 ]; then
562 _user_do "mkdir -p $dir"
564 if [ ! -d $dir ]; then
568 testio=`$XFS_IO_PROG -F -fc "falloc 0 $block_size" $dir/$$.xfs_io 2>&1`
569 echo $testio | grep -q "not found" && use_falloc=0
570 echo $testio | grep -q "Operation not supported" && use_falloc=0
572 if [ $file_size -lt $block_size ]; then
573 $file_size = $block_size
576 while [ $file_size -ge $block_size ]; do
578 if [ $switch_user -eq 0 ]; then
579 if [ $use_falloc -eq 0 ]; then
580 $XFS_IO_PROG -fc "pwrite -b 8388608 0 $file_size" \
583 $XFS_IO_PROG -fc "falloc 0 $file_size" \
587 if [ $use_falloc -eq 0 ]; then
588 _user_do "$XFS_IO_PROG -f -c \"pwrite -b 8388608 0 \
589 $file_size\" $dir/$file_count"
591 _user_do "$XFS_IO_PROG -f -c \"falloc 0 \
592 $file_size\" $dir/$file_count"
596 if [ -f $dir/$file_count ]; then
597 bytes_written=$(stat -c '%s' $dir/$file_count)
600 # If there was no room to make the file, then divide it in
601 # half, and keep going
602 if [ $bytes_written -lt $file_size ]; then
603 file_size=$((file_size / 2))
605 file_count=$((file_count + 1))