1.0.60 release

pull/1227/head v1.0.60
longpanda 2 years ago
parent 69b6bb8fca
commit b0568922d2

@ -21,7 +21,7 @@ body:
attributes:
label: Ventoy Version
description: What version of ventoy are you running?
placeholder: 1.0.59
placeholder: 1.0.60
validations:
required: true
- type: dropdown

Binary file not shown.

@ -23,6 +23,8 @@ else
fi
export PATH="./tool/$TOOLDIR:$PATH"
rm -f ./log.txt
echo ''
echo '**********************************************'

Binary file not shown.

Binary file not shown.

Binary file not shown.

@ -38,13 +38,10 @@ sh buildedk.sh >> $LOG 2>&1 || exit 1
#cd $VTOY_PATH/VtoyTool
#sh build.sh || exit 1
#cd $VTOY_PATH/vtoyfat/fat_io_lib
#cd $VTOY_PATH/vtoycli/fat_io_lib
#sh buildlib.sh
#cd $VTOY_PATH/vtoyfat
#sh build.sh || exit 1
#cd $VTOY_PATH/vtoygpt
#cd $VTOY_PATH/vtoycli
#sh build.sh || exit 1
#cd $VTOY_PATH/FUSEISO

@ -16,6 +16,7 @@ print_usage() {
echo ' -s/-S enable/disable secure boot support (default is disabled)'
echo ' -g use GPT partition style, default is MBR (only for install)'
echo ' -L Label of the 1st exfat partition (default is Ventoy)'
echo ' -n try non-destructive installation (only for install)'
echo ''
}
@ -28,6 +29,8 @@ while [ -n "$1" ]; do
elif [ "$1" = "-I" ]; then
MODE="install"
FORCE="Y"
elif [ "$1" = "-n" ]; then
NONDESTRUCTIVE="Y"
elif [ "$1" = "-u" ]; then
MODE="update"
elif [ "$1" = "-l" ]; then
@ -162,7 +165,7 @@ if [ -d ./tmp_mnt ]; then
fi
if [ "$MODE" = "install" ]; then
if [ "$MODE" = "install" -a -z "$NONDESTRUCTIVE" ]; then
vtdebug "install Ventoy ..."
if [ -n "$VTGPT" ]; then
@ -255,7 +258,10 @@ if [ "$MODE" = "install" ]; then
exit 1
fi
if ! dd if=/dev/zero of=$DISK bs=1 count=512 status=none conv=fsync; then
# check and umount
check_umount_disk "$DISK"
if ! dd if=/dev/zero of=$DISK bs=64 count=512 status=none conv=fsync; then
vterr "Write data to $DISK failed, please check whether it's in use."
exit 1
fi
@ -281,10 +287,14 @@ if [ "$MODE" = "install" ]; then
PART1=$(get_disk_part_name $DISK 1)
PART2=$(get_disk_part_name $DISK 2)
#clean part2
dd status=none conv=fsync if=/dev/zero of=$DISK bs=512 count=32 seek=$part2_start_sector
#format part1
vtinfo "Format partition 1 ..."
mkexfatfs -n "$VTNEW_LABEL" -s $cluster_sectors ${PART1}
vtinfo "writing data to disk ..."
vtinfo "writing data to disk ..."
dd status=none conv=fsync if=./boot/boot.img of=$DISK bs=1 count=446
if [ -n "$VTGPT" ]; then
@ -314,51 +324,181 @@ if [ "$MODE" = "install" ]; then
sync
vtinfo "esp partition processing ..."
if [ "$SECUREBOOT" != "YES" ]; then
sleep 2
check_umount_disk "$DISK"
vtoycli partresize -s $DISK $part2_start_sector
fi
echo ""
vtinfo "Install Ventoy to $DISK successfully finished."
echo ""
elif [ "$MODE" = "install" -a -n "$NONDESTRUCTIVE" ]; then
vtdebug "non-destructive install Ventoy ..."
version=$(get_disk_ventoy_version $DISK)
if [ $? -eq 0 ]; then
if [ -z "$FORCE" ]; then
vtwarn "$DISK already contains a Ventoy with version $version."
vtwarn "You can not do and don not need non-destructive installation."
vtwarn ""
exit 1
fi
fi
sleep 1
check_umount_disk "$DISK"
disk_sector_num=$(cat /sys/block/${DISK#/dev/}/size)
disk_size_gb=$(expr $disk_sector_num / 2097152)
if vtoycli partresize -t $DISK; then
OldStyle="GPT"
else
OldStyle="MBR"
fi
#Print disk info
echo "Disk : $DISK"
parted -s $DISK p 2>&1 | grep Model
echo "Size : $disk_size_gb GB"
echo "Style: $OldStyle"
echo ''
vtwarn "Attention:"
vtwarn "Ventoy will try non-destructive installation on $DISK if possible."
echo ""
read -p 'Continue? (y/n) ' Answer
if [ "$Answer" != "y" ]; then
if [ "$Answer" != "Y" ]; then
exit 0
fi
fi
if [ $disk_sector_num -le $VENTOY_SECTOR_NUM ]; then
vterr "No enough space in disk $DISK"
exit 1
fi
PART1=$(get_disk_part_name $DISK 1)
PART2=$(get_disk_part_name $DISK 2)
#Part1 size in MB aligned with 4KB
PART1_SECTORS=$(cat /sys/class/block/${PART1#/dev/}/size)
PART1_4K=$(expr $PART1_SECTORS / 8)
PART1_MB=$(expr $PART1_4K / 256)
PART1_NEW_MB=$(expr $PART1_MB - 32)
echo "$PART1 is ${PART1_MB}MB"
#check partition layout
echo "check partition layout ..."
vtoycli partresize -c $DISK
vtRet=$?
if [ $vtRet -eq 0 ]; then
exit 1
else
# check and umount
check_umount_disk "$DISK"
sleep 1
check_umount_disk "$DISK"
if [ "$SECUREBOOT" != "YES" ]; then
mkdir ./tmp_mnt
vtdebug "mounting part2 ...."
for tt in 1 2 3 4 5; do
if mount ${PART2} ./tmp_mnt > /dev/null 2>&1; then
vtdebug "mounting part2 success"
break
fi
if [ $vtRet -eq 1 ]; then
echo "Free space enough, start install..."
part2_start_sector=$(expr $PART1_SECTORS + 2048)
elif [ $vtRet -eq 2 ]; then
echo "We need to shrink partition 1 firstly ..."
check_umount_disk "$DISK"
sleep 2
done
rm -f ./tmp_mnt/EFI/BOOT/BOOTX64.EFI
rm -f ./tmp_mnt/EFI/BOOT/grubx64.efi
rm -f ./tmp_mnt/EFI/BOOT/BOOTIA32.EFI
rm -f ./tmp_mnt/EFI/BOOT/grubia32.efi
rm -f ./tmp_mnt/EFI/BOOT/MokManager.efi
rm -f ./tmp_mnt/EFI/BOOT/mmia32.efi
rm -f ./tmp_mnt/ENROLL_THIS_KEY_IN_MOKMANAGER.cer
mv ./tmp_mnt/EFI/BOOT/grubx64_real.efi ./tmp_mnt/EFI/BOOT/BOOTX64.EFI
mv ./tmp_mnt/EFI/BOOT/grubia32_real.efi ./tmp_mnt/EFI/BOOT/BOOTIA32.EFI
sync
for tt in 1 2 3; do
if umount ./tmp_mnt; then
vtdebug "umount part2 success"
rm -rf ./tmp_mnt
break
PART1_BLKID=$(blkid $PART1)
blkid $PART1
if echo $PART1_BLKID | egrep -q -i 'TYPE=ntfs|TYPE=.ntfs'; then
echo "Partition 1 contains NTFS filesystem"
which ntfsresize
if [ $? -ne 0 ]; then
echo "###[FAIL] ntfsresize not found. Please install ntfs-3g package."
exit 1
fi
echo "ntfsfix -b -d $PART1 ..."
ntfsfix -b -d $PART1
echo "ntfsresize --size ${PART1_NEW_MB}Mi $PART1 ..."
ntfsresize -f --size ${PART1_NEW_MB}Mi $PART1
if [ $? -ne 0 ]; then
echo "###[FAIL] ntfsresize failed."
exit 1
fi
elif echo $PART1_BLKID | egrep -q -i 'TYPE=ext[2-4]|TYPE=.ext[2-4]'; then
echo "Partition 1 contains EXT filesystem"
which resize2fs
if [ $? -ne 0 ]; then
echo "###[FAIL] resize2fs not found. Please install e2fsprogs package."
exit 1
fi
echo "e2fsck -f $PART1 ..."
e2fsck -f $PART1
echo "resize2fs $PART1 ${PART1_NEW_MB}M ..."
resize2fs $PART1 ${PART1_NEW_MB}M
if [ $? -ne 0 ]; then
echo "###[FAIL] resize2fs failed."
exit 1
fi
else
vtdebug "umount part2 failed, now retry..."
sleep 1
echo "###[FAIL] Unsupported filesystem in partition 1."
exit 1
fi
done
sync
PART1_NEW_END_MB=$(expr $PART1_NEW_MB + 1)
part2_start_sector=$(expr $PART1_NEW_END_MB \* 2048)
fi
fi
echo ""
vtinfo "Install Ventoy to $DISK successfully finished."
echo ""
vtinfo "writing data to disk part2_start=$part2_start_sector ..."
dd status=none conv=fsync if=./boot/boot.img of=$DISK bs=1 count=440
if [ "$OldStyle" = "GPT" ]; then
echo -en '\x22' | dd status=none of=$DISK conv=fsync bs=1 count=1 seek=92
xzcat ./boot/core.img.xz | dd status=none conv=fsync of=$DISK bs=512 count=2014 seek=34
echo -en '\x23' | dd of=$DISK conv=fsync bs=1 count=1 seek=17908 status=none
else
xzcat ./boot/core.img.xz | dd status=none conv=fsync of=$DISK bs=512 count=2047 seek=1
fi
xzcat ./ventoy/ventoy.disk.img.xz | dd status=none conv=fsync of=$DISK bs=512 count=$VENTOY_SECTOR_NUM seek=$part2_start_sector
#test UUID
testUUIDStr=$(vtoy_gen_uuid | hexdump -C)
vtdebug "test uuid: $testUUIDStr"
#disk uuid
vtoy_gen_uuid | dd status=none conv=fsync of=${DISK} seek=384 bs=1 count=16
vtinfo "sync data ..."
sync
vtinfo "esp partition processing ..."
if [ "$SECUREBOOT" != "YES" ]; then
vtoycli partresize -s $DISK $part2_start_sector
fi
vtinfo "update partition table $DISK $part2_start_sector ..."
vtoycli partresize -p $DISK $part2_start_sector
if [ $? -eq 0 ]; then
sync
echo ""
vtinfo "Ventoy non-destructive installation on $DISK successfully finished."
echo ""
else
echo ""
vterr "Ventoy non-destructive installation on $DISK failed."
echo ""
fi
else
vtdebug "update Ventoy ..."
@ -441,47 +581,13 @@ else
check_umount_disk "$DISK"
xzcat ./ventoy/ventoy.disk.img.xz | dd status=none conv=fsync of=$DISK bs=512 count=$VENTOY_SECTOR_NUM seek=$part2_start
sync
vtinfo "esp partition processing ..."
if [ "$SECUREBOOT" != "YES" ]; then
mkdir ./tmp_mnt
vtdebug "mounting part2 ...."
for tt in 1 2 3 4 5; do
check_umount_disk "$DISK"
if mount ${PART2} ./tmp_mnt > /dev/null 2>&1; then
vtdebug "mounting part2 success"
break
else
vtdebug "mounting part2 failed, now wait and retry..."
fi
sleep 2
done
rm -f ./tmp_mnt/EFI/BOOT/BOOTX64.EFI
rm -f ./tmp_mnt/EFI/BOOT/grubx64.efi
rm -f ./tmp_mnt/EFI/BOOT/BOOTIA32.EFI
rm -f ./tmp_mnt/EFI/BOOT/grubia32.efi
rm -f ./tmp_mnt/EFI/BOOT/MokManager.efi
rm -f ./tmp_mnt/EFI/BOOT/mmia32.efi
rm -f ./tmp_mnt/ENROLL_THIS_KEY_IN_MOKMANAGER.cer
mv ./tmp_mnt/EFI/BOOT/grubx64_real.efi ./tmp_mnt/EFI/BOOT/BOOTX64.EFI
mv ./tmp_mnt/EFI/BOOT/grubia32_real.efi ./tmp_mnt/EFI/BOOT/BOOTIA32.EFI
sync
for tt in 1 2 3; do
if umount ./tmp_mnt > /dev/null 2>&1; then
vtdebug "umount part2 success"
rm -rf ./tmp_mnt
break
else
vtdebug "umount part2 failed, now retry..."
sleep 1
fi
done
sleep 2
check_umount_disk "$DISK"
vtoycli partresize -s $DISK $part2_start
fi
echo ""

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

@ -68,10 +68,10 @@ check_tool_work_ok() {
return
fi
if vtoyfat -T; then
vtdebug "vtoyfat test ok ..."
if vtoycli fat -T; then
vtdebug "vtoycli fat test ok ..."
else
vtdebug "vtoyfat test fail ..."
vtdebug "vtoycli fat test fail ..."
ventoy_false
return
fi
@ -183,7 +183,7 @@ check_disk_secure_boot() {
PART2=$(get_disk_part_name $1 2)
vtoyfat -s $PART2
vtoycli fat -s $PART2
}
get_disk_ventoy_version() {
@ -195,7 +195,7 @@ get_disk_ventoy_version() {
PART2=$(get_disk_part_name $1 2)
ParseVer=$(vtoyfat $PART2)
ParseVer=$(vtoycli fat $PART2)
if [ $? -eq 0 ]; then
vtdebug "Ventoy version in $PART2 is $ParseVer"
echo $ParseVer
@ -391,7 +391,7 @@ format_ventoy_disk_gpt() {
sync
vtoygpt -f $DISK
vtoycli gpt -f $DISK
sync
udevadm trigger --name-match=$DISK >/dev/null 2>&1

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

@ -89,9 +89,9 @@ mkdir -p $tmpmnt/tool
# cp $OPT ./tool/x86_64/mount.exfat-fuse $tmpmnt/tool/mount.exfat-fuse_x86_64
# cp $OPT ./tool/aarch64/mount.exfat-fuse $tmpmnt/tool/mount.exfat-fuse_aarch64
# to save space
cp $OPT ./tool/i386/vtoygpt $tmpmnt/tool/mount.exfat-fuse_i386
cp $OPT ./tool/x86_64/vtoygpt $tmpmnt/tool/mount.exfat-fuse_x86_64
cp $OPT ./tool/aarch64/vtoygpt $tmpmnt/tool/mount.exfat-fuse_aarch64
dd status=none bs=1024 count=16 if=./tool/i386/vtoycli of=$tmpmnt/tool/mount.exfat-fuse_i386
dd status=none bs=1024 count=16 if=./tool/x86_64/vtoycli of=$tmpmnt/tool/mount.exfat-fuse_x86_64
dd status=none bs=1024 count=16 if=./tool/aarch64/vtoycli of=$tmpmnt/tool/mount.exfat-fuse_aarch64
rm -f $tmpmnt/grub/i386-pc/*.img

@ -0,0 +1,37 @@
#!/bin/sh
rm -f vtoycli_64
rm -f vtoycli_32
rm -f vtoycli_aa64
rm -f vtoycli_m64e
SRCS="vtoycli.c vtoyfat.c vtoygpt.c crc32.c partresize.c"
gcc -specs "/usr/local/musl/lib/musl-gcc.specs" -Os -static -D_FILE_OFFSET_BITS=64 $SRCS -Ifat_io_lib/include fat_io_lib/lib/libfat_io_64.a -o vtoycli_64
/opt/diet32/bin/diet -Os gcc -D_FILE_OFFSET_BITS=64 -m32 $SRCS -Ifat_io_lib/include fat_io_lib/lib/libfat_io_32.a -o vtoycli_32
#gcc -O2 -D_FILE_OFFSET_BITS=64 $SRCS -Ifat_io_lib/include fat_io_lib/lib/libfat_io_64.a -o vtoycli_64
#gcc -m32 -O2 -D_FILE_OFFSET_BITS=64 $SRCS -Ifat_io_lib/include fat_io_lib/lib/libfat_io_32.a -o vtoycli_32
aarch64-buildroot-linux-uclibc-gcc -static -O2 -D_FILE_OFFSET_BITS=64 $SRCS -Ifat_io_lib/include fat_io_lib/lib/libfat_io_aa64.a -o vtoycli_aa64
mips64el-linux-musl-gcc -mips64r2 -mabi=64 -static -O2 -D_FILE_OFFSET_BITS=64 $SRCS -Ifat_io_lib/include fat_io_lib/lib/libfat_io_m64e.a -o vtoycli_m64e
if [ -e vtoycli_64 ] && [ -e vtoycli_32 ] && [ -e vtoycli_aa64 ] && [ -e vtoycli_m64e ]; then
echo -e "\n===== success $name =======\n"
strip --strip-all vtoycli_32
strip --strip-all vtoycli_64
aarch64-buildroot-linux-uclibc-strip --strip-all vtoycli_aa64
mips64el-linux-musl-strip --strip-all vtoycli_m64e
[ -d ../INSTALL/tool/i386/ ] && mv vtoycli_32 ../INSTALL/tool/i386/vtoycli
[ -d ../INSTALL/tool/x86_64/ ] && mv vtoycli_64 ../INSTALL/tool/x86_64/vtoycli
[ -d ../INSTALL/tool/aarch64/ ] && mv vtoycli_aa64 ../INSTALL/tool/aarch64/vtoycli
[ -d ../INSTALL/tool/mips64el/ ] && mv vtoycli_m64e ../INSTALL/tool/mips64el/vtoycli
else
echo -e "\n===== failed =======\n"
exit 1
fi

@ -0,0 +1,305 @@
/******************************************************************************
* vtoygpt.c ---- ventoy gpt util
*
* Copyright (c) 2020, longpanda <admin@ventoy.net>
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include <stdio.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define VOID void
#define CHAR char
#define UINT64 unsigned long long
#define UINT32 unsigned int
#define UINT16 unsigned short
#define CHAR16 unsigned short
#define UINT8 unsigned char
UINT32 g_crc_table[256] = {
0x00000000,
0x77073096,
0xEE0E612C,
0x990951BA,
0x076DC419,
0x706AF48F,
0xE963A535,
0x9E6495A3,
0x0EDB8832,
0x79DCB8A4,
0xE0D5E91E,
0x97D2D988,
0x09B64C2B,
0x7EB17CBD,
0xE7B82D07,
0x90BF1D91,
0x1DB71064,
0x6AB020F2,
0xF3B97148,
0x84BE41DE,
0x1ADAD47D,
0x6DDDE4EB,
0xF4D4B551,
0x83D385C7,
0x136C9856,
0x646BA8C0,
0xFD62F97A,
0x8A65C9EC,
0x14015C4F,
0x63066CD9,
0xFA0F3D63,
0x8D080DF5,
0x3B6E20C8,
0x4C69105E,
0xD56041E4,
0xA2677172,
0x3C03E4D1,
0x4B04D447,
0xD20D85FD,
0xA50AB56B,
0x35B5A8FA,
0x42B2986C,
0xDBBBC9D6,
0xACBCF940,
0x32D86CE3,
0x45DF5C75,
0xDCD60DCF,
0xABD13D59,
0x26D930AC,
0x51DE003A,
0xC8D75180,
0xBFD06116,
0x21B4F4B5,
0x56B3C423,
0xCFBA9599,
0xB8BDA50F,
0x2802B89E,
0x5F058808,
0xC60CD9B2,
0xB10BE924,
0x2F6F7C87,
0x58684C11,
0xC1611DAB,
0xB6662D3D,
0x76DC4190,
0x01DB7106,
0x98D220BC,
0xEFD5102A,
0x71B18589,
0x06B6B51F,
0x9FBFE4A5,
0xE8B8D433,
0x7807C9A2,
0x0F00F934,
0x9609A88E,
0xE10E9818,
0x7F6A0DBB,
0x086D3D2D,
0x91646C97,
0xE6635C01,
0x6B6B51F4,
0x1C6C6162,
0x856530D8,
0xF262004E,
0x6C0695ED,
0x1B01A57B,
0x8208F4C1,
0xF50FC457,
0x65B0D9C6,
0x12B7E950,
0x8BBEB8EA,
0xFCB9887C,
0x62DD1DDF,
0x15DA2D49,
0x8CD37CF3,
0xFBD44C65,
0x4DB26158,
0x3AB551CE,
0xA3BC0074,
0xD4BB30E2,
0x4ADFA541,
0x3DD895D7,
0xA4D1C46D,
0xD3D6F4FB,
0x4369E96A,
0x346ED9FC,
0xAD678846,
0xDA60B8D0,
0x44042D73,
0x33031DE5,
0xAA0A4C5F,
0xDD0D7CC9,
0x5005713C,
0x270241AA,
0xBE0B1010,
0xC90C2086,
0x5768B525,
0x206F85B3,
0xB966D409,
0xCE61E49F,
0x5EDEF90E,
0x29D9C998,
0xB0D09822,
0xC7D7A8B4,
0x59B33D17,
0x2EB40D81,
0xB7BD5C3B,
0xC0BA6CAD,
0xEDB88320,
0x9ABFB3B6,
0x03B6E20C,
0x74B1D29A,
0xEAD54739,
0x9DD277AF,
0x04DB2615,
0x73DC1683,
0xE3630B12,
0x94643B84,
0x0D6D6A3E,
0x7A6A5AA8,
0xE40ECF0B,
0x9309FF9D,
0x0A00AE27,
0x7D079EB1,
0xF00F9344,
0x8708A3D2,
0x1E01F268,
0x6906C2FE,
0xF762575D,
0x806567CB,
0x196C3671,
0x6E6B06E7,
0xFED41B76,
0x89D32BE0,
0x10DA7A5A,
0x67DD4ACC,
0xF9B9DF6F,
0x8EBEEFF9,
0x17B7BE43,
0x60B08ED5,
0xD6D6A3E8,
0xA1D1937E,
0x38D8C2C4,
0x4FDFF252,
0xD1BB67F1,
0xA6BC5767,
0x3FB506DD,
0x48B2364B,
0xD80D2BDA,
0xAF0A1B4C,
0x36034AF6,
0x41047A60,
0xDF60EFC3,
0xA867DF55,
0x316E8EEF,
0x4669BE79,
0xCB61B38C,
0xBC66831A,
0x256FD2A0,
0x5268E236,
0xCC0C7795,
0xBB0B4703,
0x220216B9,
0x5505262F,
0xC5BA3BBE,
0xB2BD0B28,
0x2BB45A92,
0x5CB36A04,
0xC2D7FFA7,
0xB5D0CF31,
0x2CD99E8B,
0x5BDEAE1D,
0x9B64C2B0,
0xEC63F226,
0x756AA39C,
0x026D930A,
0x9C0906A9,
0xEB0E363F,
0x72076785,
0x05005713,
0x95BF4A82,
0xE2B87A14,
0x7BB12BAE,
0x0CB61B38,
0x92D28E9B,
0xE5D5BE0D,
0x7CDCEFB7,
0x0BDBDF21,
0x86D3D2D4,
0xF1D4E242,
0x68DDB3F8,
0x1FDA836E,
0x81BE16CD,
0xF6B9265B,
0x6FB077E1,
0x18B74777,
0x88085AE6,
0xFF0F6A70,
0x66063BCA,
0x11010B5C,
0x8F659EFF,
0xF862AE69,
0x616BFFD3,
0x166CCF45,
0xA00AE278,
0xD70DD2EE,
0x4E048354,
0x3903B3C2,
0xA7672661,
0xD06016F7,
0x4969474D,
0x3E6E77DB,
0xAED16A4A,
0xD9D65ADC,
0x40DF0B66,
0x37D83BF0,
0xA9BCAE53,
0xDEBB9EC5,
0x47B2CF7F,
0x30B5FFE9,
0xBDBDF21C,
0xCABAC28A,
0x53B39330,
0x24B4A3A6,
0xBAD03605,
0xCDD70693,
0x54DE5729,
0x23D967BF,
0xB3667A2E,
0xC4614AB8,
0x5D681B02,
0x2A6F2B94,
0xB40BBE37,
0xC30C8EA1,
0x5A05DF1B,
0x2D02EF8D
};
UINT32 VtoyCrc32(VOID *Buffer, UINT32 Length)
{
UINT32 i;
UINT8 *Ptr = Buffer;
UINT32 Crc = 0xFFFFFFFF;
for (i = 0; i < Length; i++, Ptr++)
{
Crc = (Crc >> 8) ^ g_crc_table[(UINT8) Crc ^ *Ptr];
}
return Crc ^ 0xffffffff;
}

@ -0,0 +1,35 @@
#!/bin/sh
rm -rf include
rm -rf lib
cd release
#/opt/diet64/bin/diet -Os gcc -O2 -D_FILE_OFFSET_BITS=64 fat*.c -c
gcc -specs "/usr/local/musl/lib/musl-gcc.specs" -O2 -D_FILE_OFFSET_BITS=64 fat*.c -c
ar -rc libfat_io_64.a *.o
rm -f *.o
gcc -m32 -O2 -D_FILE_OFFSET_BITS=64 fat*.c -c
ar -rc libfat_io_32.a *.o
rm -f *.o
aarch64-linux-gnu-gcc -O2 -D_FILE_OFFSET_BITS=64 fat*.c -c
ar -rc libfat_io_aa64.a *.o
rm -f *.o
mips64el-linux-musl-gcc -mips64r2 -mabi=64 -O2 -D_FILE_OFFSET_BITS=64 fat*.c -c
ar -rc libfat_io_m64e.a *.o
rm -f *.o
cd -
mkdir lib
mkdir include
mv release/*.a lib/
cp -a release/*.h include/

@ -0,0 +1,133 @@
#ifndef __FAT_ACCESS_H__
#define __FAT_ACCESS_H__
#include "fat_defs.h"
#include "fat_opts.h"
//-----------------------------------------------------------------------------
// Defines
//-----------------------------------------------------------------------------
#define FAT_INIT_OK 0
#define FAT_INIT_MEDIA_ACCESS_ERROR (-1)
#define FAT_INIT_INVALID_SECTOR_SIZE (-2)
#define FAT_INIT_INVALID_SIGNATURE (-3)
#define FAT_INIT_ENDIAN_ERROR (-4)
#define FAT_INIT_WRONG_FILESYS_TYPE (-5)
#define FAT_INIT_WRONG_PARTITION_TYPE (-6)
#define FAT_INIT_STRUCT_PACKING (-7)
#define FAT_DIR_ENTRIES_PER_SECTOR (FAT_SECTOR_SIZE / FAT_DIR_ENTRY_SIZE)
//-----------------------------------------------------------------------------
// Function Pointers
//-----------------------------------------------------------------------------
typedef int (*fn_diskio_read) (uint32 sector, uint8 *buffer, uint32 sector_count);
typedef int (*fn_diskio_write)(uint32 sector, uint8 *buffer, uint32 sector_count);
//-----------------------------------------------------------------------------
// Structures
//-----------------------------------------------------------------------------
struct disk_if
{
// User supplied function pointers for disk IO
fn_diskio_read read_media;
fn_diskio_write write_media;
};
// Forward declaration
struct fat_buffer;
struct fat_buffer
{
uint8 sector[FAT_SECTOR_SIZE * FAT_BUFFER_SECTORS];
uint32 address;
int dirty;
uint8 * ptr;
// Next in chain of sector buffers
struct fat_buffer *next;
};
typedef enum eFatType
{
FAT_TYPE_16,
FAT_TYPE_32
} tFatType;
struct fatfs
{
// Filesystem globals
uint8 sectors_per_cluster;
uint32 cluster_begin_lba;
uint32 rootdir_first_cluster;
uint32 rootdir_first_sector;
uint32 rootdir_sectors;
uint32 fat_begin_lba;
uint16 fs_info_sector;
uint32 lba_begin;
uint32 fat_sectors;
uint32 next_free_cluster;
uint16 root_entry_count;
uint16 reserved_sectors;
uint8 num_of_fats;
tFatType fat_type;
// Disk/Media API
struct disk_if disk_io;
// [Optional] Thread Safety
void (*fl_lock)(void);
void (*fl_unlock)(void);
// Working buffer
struct fat_buffer currentsector;
// FAT Buffer
struct fat_buffer *fat_buffer_head;
struct fat_buffer fat_buffers[FAT_BUFFERS];
};
struct fs_dir_list_status
{
uint32 sector;
uint32 cluster;
uint8 offset;
};
struct fs_dir_ent
{
char filename[FATFS_MAX_LONG_FILENAME];
uint8 is_dir;
uint32 cluster;
uint32 size;
#if FATFS_INC_TIME_DATE_SUPPORT
uint16 access_date;
uint16 write_time;
uint16 write_date;
uint16 create_date;
uint16 create_time;
#endif
};
//-----------------------------------------------------------------------------
// Prototypes
//-----------------------------------------------------------------------------
int fatfs_init(struct fatfs *fs);
uint32 fatfs_lba_of_cluster(struct fatfs *fs, uint32 Cluster_Number);
int fatfs_sector_reader(struct fatfs *fs, uint32 Startcluster, uint32 offset, uint8 *target);
int fatfs_sector_read(struct fatfs *fs, uint32 lba, uint8 *target, uint32 count);
int fatfs_sector_write(struct fatfs *fs, uint32 lba, uint8 *target, uint32 count);
int fatfs_read_sector(struct fatfs *fs, uint32 cluster, uint32 sector, uint8 *target);
int fatfs_write_sector(struct fatfs *fs, uint32 cluster, uint32 sector, uint8 *target);
void fatfs_show_details(struct fatfs *fs);
uint32 fatfs_get_root_cluster(struct fatfs *fs);
uint32 fatfs_get_file_entry(struct fatfs *fs, uint32 Cluster, char *nametofind, struct fat_dir_entry *sfEntry);
int fatfs_sfn_exists(struct fatfs *fs, uint32 Cluster, char *shortname);
int fatfs_update_file_length(struct fatfs *fs, uint32 Cluster, char *shortname, uint32 fileLength);
int fatfs_mark_file_deleted(struct fatfs *fs, uint32 Cluster, char *shortname);
void fatfs_list_directory_start(struct fatfs *fs, struct fs_dir_list_status *dirls, uint32 StartCluster);
int fatfs_list_directory_next(struct fatfs *fs, struct fs_dir_list_status *dirls, struct fs_dir_ent *entry);
int fatfs_update_timestamps(struct fat_dir_entry *directoryEntry, int create, int modify, int access);
#endif

@ -0,0 +1,13 @@
#ifndef __FAT_CACHE_H__
#define __FAT_CACHE_H__
#include "fat_filelib.h"
//-----------------------------------------------------------------------------
// Prototypes
//-----------------------------------------------------------------------------
int fatfs_cache_init(struct fatfs *fs, FL_FILE *file);
int fatfs_cache_get_next_cluster(struct fatfs *fs, FL_FILE *file, uint32 clusterIdx, uint32 *pNextCluster);
int fatfs_cache_set_next_cluster(struct fatfs *fs, FL_FILE *file, uint32 clusterIdx, uint32 nextCluster);
#endif

@ -0,0 +1,128 @@
#ifndef __FAT_DEFS_H__
#define __FAT_DEFS_H__
#include "fat_opts.h"
#include "fat_types.h"
//-----------------------------------------------------------------------------
// FAT32 Offsets
// Name Offset
//-----------------------------------------------------------------------------
// Boot Sector
#define BS_JMPBOOT 0 // Length = 3
#define BS_OEMNAME 3 // Length = 8
#define BPB_BYTSPERSEC 11 // Length = 2
#define BPB_SECPERCLUS 13 // Length = 1
#define BPB_RSVDSECCNT 14 // Length = 2
#define BPB_NUMFATS 16 // Length = 1
#define BPB_ROOTENTCNT 17 // Length = 2
#define BPB_TOTSEC16 19 // Length = 2
#define BPB_MEDIA 21 // Length = 1
#define BPB_FATSZ16 22 // Length = 2
#define BPB_SECPERTRK 24 // Length = 2
#define BPB_NUMHEADS 26 // Length = 2
#define BPB_HIDDSEC 28 // Length = 4
#define BPB_TOTSEC32 32 // Length = 4
// FAT 12/16
#define BS_FAT_DRVNUM 36 // Length = 1
#define BS_FAT_BOOTSIG 38 // Length = 1
#define BS_FAT_VOLID 39 // Length = 4
#define BS_FAT_VOLLAB 43 // Length = 11
#define BS_FAT_FILSYSTYPE 54 // Length = 8
// FAT 32
#define BPB_FAT32_FATSZ32 36 // Length = 4
#define BPB_FAT32_EXTFLAGS 40 // Length = 2
#define BPB_FAT32_FSVER 42 // Length = 2
#define BPB_FAT32_ROOTCLUS 44 // Length = 4
#define BPB_FAT32_FSINFO 48 // Length = 2
#define BPB_FAT32_BKBOOTSEC 50 // Length = 2
#define BS_FAT32_DRVNUM 64 // Length = 1
#define BS_FAT32_BOOTSIG 66 // Length = 1
#define BS_FAT32_VOLID 67 // Length = 4
#define BS_FAT32_VOLLAB 71 // Length = 11
#define BS_FAT32_FILSYSTYPE 82 // Length = 8
//-----------------------------------------------------------------------------
// FAT Types
//-----------------------------------------------------------------------------
#define FAT_TYPE_FAT12 1
#define FAT_TYPE_FAT16 2
#define FAT_TYPE_FAT32 3
//-----------------------------------------------------------------------------
// FAT32 Specific Statics
//-----------------------------------------------------------------------------
#define SIGNATURE_POSITION 510
#define SIGNATURE_VALUE 0xAA55
#define PARTITION1_TYPECODE_LOCATION 450
#define FAT32_TYPECODE1 0x0B
#define FAT32_TYPECODE2 0x0C
#define PARTITION1_LBA_BEGIN_LOCATION 454
#define PARTITION1_SIZE_LOCATION 458
#define FAT_DIR_ENTRY_SIZE 32
#define FAT_SFN_SIZE_FULL 11
#define FAT_SFN_SIZE_PARTIAL 8
//-----------------------------------------------------------------------------
// FAT32 File Attributes and Types
//-----------------------------------------------------------------------------
#define FILE_ATTR_READ_ONLY 0x01
#define FILE_ATTR_HIDDEN 0x02
#define FILE_ATTR_SYSTEM 0x04
#define FILE_ATTR_SYSHID 0x06
#define FILE_ATTR_VOLUME_ID 0x08
#define FILE_ATTR_DIRECTORY 0x10
#define FILE_ATTR_ARCHIVE 0x20
#define FILE_ATTR_LFN_TEXT 0x0F
#define FILE_HEADER_BLANK 0x00
#define FILE_HEADER_DELETED 0xE5
#define FILE_TYPE_DIR 0x10
#define FILE_TYPE_FILE 0x20
//-----------------------------------------------------------------------------
// Time / Date details
//-----------------------------------------------------------------------------
#define FAT_TIME_HOURS_SHIFT 11
#define FAT_TIME_HOURS_MASK 0x1F
#define FAT_TIME_MINUTES_SHIFT 5
#define FAT_TIME_MINUTES_MASK 0x3F
#define FAT_TIME_SECONDS_SHIFT 0
#define FAT_TIME_SECONDS_MASK 0x1F
#define FAT_TIME_SECONDS_SCALE 2
#define FAT_DATE_YEAR_SHIFT 9
#define FAT_DATE_YEAR_MASK 0x7F
#define FAT_DATE_MONTH_SHIFT 5
#define FAT_DATE_MONTH_MASK 0xF
#define FAT_DATE_DAY_SHIFT 0
#define FAT_DATE_DAY_MASK 0x1F
#define FAT_DATE_YEAR_OFFSET 1980
//-----------------------------------------------------------------------------
// Other Defines
//-----------------------------------------------------------------------------
#define FAT32_LAST_CLUSTER 0xFFFFFFFF
#define FAT32_INVALID_CLUSTER 0xFFFFFFFF
STRUCT_PACK_BEGIN
struct fat_dir_entry STRUCT_PACK
{
uint8 Name[11];
uint8 Attr;
uint8 NTRes;
uint8 CrtTimeTenth;
uint8 CrtTime[2];
uint8 CrtDate[2];
uint8 LstAccDate[2];
uint16 FstClusHI;
uint8 WrtTime[2];
uint8 WrtDate[2];
uint16 FstClusLO;
uint32 FileSize;
} STRUCT_PACKED;
STRUCT_PACK_END
#endif

@ -0,0 +1,146 @@
#ifndef __FAT_FILELIB_H__
#define __FAT_FILELIB_H__
#include "fat_opts.h"
#include "fat_access.h"
#include "fat_list.h"
//-----------------------------------------------------------------------------
// Defines
//-----------------------------------------------------------------------------
#ifndef SEEK_CUR
#define SEEK_CUR 1
#endif
#ifndef SEEK_END
#define SEEK_END 2
#endif
#ifndef SEEK_SET
#define SEEK_SET 0
#endif
#ifndef EOF
#define EOF (-1)
#endif
//-----------------------------------------------------------------------------
// Structures
//-----------------------------------------------------------------------------
struct sFL_FILE;
struct cluster_lookup
{
uint32 ClusterIdx;
uint32 CurrentCluster;
};
typedef struct sFL_FILE
{
uint32 parentcluster;
uint32 startcluster;
uint32 bytenum;
uint32 filelength;
int filelength_changed;
char path[FATFS_MAX_LONG_FILENAME];
char filename[FATFS_MAX_LONG_FILENAME];
uint8 shortfilename[11];
#ifdef FAT_CLUSTER_CACHE_ENTRIES
uint32 cluster_cache_idx[FAT_CLUSTER_CACHE_ENTRIES];
uint32 cluster_cache_data[FAT_CLUSTER_CACHE_ENTRIES];
#endif
// Cluster Lookup
struct cluster_lookup last_fat_lookup;
// Read/Write sector buffer
uint8 file_data_sector[FAT_SECTOR_SIZE];
uint32 file_data_address;
int file_data_dirty;
// File fopen flags
uint8 flags;
#define FILE_READ (1 << 0)
#define FILE_WRITE (1 << 1)
#define FILE_APPEND (1 << 2)
#define FILE_BINARY (1 << 3)
#define FILE_ERASE (1 << 4)
#define FILE_CREATE (1 << 5)
struct fat_node list_node;
} FL_FILE;
//-----------------------------------------------------------------------------
// Prototypes
//-----------------------------------------------------------------------------
// External
void fl_init(void);
void fl_attach_locks(void (*lock)(void), void (*unlock)(void));
int fl_attach_media(fn_diskio_read rd, fn_diskio_write wr);
void fl_shutdown(void);
// Standard API
void* fl_fopen(const char *path, const char *modifiers);
void fl_fclose(void *file);
int fl_fflush(void *file);
int fl_fgetc(void *file);
char * fl_fgets(char *s, int n, void *f);
int fl_fputc(int c, void *file);
int fl_fputs(const char * str, void *file);
int fl_fwrite(const void * data, int size, int count, void *file );
int fl_fread(void * data, int size, int count, void *file );
int fl_fseek(void *file , long offset , int origin );
int fl_fgetpos(void *file , uint32 * position);
long fl_ftell(void *f);
int fl_feof(void *f);
int fl_remove(const char * filename);
// Equivelant dirent.h
typedef struct fs_dir_list_status FL_DIR;
typedef struct fs_dir_ent fl_dirent;
FL_DIR* fl_opendir(const char* path, FL_DIR *dir);
int fl_readdir(FL_DIR *dirls, fl_dirent *entry);
int fl_closedir(FL_DIR* dir);
// Extensions
void fl_listdirectory(const char *path);
int fl_createdirectory(const char *path);
int fl_is_dir(const char *path);
int fl_format(uint32 volume_sectors, const char *name);
// Test hooks
#ifdef FATFS_INC_TEST_HOOKS
struct fatfs* fl_get_fs(void);
#endif
//-----------------------------------------------------------------------------
// Stdio file I/O names
//-----------------------------------------------------------------------------
#ifdef USE_FILELIB_STDIO_COMPAT_NAMES
#define FILE FL_FILE
#define fopen(a,b) fl_fopen(a, b)
#define fclose(a) fl_fclose(a)
#define fflush(a) fl_fflush(a)
#define fgetc(a) fl_fgetc(a)
#define fgets(a,b,c) fl_fgets(a, b, c)
#define fputc(a,b) fl_fputc(a, b)
#define fputs(a,b) fl_fputs(a, b)
#define fwrite(a,b,c,d) fl_fwrite(a, b, c, d)
#define fread(a,b,c,d) fl_fread(a, b, c, d)
#define fseek(a,b,c) fl_fseek(a, b, c)
#define fgetpos(a,b) fl_fgetpos(a, b)
#define ftell(a) fl_ftell(a)
#define feof(a) fl_feof(a)
#define remove(a) fl_remove(a)
#define mkdir(a) fl_createdirectory(a)
#define rmdir(a) 0
#endif
#endif

@ -0,0 +1,15 @@
#ifndef __FAT_FORMAT_H__
#define __FAT_FORMAT_H__
#include "fat_defs.h"
#include "fat_opts.h"
#include "fat_access.h"
//-----------------------------------------------------------------------------
// Prototypes
//-----------------------------------------------------------------------------
int fatfs_format(struct fatfs *fs, uint32 volume_sectors, const char *name);
int fatfs_format_fat16(struct fatfs *fs, uint32 volume_sectors, const char *name);
int fatfs_format_fat32(struct fatfs *fs, uint32 volume_sectors, const char *name);
#endif

@ -0,0 +1,161 @@
#ifndef __FAT_LIST_H__
#define __FAT_LIST_H__
#ifndef FAT_ASSERT
#define FAT_ASSERT(x)
#endif
#ifndef FAT_INLINE
#define FAT_INLINE
#endif
//-----------------------------------------------------------------
// Types
//-----------------------------------------------------------------
struct fat_list;
struct fat_node
{
struct fat_node *previous;
struct fat_node *next;
};
struct fat_list
{
struct fat_node *head;
struct fat_node *tail;
};
//-----------------------------------------------------------------
// Macros
//-----------------------------------------------------------------
#define fat_list_entry(p, t, m) p ? ((t *)((char *)(p)-(char*)(&((t *)0)->m))) : 0
#define fat_list_next(l, p) (p)->next
#define fat_list_prev(l, p) (p)->previous
#define fat_list_first(l) (l)->head
#define fat_list_last(l) (l)->tail
#define fat_list_for_each(l, p) for ((p) = (l)->head; (p); (p) = (p)->next)
//-----------------------------------------------------------------
// Inline Functions
//-----------------------------------------------------------------
//-----------------------------------------------------------------
// fat_list_init:
//-----------------------------------------------------------------
static FAT_INLINE void fat_list_init(struct fat_list *list)
{
FAT_ASSERT(list);
list->head = list->tail = 0;
}
//-----------------------------------------------------------------
// fat_list_remove:
//-----------------------------------------------------------------
static FAT_INLINE void fat_list_remove(struct fat_list *list, struct fat_node *node)
{
FAT_ASSERT(list);
FAT_ASSERT(node);
if(!node->previous)
list->head = node->next;
else
node->previous->next = node->next;
if(!node->next)
list->tail = node->previous;
else
node->next->previous = node->previous;
}
//-----------------------------------------------------------------
// fat_list_insert_after:
//-----------------------------------------------------------------
static FAT_INLINE void fat_list_insert_after(struct fat_list *list, struct fat_node *node, struct fat_node *new_node)
{
FAT_ASSERT(list);
FAT_ASSERT(node);
FAT_ASSERT(new_node);
new_node->previous = node;
new_node->next = node->next;
if (!node->next)
list->tail = new_node;
else
node->next->previous = new_node;
node->next = new_node;
}
//-----------------------------------------------------------------
// fat_list_insert_before:
//-----------------------------------------------------------------
static FAT_INLINE void fat_list_insert_before(struct fat_list *list, struct fat_node *node, struct fat_node *new_node)
{
FAT_ASSERT(list);
FAT_ASSERT(node);
FAT_ASSERT(new_node);
new_node->previous = node->previous;
new_node->next = node;
if (!node->previous)
list->head = new_node;
else
node->previous->next = new_node;
node->previous = new_node;
}
//-----------------------------------------------------------------
// fat_list_insert_first:
//-----------------------------------------------------------------
static FAT_INLINE void fat_list_insert_first(struct fat_list *list, struct fat_node *node)
{
FAT_ASSERT(list);
FAT_ASSERT(node);
if (!list->head)
{
list->head = node;
list->tail = node;
node->previous = 0;
node->next = 0;
}
else
fat_list_insert_before(list, list->head, node);
}
//-----------------------------------------------------------------
// fat_list_insert_last:
//-----------------------------------------------------------------
static FAT_INLINE void fat_list_insert_last(struct fat_list *list, struct fat_node *node)
{
FAT_ASSERT(list);
FAT_ASSERT(node);
if (!list->tail)
fat_list_insert_first(list, node);
else
fat_list_insert_after(list, list->tail, node);
}
//-----------------------------------------------------------------
// fat_list_is_empty:
//-----------------------------------------------------------------
static FAT_INLINE int fat_list_is_empty(struct fat_list *list)
{
FAT_ASSERT(list);
return !list->head;
}
//-----------------------------------------------------------------
// fat_list_pop_head:
//-----------------------------------------------------------------
static FAT_INLINE struct fat_node * fat_list_pop_head(struct fat_list *list)
{
struct fat_node * node;
FAT_ASSERT(list);
node = fat_list_first(list);
if (node)
fat_list_remove(list, node);
return node;
}
#endif

@ -0,0 +1,63 @@
#ifndef __FAT_MISC_H__
#define __FAT_MISC_H__
#include "fat_defs.h"
#include "fat_opts.h"
//-----------------------------------------------------------------------------
// Defines
//-----------------------------------------------------------------------------
#define MAX_LONGFILENAME_ENTRIES 20
#define MAX_LFN_ENTRY_LENGTH 13
//-----------------------------------------------------------------------------
// Macros
//-----------------------------------------------------------------------------
#define GET_32BIT_WORD(buffer, location) ( ((uint32)buffer[location+3]<<24) + ((uint32)buffer[location+2]<<16) + ((uint32)buffer[location+1]<<8) + (uint32)buffer[location+0] )
#define GET_16BIT_WORD(buffer, location) ( ((uint16)buffer[location+1]<<8) + (uint16)buffer[location+0] )
#define SET_32BIT_WORD(buffer, location, value) { buffer[location+0] = (uint8)((value)&0xFF); \
buffer[location+1] = (uint8)((value>>8)&0xFF); \
buffer[location+2] = (uint8)((value>>16)&0xFF); \
buffer[location+3] = (uint8)((value>>24)&0xFF); }
#define SET_16BIT_WORD(buffer, location, value) { buffer[location+0] = (uint8)((value)&0xFF); \
buffer[location+1] = (uint8)((value>>8)&0xFF); }
//-----------------------------------------------------------------------------
// Structures
//-----------------------------------------------------------------------------
struct lfn_cache
{
#if FATFS_INC_LFN_SUPPORT
// Long File Name Structure (max 260 LFN length)
uint8 String[MAX_LONGFILENAME_ENTRIES][MAX_LFN_ENTRY_LENGTH];
uint8 Null;
#endif
uint8 no_of_strings;
};
//-----------------------------------------------------------------------------
// Prototypes
//-----------------------------------------------------------------------------
void fatfs_lfn_cache_init(struct lfn_cache *lfn, int wipeTable);
void fatfs_lfn_cache_entry(struct lfn_cache *lfn, uint8 *entryBuffer);
char* fatfs_lfn_cache_get(struct lfn_cache *lfn);
int fatfs_entry_lfn_text(struct fat_dir_entry *entry);
int fatfs_entry_lfn_invalid(struct fat_dir_entry *entry);
int fatfs_entry_lfn_exists(struct lfn_cache *lfn, struct fat_dir_entry *entry);
int fatfs_entry_sfn_only(struct fat_dir_entry *entry);
int fatfs_entry_is_dir(struct fat_dir_entry *entry);
int fatfs_entry_is_file(struct fat_dir_entry *entry);
int fatfs_lfn_entries_required(char *filename);
void fatfs_filename_to_lfn(char *filename, uint8 *buffer, int entry, uint8 sfnChk);
void fatfs_sfn_create_entry(char *shortfilename, uint32 size, uint32 startCluster, struct fat_dir_entry *entry, int dir);
int fatfs_lfn_create_sfn(char *sfn_output, char *filename);
int fatfs_lfn_generate_tail(char *sfn_output, char *sfn_input, uint32 tailNum);
void fatfs_convert_from_fat_time(uint16 fat_time, int *hours, int *minutes, int *seconds);
void fatfs_convert_from_fat_date(uint16 fat_date, int *day, int *month, int *year);
uint16 fatfs_convert_to_fat_time(int hours, int minutes, int seconds);
uint16 fatfs_convert_to_fat_date(int day, int month, int year);
void fatfs_print_sector(uint32 sector, uint8 *data);
#endif

@ -0,0 +1,90 @@
#ifndef __FAT_OPTS_H__
#define __FAT_OPTS_H__
#ifdef FATFS_USE_CUSTOM_OPTS_FILE
#include "fat_custom.h"
#endif
//-------------------------------------------------------------
// Configuration
//-------------------------------------------------------------
// Is the processor little endian (1) or big endian (0)
#ifndef FATFS_IS_LITTLE_ENDIAN
#define FATFS_IS_LITTLE_ENDIAN 1
#endif
// Max filename Length
#ifndef FATFS_MAX_LONG_FILENAME
#define FATFS_MAX_LONG_FILENAME 260
#endif
// Max open files (reduce to lower memory requirements)
#ifndef FATFS_MAX_OPEN_FILES
#define FATFS_MAX_OPEN_FILES 2
#endif
// Number of sectors per FAT_BUFFER (min 1)
#ifndef FAT_BUFFER_SECTORS
#define FAT_BUFFER_SECTORS 1
#endif
// Max FAT sectors to buffer (min 1)
// (mem used is FAT_BUFFERS * FAT_BUFFER_SECTORS * FAT_SECTOR_SIZE)
#ifndef FAT_BUFFERS
#define FAT_BUFFERS 1
#endif
// Size of cluster chain cache (can be undefined)
// Mem used = FAT_CLUSTER_CACHE_ENTRIES * 4 * 2
// Improves access speed considerably
//#define FAT_CLUSTER_CACHE_ENTRIES 128
// Include support for writing files (1 / 0)?
#ifndef FATFS_INC_WRITE_SUPPORT
#define FATFS_INC_WRITE_SUPPORT 1
#endif
// Support long filenames (1 / 0)?
// (if not (0) only 8.3 format is supported)
#ifndef FATFS_INC_LFN_SUPPORT
#define FATFS_INC_LFN_SUPPORT 1
#endif
// Support directory listing (1 / 0)?
#ifndef FATFS_DIR_LIST_SUPPORT
#define FATFS_DIR_LIST_SUPPORT 1
#endif
// Support time/date (1 / 0)?
#ifndef FATFS_INC_TIME_DATE_SUPPORT
#define FATFS_INC_TIME_DATE_SUPPORT 0
#endif
// Include support for formatting disks (1 / 0)?
#ifndef FATFS_INC_FORMAT_SUPPORT
#define FATFS_INC_FORMAT_SUPPORT 1
#endif
// Sector size used
#define FAT_SECTOR_SIZE 512
// Printf output (directory listing / debug)
#ifndef FAT_PRINTF
// Don't include stdio, but there is a printf function available
#ifdef FAT_PRINTF_NOINC_STDIO
extern int printf(const char* ctrl1, ... );
#define FAT_PRINTF(a) printf a
// Include stdio to use printf
#else
#include <stdio.h>
#define FAT_PRINTF(a) printf a
#endif
#endif
// Time/Date support requires time.h
#if FATFS_INC_TIME_DATE_SUPPORT
#include <time.h>
#endif
#endif

@ -0,0 +1,20 @@
#ifndef __FILESTRING_H__
#define __FILESTRING_H__
//-----------------------------------------------------------------------------
// Prototypes
//-----------------------------------------------------------------------------
int fatfs_total_path_levels(char *path);
int fatfs_get_substring(char *Path, int levelreq, char *output, int max_len);
int fatfs_split_path(char *FullPath, char *Path, int max_path, char *FileName, int max_filename);
int fatfs_compare_names(char* strA, char* strB);
int fatfs_string_ends_with_slash(char *path);
int fatfs_get_sfn_display_name(char* out, char* in);
int fatfs_get_extension(char* filename, char* out, int maxlen);
int fatfs_create_path_string(char* path, char *filename, char* out, int maxlen);
#ifndef NULL
#define NULL 0
#endif
#endif

@ -0,0 +1,20 @@
#ifndef __FAT_TABLE_H__
#define __FAT_TABLE_H__
#include "fat_opts.h"
#include "fat_misc.h"
//-----------------------------------------------------------------------------
// Prototypes
//-----------------------------------------------------------------------------
void fatfs_fat_init(struct fatfs *fs);
int fatfs_fat_purge(struct fatfs *fs);
uint32 fatfs_find_next_cluster(struct fatfs *fs, uint32 current_cluster);
void fatfs_set_fs_info_next_free_cluster(struct fatfs *fs, uint32 newValue);
int fatfs_find_blank_cluster(struct fatfs *fs, uint32 start_cluster, uint32 *free_cluster);
int fatfs_fat_set_cluster(struct fatfs *fs, uint32 cluster, uint32 next_cluster);
int fatfs_fat_add_cluster_to_chain(struct fatfs *fs, uint32 start_cluster, uint32 newEntry);
int fatfs_free_cluster_chain(struct fatfs *fs, uint32 start_cluster);
uint32 fatfs_count_free_clusters(struct fatfs *fs);
#endif

@ -0,0 +1,69 @@
#ifndef __FAT_TYPES_H__
#define __FAT_TYPES_H__
// Detect 64-bit compilation on GCC
#if defined(__GNUC__) && defined(__SIZEOF_LONG__)
#if __SIZEOF_LONG__ == 8
#define FATFS_DEF_UINT32_AS_INT
#endif
#endif
//-------------------------------------------------------------
// System specific types
//-------------------------------------------------------------
#ifndef FATFS_NO_DEF_TYPES
typedef unsigned char uint8;
typedef unsigned short uint16;
// If compiling on a 64-bit machine, use int as 32-bits
#ifdef FATFS_DEF_UINT32_AS_INT
typedef unsigned int uint32;
// Else for 32-bit machines & embedded systems, use long...
#else
typedef unsigned long uint32;
#endif
#endif
#ifndef NULL
#define NULL 0
#endif
//-------------------------------------------------------------
// Endian Macros
//-------------------------------------------------------------
// FAT is little endian so big endian systems need to swap words
// Little Endian - No swap required
#if FATFS_IS_LITTLE_ENDIAN == 1
#define FAT_HTONS(n) (n)
#define FAT_HTONL(n) (n)
// Big Endian - Swap required
#else
#define FAT_HTONS(n) ((((uint16)((n) & 0xff)) << 8) | (((n) & 0xff00) >> 8))
#define FAT_HTONL(n) (((((uint32)(n) & 0xFF)) << 24) | \
((((uint32)(n) & 0xFF00)) << 8) | \
((((uint32)(n) & 0xFF0000)) >> 8) | \
((((uint32)(n) & 0xFF000000)) >> 24))
#endif
//-------------------------------------------------------------
// Structure Packing Compile Options
//-------------------------------------------------------------
#ifdef __GNUC__
#define STRUCT_PACK
#define STRUCT_PACK_BEGIN
#define STRUCT_PACK_END
#define STRUCT_PACKED __attribute__ ((packed))
#else
// Other compilers may require other methods of packing structures
#define STRUCT_PACK
#define STRUCT_PACK_BEGIN
#define STRUCT_PACK_END
#define STRUCT_PACKED
#endif
#endif

@ -0,0 +1,14 @@
#ifndef __FAT_WRITE_H__
#define __FAT_WRITE_H__
#include "fat_defs.h"
#include "fat_opts.h"
//-----------------------------------------------------------------------------
// Prototypes
//-----------------------------------------------------------------------------
int fatfs_add_file_entry(struct fatfs *fs, uint32 dirCluster, char *filename, char *shortfilename, uint32 startCluster, uint32 size, int dir);
int fatfs_add_free_space(struct fatfs *fs, uint32 *startCluster, uint32 clusters);
int fatfs_allocate_free_space(struct fatfs *fs, int newFile, uint32 *startCluster, uint32 size);
#endif

@ -0,0 +1,22 @@
File IO Lib API
-=-=-=-=-=-=-=-=-
void fl_init(void)
Called to initialize FAT IO library.
This should be called prior to any other functions.
void fl_attach_locks(void (*lock)(void), void (*unlock)(void))
[Optional] File system thread safety locking functions.
For thread safe operation, you should provide lock() and unlock() functions.
Note that locking primitive used must support recursive locking, i.e lock() called within an already locked region.
int fl_attach_media(fn_diskio_read rd, fn_diskio_write wr)
This function is used to attach system specific disk/media access functions.
This should be done subsequent to calling fl_init() and fl_attach_locks() (if locking required).
void fl_shutdown(void)
Shutdown the FAT IO library. This purges any un-saved data back to disk.

@ -0,0 +1,345 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General
Public License instead of this License.

@ -0,0 +1,53 @@
File IO Lib Options
-=-=-=-=-=-=-=-=-=-
See defines in fat_opts.h:
FATFS_IS_LITTLE_ENDIAN [1/0]
Which endian is your system? Set to 1 for little endian, 0 for big endian.
FATFS_MAX_LONG_FILENAME [260]
By default, 260 characters (max LFN length). Increase this to support greater path depths.
FATFS_MAX_OPEN_FILES
The more files you wish to have concurrently open, the greater this number should be.
This increases the number of FL_FILE file structures in the library, each of these is around 1K in size (assuming 512 byte sectors).
FAT_BUFFER_SECTORS
Minimum is 1, more increases performance.
This defines how many FAT sectors can be buffered per FAT_BUFFER entry.
FAT_BUFFERS
Minimum is 1, more increases performance.
This defines how many FAT buffer entries are available.
Memory usage is FAT_BUFFERS * FAT_BUFFER_SECTORS * FAT_SECTOR_SIZE
FATFS_INC_WRITE_SUPPORT
Support file write functionality.
FAT_SECTOR_SIZE
Sector size used by buffers. Most likely to be 512 bytes (standard for ATA/IDE).
FAT_PRINTF
A define that allows the File IO library to print to console/stdout.
Provide your own printf function if printf not available.
FAT_CLUSTER_CACHE_ENTRIES
Size of cluster chain cache (can be undefined if not required).
Mem used = FAT_CLUSTER_CACHE_ENTRIES * 4 * 2
Improves access speed considerably.
FATFS_INC_LFN_SUPPORT [1/0]
Enable/Disable support for long filenames.
FATFS_DIR_LIST_SUPPORT [1/0]
Include support for directory listing.
FATFS_INC_TIME_DATE_SUPPORT [1/0]
Use time/date functions provided by time.h to update creation & modification timestamps.
FATFS_INC_FORMAT_SUPPORT
Include support for formatting disks (FAT16 only).
FAT_PRINTF_NOINC_STDIO
Disable use of printf & inclusion of stdio.h

@ -0,0 +1,24 @@
Revision History
-=-=-=-=-=-=-=-=-
v2.6.11 - Fix compilation with GCC on 64-bit machines
v2.6.10 - Added support for FAT32 format.
V2.6.9 - Added support for time & date handling.
V2.6.8 - Fixed error with FSINFO sector write.
V2.6.7 - Added fgets().
Fixed C warnings, removed dependancy on some string.h functions.
V2.6.6 Massive read + write performance improvements.
V2.6.5 Bug fixes for big endian systems.
V2.6.4 Further bug fixes and performance improvements for write operations.
V2.6.3 Peformance improvements, FAT16 formatting support. Various bug fixes.
V2.6 - Basic support for FAT16 added (18-04-10).
V2.5 - Code cleaned up. Many bugs fixed. Thread safety functions added.
V2.x - Write support added as well as better stdio like API.
V1.0 - Rewrite of all code to enable multiple files to be opened and provides a
better file API.
Also better string matching, and generally better C code than origonal
version.
V0.1c - Fetch_ID_Max_LBA() function added to retrieve Drive infomation and stoping
the drive reads from addressing a sector that is out of range.
V0.1b - fopen(), fgetc(), fopenDIR() using new software stack for IDE and FAT32
access.
V0.1a - First release (27/12/03); fopen(), fgetc() unbuffered reads.

@ -0,0 +1,10 @@
FAT File IO Library License
-=-=-=-=-=-=-=-=-=-=-=-=-=-
This versions license: GPL
If you include GPL software in your project, you must release the source code of that project too.
If you would like a version with a more permissive license for use in closed source commercial applications please contact me for details.
Email: admin@ultra-embedded.com

@ -0,0 +1,40 @@
Media Access API
-=-=-=-=-=-=-=-=-
int media_read(uint32 sector, uint8 *buffer, uint32 sector_count)
Params:
Sector: 32-bit sector number
Buffer: Target buffer to read n sectors of data into.
Sector_count: Number of sectors to read.
Return:
int, 1 = success, 0 = failure.
Description:
Application/target specific disk/media read function.
Sector number (sectors are usually 512 byte pages) to read.
Media Write API
int media_write(uint32 sector, uint8 *buffer, uint32 sector_count)
Params:
Sector: 32-bit sector number
Buffer: Target buffer to write n sectors of data from.
Sector_count: Number of sectors to write.
Return:
int, 1 = success, 0 = failure.
Description:
Application/target specific disk/media write function.
Sector number (sectors are usually 512 byte pages) to write to.
File IO Library Linkage
Use the following API to attach the media IO functions to the File IO library.
int fl_attach_media(fn_diskio_read rd, fn_diskio_write wr)

@ -0,0 +1,87 @@
#include <stdio.h>
#include "fat_filelib.h"
int media_init()
{
// ...
return 1;
}
int media_read(unsigned long sector, unsigned char *buffer, unsigned long sector_count)
{
unsigned long i;
for (i=0;i<sector_count;i++)
{
// ...
// Add platform specific sector (512 bytes) read code here
//..
sector ++;
buffer += 512;
}
return 1;
}
int media_write(unsigned long sector, unsigned char *buffer, unsigned long sector_count)
{
unsigned long i;
for (i=0;i<sector_count;i++)
{
// ...
// Add platform specific sector (512 bytes) write code here
//..
sector ++;
buffer += 512;
}
return 1;
}
void main()
{
FL_FILE *file;
// Initialise media
media_init();
// Initialise File IO Library
fl_init();
// Attach media access functions to library
if (fl_attach_media(media_read, media_write) != FAT_INIT_OK)
{
printf("ERROR: Media attach failed\n");
return;
}
// List root directory
fl_listdirectory("/");
// Create File
file = fl_fopen("/file.bin", "w");
if (file)
{
// Write some data
unsigned char data[] = { 1, 2, 3, 4 };
if (fl_fwrite(data, 1, sizeof(data), file) != sizeof(data))
printf("ERROR: Write file failed\n");
}
else
printf("ERROR: Create file failed\n");
// Close file
fl_fclose(file);
// Delete File
if (fl_remove("/file.bin") < 0)
printf("ERROR: Delete file failed\n");
// List root directory
fl_listdirectory("/");
fl_shutdown();
}

@ -0,0 +1,904 @@
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// FAT16/32 File IO Library
// V2.6
// Ultra-Embedded.com
// Copyright 2003 - 2012
//
// Email: admin@ultra-embedded.com
//
// License: GPL
// If you would like a version with a more permissive license for use in
// closed source commercial applications please contact me for details.
//-----------------------------------------------------------------------------
//
// This file is part of FAT File IO Library.
//
// FAT File IO Library 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.
//
// FAT File IO Library 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 FAT File IO Library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
#include <string.h>
#include "fat_defs.h"
#include "fat_access.h"
#include "fat_table.h"
#include "fat_write.h"
#include "fat_string.h"
#include "fat_misc.h"
//-----------------------------------------------------------------------------
// fatfs_init: Load FAT Parameters
//-----------------------------------------------------------------------------
int fatfs_init(struct fatfs *fs)
{
uint8 num_of_fats;
uint16 reserved_sectors;
uint32 FATSz;
uint32 root_dir_sectors;
uint32 total_sectors;
uint32 data_sectors;
uint32 count_of_clusters;
uint8 valid_partition = 0;
fs->currentsector.address = FAT32_INVALID_CLUSTER;
fs->currentsector.dirty = 0;
fs->next_free_cluster = 0; // Invalid
fatfs_fat_init(fs);
// Make sure we have a read function (write function is optional)
if (!fs->disk_io.read_media)
return FAT_INIT_MEDIA_ACCESS_ERROR;
// MBR: Sector 0 on the disk
// NOTE: Some removeable media does not have this.
// Load MBR (LBA 0) into the 512 byte buffer
if (!fs->disk_io.read_media(0, fs->currentsector.sector, 1))
return FAT_INIT_MEDIA_ACCESS_ERROR;
// Make Sure 0x55 and 0xAA are at end of sector
// (this should be the case regardless of the MBR or boot sector)
if (fs->currentsector.sector[SIGNATURE_POSITION] != 0x55 || fs->currentsector.sector[SIGNATURE_POSITION+1] != 0xAA)
return FAT_INIT_INVALID_SIGNATURE;
// Now check again using the access function to prove endian conversion function
if (GET_16BIT_WORD(fs->currentsector.sector, SIGNATURE_POSITION) != SIGNATURE_VALUE)
return FAT_INIT_ENDIAN_ERROR;
// Verify packed structures
if (sizeof(struct fat_dir_entry) != FAT_DIR_ENTRY_SIZE)
return FAT_INIT_STRUCT_PACKING;
// Check the partition type code
switch(fs->currentsector.sector[PARTITION1_TYPECODE_LOCATION])
{
case 0x0B:
case 0x06:
case 0x0C:
case 0x0E:
case 0x0F:
case 0x05:
valid_partition = 1;
break;
case 0x00:
valid_partition = 0;
break;
default:
if (fs->currentsector.sector[PARTITION1_TYPECODE_LOCATION] <= 0x06)
valid_partition = 1;
break;
}
// Read LBA Begin for the file system
if (valid_partition)
fs->lba_begin = GET_32BIT_WORD(fs->currentsector.sector, PARTITION1_LBA_BEGIN_LOCATION);
// Else possibly MBR less disk
else
fs->lba_begin = 0;
// Load Volume 1 table into sector buffer
// (We may already have this in the buffer if MBR less drive!)
if (!fs->disk_io.read_media(fs->lba_begin, fs->currentsector.sector, 1))
return FAT_INIT_MEDIA_ACCESS_ERROR;
// Make sure there are 512 bytes per cluster
if (GET_16BIT_WORD(fs->currentsector.sector, 0x0B) != FAT_SECTOR_SIZE)
return FAT_INIT_INVALID_SECTOR_SIZE;
// Load Parameters of FAT partition
fs->sectors_per_cluster = fs->currentsector.sector[BPB_SECPERCLUS];
reserved_sectors = GET_16BIT_WORD(fs->currentsector.sector, BPB_RSVDSECCNT);
num_of_fats = fs->currentsector.sector[BPB_NUMFATS];
fs->root_entry_count = GET_16BIT_WORD(fs->currentsector.sector, BPB_ROOTENTCNT);
if(GET_16BIT_WORD(fs->currentsector.sector, BPB_FATSZ16) != 0)
fs->fat_sectors = GET_16BIT_WORD(fs->currentsector.sector, BPB_FATSZ16);
else
fs->fat_sectors = GET_32BIT_WORD(fs->currentsector.sector, BPB_FAT32_FATSZ32);
// For FAT32 (which this may be)
fs->rootdir_first_cluster = GET_32BIT_WORD(fs->currentsector.sector, BPB_FAT32_ROOTCLUS);
fs->fs_info_sector = GET_16BIT_WORD(fs->currentsector.sector, BPB_FAT32_FSINFO);
// For FAT16 (which this may be), rootdir_first_cluster is actuall rootdir_first_sector
fs->rootdir_first_sector = reserved_sectors + (num_of_fats * fs->fat_sectors);
fs->rootdir_sectors = ((fs->root_entry_count * 32) + (FAT_SECTOR_SIZE - 1)) / FAT_SECTOR_SIZE;
// First FAT LBA address
fs->fat_begin_lba = fs->lba_begin + reserved_sectors;
// The address of the first data cluster on this volume
fs->cluster_begin_lba = fs->fat_begin_lba + (num_of_fats * fs->fat_sectors);
if (GET_16BIT_WORD(fs->currentsector.sector, 0x1FE) != 0xAA55) // This signature should be AA55
return FAT_INIT_INVALID_SIGNATURE;
// Calculate the root dir sectors
root_dir_sectors = ((GET_16BIT_WORD(fs->currentsector.sector, BPB_ROOTENTCNT) * 32) + (GET_16BIT_WORD(fs->currentsector.sector, BPB_BYTSPERSEC) - 1)) / GET_16BIT_WORD(fs->currentsector.sector, BPB_BYTSPERSEC);
if(GET_16BIT_WORD(fs->currentsector.sector, BPB_FATSZ16) != 0)
FATSz = GET_16BIT_WORD(fs->currentsector.sector, BPB_FATSZ16);
else
FATSz = GET_32BIT_WORD(fs->currentsector.sector, BPB_FAT32_FATSZ32);
if(GET_16BIT_WORD(fs->currentsector.sector, BPB_TOTSEC16) != 0)
total_sectors = GET_16BIT_WORD(fs->currentsector.sector, BPB_TOTSEC16);
else
total_sectors = GET_32BIT_WORD(fs->currentsector.sector, BPB_TOTSEC32);
data_sectors = total_sectors - (GET_16BIT_WORD(fs->currentsector.sector, BPB_RSVDSECCNT) + (fs->currentsector.sector[BPB_NUMFATS] * FATSz) + root_dir_sectors);
// Find out which version of FAT this is...
if (fs->sectors_per_cluster != 0)
{
count_of_clusters = data_sectors / fs->sectors_per_cluster;
if(count_of_clusters < 4085)
// Volume is FAT12
return FAT_INIT_WRONG_FILESYS_TYPE;
else if(count_of_clusters < 65525)
{
// Clear this FAT32 specific param
fs->rootdir_first_cluster = 0;
// Volume is FAT16
fs->fat_type = FAT_TYPE_16;
return FAT_INIT_OK;
}
else
{
// Volume is FAT32
fs->fat_type = FAT_TYPE_32;
return FAT_INIT_OK;
}
}
else
return FAT_INIT_WRONG_FILESYS_TYPE;
}
//-----------------------------------------------------------------------------
// fatfs_lba_of_cluster: This function converts a cluster number into a sector /
// LBA number.
//-----------------------------------------------------------------------------
uint32 fatfs_lba_of_cluster(struct fatfs *fs, uint32 Cluster_Number)
{
if (fs->fat_type == FAT_TYPE_16)
return (fs->cluster_begin_lba + (fs->root_entry_count * 32 / FAT_SECTOR_SIZE) + ((Cluster_Number-2) * fs->sectors_per_cluster));
else
return ((fs->cluster_begin_lba + ((Cluster_Number-2)*fs->sectors_per_cluster)));
}
//-----------------------------------------------------------------------------
// fatfs_sector_read:
//-----------------------------------------------------------------------------
int fatfs_sector_read(struct fatfs *fs, uint32 lba, uint8 *target, uint32 count)
{
return fs->disk_io.read_media(lba, target, count);
}
//-----------------------------------------------------------------------------
// fatfs_sector_write:
//-----------------------------------------------------------------------------
int fatfs_sector_write(struct fatfs *fs, uint32 lba, uint8 *target, uint32 count)
{
return fs->disk_io.write_media(lba, target, count);
}
//-----------------------------------------------------------------------------
// fatfs_sector_reader: From the provided startcluster and sector offset
// Returns True if success, returns False if not (including if read out of range)
//-----------------------------------------------------------------------------
int fatfs_sector_reader(struct fatfs *fs, uint32 start_cluster, uint32 offset, uint8 *target)
{
uint32 sector_to_read = 0;
uint32 cluster_to_read = 0;
uint32 cluster_chain = 0;
uint32 i;
uint32 lba;
// FAT16 Root directory
if (fs->fat_type == FAT_TYPE_16 && start_cluster == 0)
{
if (offset < fs->rootdir_sectors)
lba = fs->lba_begin + fs->rootdir_first_sector + offset;
else
return 0;
}
// FAT16/32 Other
else
{
// Set start of cluster chain to initial value
cluster_chain = start_cluster;
// Find parameters
cluster_to_read = offset / fs->sectors_per_cluster;
sector_to_read = offset - (cluster_to_read*fs->sectors_per_cluster);
// Follow chain to find cluster to read
for (i=0; i<cluster_to_read; i++)
cluster_chain = fatfs_find_next_cluster(fs, cluster_chain);
// If end of cluster chain then return false
if (cluster_chain == FAT32_LAST_CLUSTER)
return 0;
// Calculate sector address
lba = fatfs_lba_of_cluster(fs, cluster_chain)+sector_to_read;
}
// User provided target array
if (target)
return fs->disk_io.read_media(lba, target, 1);
// Else read sector if not already loaded
else if (lba != fs->currentsector.address)
{
fs->currentsector.address = lba;
return fs->disk_io.read_media(fs->currentsector.address, fs->currentsector.sector, 1);
}
else
return 1;
}
//-----------------------------------------------------------------------------
// fatfs_read_sector: Read from the provided cluster and sector offset
// Returns True if success, returns False if not
//-----------------------------------------------------------------------------
int fatfs_read_sector(struct fatfs *fs, uint32 cluster, uint32 sector, uint8 *target)
{
// FAT16 Root directory
if (fs->fat_type == FAT_TYPE_16 && cluster == 0)
{
uint32 lba;
// In FAT16, there are a limited amount of sectors in root dir!
if (sector < fs->rootdir_sectors)
lba = fs->lba_begin + fs->rootdir_first_sector + sector;
else
return 0;
// User target buffer passed in
if (target)
{
// Read from disk
return fs->disk_io.read_media(lba, target, 1);
}
else
{
// Calculate read address
fs->currentsector.address = lba;
// Read from disk
return fs->disk_io.read_media(fs->currentsector.address, fs->currentsector.sector, 1);
}
}
// FAT16/32 Other
else
{
// User target buffer passed in
if (target)
{
// Calculate read address
uint32 lba = fatfs_lba_of_cluster(fs, cluster) + sector;
// Read from disk
return fs->disk_io.read_media(lba, target, 1);
}
else
{
// Calculate write address
fs->currentsector.address = fatfs_lba_of_cluster(fs, cluster)+sector;
// Read from disk
return fs->disk_io.read_media(fs->currentsector.address, fs->currentsector.sector, 1);
}
}
}
//-----------------------------------------------------------------------------
// fatfs_write_sector: Write to the provided cluster and sector offset
// Returns True if success, returns False if not
//-----------------------------------------------------------------------------
#if FATFS_INC_WRITE_SUPPORT
int fatfs_write_sector(struct fatfs *fs, uint32 cluster, uint32 sector, uint8 *target)
{
// No write access?
if (!fs->disk_io.write_media)
return 0;
// FAT16 Root directory
if (fs->fat_type == FAT_TYPE_16 && cluster == 0)
{
uint32 lba;
// In FAT16 we cannot extend the root dir!
if (sector < fs->rootdir_sectors)
lba = fs->lba_begin + fs->rootdir_first_sector + sector;
else
return 0;
// User target buffer passed in
if (target)
{
// Write to disk
return fs->disk_io.write_media(lba, target, 1);
}
else
{
// Calculate write address
fs->currentsector.address = lba;
// Write to disk
return fs->disk_io.write_media(fs->currentsector.address, fs->currentsector.sector, 1);
}
}
// FAT16/32 Other
else
{
// User target buffer passed in
if (target)
{
// Calculate write address
uint32 lba = fatfs_lba_of_cluster(fs, cluster) + sector;
// Write to disk
return fs->disk_io.write_media(lba, target, 1);
}
else
{
// Calculate write address
fs->currentsector.address = fatfs_lba_of_cluster(fs, cluster)+sector;
// Write to disk
return fs->disk_io.write_media(fs->currentsector.address, fs->currentsector.sector, 1);
}
}
}
#endif
//-----------------------------------------------------------------------------
// fatfs_show_details: Show the details about the filesystem
//-----------------------------------------------------------------------------
void fatfs_show_details(struct fatfs *fs)
{
FAT_PRINTF(("FAT details:\r\n"));
FAT_PRINTF((" Type =%s", (fs->fat_type == FAT_TYPE_32) ? "FAT32": "FAT16"));
FAT_PRINTF((" Root Dir First Cluster = %x\r\n", fs->rootdir_first_cluster));
FAT_PRINTF((" FAT Begin LBA = 0x%x\r\n",fs->fat_begin_lba));
FAT_PRINTF((" Cluster Begin LBA = 0x%x\r\n",fs->cluster_begin_lba));
FAT_PRINTF((" Sectors Per Cluster = %d\r\n", fs->sectors_per_cluster));
}
//-----------------------------------------------------------------------------
// fatfs_get_root_cluster: Get the root dir cluster
//-----------------------------------------------------------------------------
uint32 fatfs_get_root_cluster(struct fatfs *fs)
{
// NOTE: On FAT16 this will be 0 which has a special meaning...
return fs->rootdir_first_cluster;
}
//-------------------------------------------------------------
// fatfs_get_file_entry: Find the file entry for a filename
//-------------------------------------------------------------
uint32 fatfs_get_file_entry(struct fatfs *fs, uint32 Cluster, char *name_to_find, struct fat_dir_entry *sfEntry)
{
uint8 item=0;
uint16 recordoffset = 0;
uint8 i=0;
int x=0;
char *long_filename = NULL;
char short_filename[13];
struct lfn_cache lfn;
int dotRequired = 0;
struct fat_dir_entry *directoryEntry;
fatfs_lfn_cache_init(&lfn, 1);
// Main cluster following loop
while (1)
{
// Read sector
if (fatfs_sector_reader(fs, Cluster, x++, 0)) // If sector read was successfull
{
// Analyse Sector
for (item = 0; item < FAT_DIR_ENTRIES_PER_SECTOR; item++)
{
// Create the multiplier for sector access
recordoffset = FAT_DIR_ENTRY_SIZE * item;
// Overlay directory entry over buffer
directoryEntry = (struct fat_dir_entry*)(fs->currentsector.sector+recordoffset);
#if FATFS_INC_LFN_SUPPORT
// Long File Name Text Found
if (fatfs_entry_lfn_text(directoryEntry) )
fatfs_lfn_cache_entry(&lfn, fs->currentsector.sector+recordoffset);
// If Invalid record found delete any long file name information collated
else if (fatfs_entry_lfn_invalid(directoryEntry) )
fatfs_lfn_cache_init(&lfn, 0);
// Normal SFN Entry and Long text exists
else if (fatfs_entry_lfn_exists(&lfn, directoryEntry) )
{
long_filename = fatfs_lfn_cache_get(&lfn);
// Compare names to see if they match
if (fatfs_compare_names(long_filename, name_to_find))
{
memcpy(sfEntry,directoryEntry,sizeof(struct fat_dir_entry));
return 1;
}
fatfs_lfn_cache_init(&lfn, 0);
}
else
#endif
// Normal Entry, only 8.3 Text
if (fatfs_entry_sfn_only(directoryEntry) )
{
memset(short_filename, 0, sizeof(short_filename));
// Copy name to string
for (i=0; i<8; i++)
short_filename[i] = directoryEntry->Name[i];
// Extension
dotRequired = 0;
for (i=8; i<11; i++)
{
short_filename[i+1] = directoryEntry->Name[i];
if (directoryEntry->Name[i] != ' ')
dotRequired = 1;
}
// Dot only required if extension present
if (dotRequired)
{
// If not . or .. entry
if (short_filename[0]!='.')
short_filename[8] = '.';
else
short_filename[8] = ' ';
}
else
short_filename[8] = ' ';
// Compare names to see if they match
if (fatfs_compare_names(short_filename, name_to_find))
{
memcpy(sfEntry,directoryEntry,sizeof(struct fat_dir_entry));
return 1;
}
fatfs_lfn_cache_init(&lfn, 0);
}
} // End of if
}
else
break;
} // End of while loop
return 0;
}
//-------------------------------------------------------------
// fatfs_sfn_exists: Check if a short filename exists.
// NOTE: shortname is XXXXXXXXYYY not XXXXXXXX.YYY
//-------------------------------------------------------------
#if FATFS_INC_WRITE_SUPPORT
int fatfs_sfn_exists(struct fatfs *fs, uint32 Cluster, char *shortname)
{
uint8 item=0;
uint16 recordoffset = 0;
int x=0;
struct fat_dir_entry *directoryEntry;
// Main cluster following loop
while (1)
{
// Read sector
if (fatfs_sector_reader(fs, Cluster, x++, 0)) // If sector read was successfull
{
// Analyse Sector
for (item = 0; item < FAT_DIR_ENTRIES_PER_SECTOR; item++)
{
// Create the multiplier for sector access
recordoffset = FAT_DIR_ENTRY_SIZE * item;
// Overlay directory entry over buffer
directoryEntry = (struct fat_dir_entry*)(fs->currentsector.sector+recordoffset);
#if FATFS_INC_LFN_SUPPORT
// Long File Name Text Found
if (fatfs_entry_lfn_text(directoryEntry) )
;
// If Invalid record found delete any long file name information collated
else if (fatfs_entry_lfn_invalid(directoryEntry) )
;
else
#endif
// Normal Entry, only 8.3 Text
if (fatfs_entry_sfn_only(directoryEntry) )
{
if (strncmp((const char*)directoryEntry->Name, shortname, 11)==0)
return 1;
}
} // End of if
}
else
break;
} // End of while loop
return 0;
}
#endif
//-------------------------------------------------------------
// fatfs_update_timestamps: Update date/time details
//-------------------------------------------------------------
#if FATFS_INC_TIME_DATE_SUPPORT
int fatfs_update_timestamps(struct fat_dir_entry *directoryEntry, int create, int modify, int access)
{
time_t time_now;
struct tm * time_info;
uint16 fat_time;
uint16 fat_date;
// Get system time
time(&time_now);
// Convert to local time
time_info = localtime(&time_now);
// Convert time to FAT format
fat_time = fatfs_convert_to_fat_time(time_info->tm_hour, time_info->tm_min, time_info->tm_sec);
// Convert date to FAT format
fat_date = fatfs_convert_to_fat_date(time_info->tm_mday, time_info->tm_mon + 1, time_info->tm_year + 1900);
// Update requested fields
if (create)
{
directoryEntry->CrtTime[1] = fat_time >> 8;
directoryEntry->CrtTime[0] = fat_time >> 0;
directoryEntry->CrtDate[1] = fat_date >> 8;
directoryEntry->CrtDate[0] = fat_date >> 0;
}
if (modify)
{
directoryEntry->WrtTime[1] = fat_time >> 8;
directoryEntry->WrtTime[0] = fat_time >> 0;
directoryEntry->WrtDate[1] = fat_date >> 8;
directoryEntry->WrtDate[0] = fat_date >> 0;
}
if (access)
{
directoryEntry->LstAccDate[1] = fat_time >> 8;
directoryEntry->LstAccDate[0] = fat_time >> 0;
directoryEntry->LstAccDate[1] = fat_date >> 8;
directoryEntry->LstAccDate[0] = fat_date >> 0;
}
return 1;
}
#endif
//-------------------------------------------------------------
// fatfs_update_file_length: Find a SFN entry and update it
// NOTE: shortname is XXXXXXXXYYY not XXXXXXXX.YYY
//-------------------------------------------------------------
#if FATFS_INC_WRITE_SUPPORT
int fatfs_update_file_length(struct fatfs *fs, uint32 Cluster, char *shortname, uint32 fileLength)
{
uint8 item=0;
uint16 recordoffset = 0;
int x=0;
struct fat_dir_entry *directoryEntry;
// No write access?
if (!fs->disk_io.write_media)
return 0;
// Main cluster following loop
while (1)
{
// Read sector
if (fatfs_sector_reader(fs, Cluster, x++, 0)) // If sector read was successfull
{
// Analyse Sector
for (item = 0; item < FAT_DIR_ENTRIES_PER_SECTOR; item++)
{
// Create the multiplier for sector access
recordoffset = FAT_DIR_ENTRY_SIZE * item;
// Overlay directory entry over buffer
directoryEntry = (struct fat_dir_entry*)(fs->currentsector.sector+recordoffset);
#if FATFS_INC_LFN_SUPPORT
// Long File Name Text Found
if (fatfs_entry_lfn_text(directoryEntry) )
;
// If Invalid record found delete any long file name information collated
else if (fatfs_entry_lfn_invalid(directoryEntry) )
;
// Normal Entry, only 8.3 Text
else
#endif
if (fatfs_entry_sfn_only(directoryEntry) )
{
if (strncmp((const char*)directoryEntry->Name, shortname, 11)==0)
{
directoryEntry->FileSize = FAT_HTONL(fileLength);
#if FATFS_INC_TIME_DATE_SUPPORT
// Update access / modify time & date
fatfs_update_timestamps(directoryEntry, 0, 1, 1);
#endif
// Update sfn entry
memcpy((uint8*)(fs->currentsector.sector+recordoffset), (uint8*)directoryEntry, sizeof(struct fat_dir_entry));
// Write sector back
return fs->disk_io.write_media(fs->currentsector.address, fs->currentsector.sector, 1);
}
}
} // End of if
}
else
break;
} // End of while loop
return 0;
}
#endif
//-------------------------------------------------------------
// fatfs_mark_file_deleted: Find a SFN entry and mark if as deleted
// NOTE: shortname is XXXXXXXXYYY not XXXXXXXX.YYY
//-------------------------------------------------------------
#if FATFS_INC_WRITE_SUPPORT
int fatfs_mark_file_deleted(struct fatfs *fs, uint32 Cluster, char *shortname)
{
uint8 item=0;
uint16 recordoffset = 0;
int x=0;
struct fat_dir_entry *directoryEntry;
// No write access?
if (!fs->disk_io.write_media)
return 0;
// Main cluster following loop
while (1)
{
// Read sector
if (fatfs_sector_reader(fs, Cluster, x++, 0)) // If sector read was successfull
{
// Analyse Sector
for (item = 0; item < FAT_DIR_ENTRIES_PER_SECTOR; item++)
{
// Create the multiplier for sector access
recordoffset = FAT_DIR_ENTRY_SIZE * item;
// Overlay directory entry over buffer
directoryEntry = (struct fat_dir_entry*)(fs->currentsector.sector+recordoffset);
#if FATFS_INC_LFN_SUPPORT
// Long File Name Text Found
if (fatfs_entry_lfn_text(directoryEntry) )
;
// If Invalid record found delete any long file name information collated
else if (fatfs_entry_lfn_invalid(directoryEntry) )
;
// Normal Entry, only 8.3 Text
else
#endif
if (fatfs_entry_sfn_only(directoryEntry) )
{
if (strncmp((const char *)directoryEntry->Name, shortname, 11)==0)
{
// Mark as deleted
directoryEntry->Name[0] = FILE_HEADER_DELETED;
#if FATFS_INC_TIME_DATE_SUPPORT
// Update access / modify time & date
fatfs_update_timestamps(directoryEntry, 0, 1, 1);
#endif
// Update sfn entry
memcpy((uint8*)(fs->currentsector.sector+recordoffset), (uint8*)directoryEntry, sizeof(struct fat_dir_entry));
// Write sector back
return fs->disk_io.write_media(fs->currentsector.address, fs->currentsector.sector, 1);
}
}
} // End of if
}
else
break;
} // End of while loop
return 0;
}
#endif
//-----------------------------------------------------------------------------
// fatfs_list_directory_start: Initialise a directory listing procedure
//-----------------------------------------------------------------------------
#if FATFS_DIR_LIST_SUPPORT
void fatfs_list_directory_start(struct fatfs *fs, struct fs_dir_list_status *dirls, uint32 StartCluster)
{
dirls->cluster = StartCluster;
dirls->sector = 0;
dirls->offset = 0;
}
#endif
//-----------------------------------------------------------------------------
// fatfs_list_directory_next: Get the next entry in the directory.
// Returns: 1 = found, 0 = end of listing
//-----------------------------------------------------------------------------
#if FATFS_DIR_LIST_SUPPORT
int fatfs_list_directory_next(struct fatfs *fs, struct fs_dir_list_status *dirls, struct fs_dir_ent *entry)
{
uint8 i,item;
uint16 recordoffset;
struct fat_dir_entry *directoryEntry;
char *long_filename = NULL;
char short_filename[13];
struct lfn_cache lfn;
int dotRequired = 0;
int result = 0;
// Initialise LFN cache first
fatfs_lfn_cache_init(&lfn, 0);
while (1)
{
// If data read OK
if (fatfs_sector_reader(fs, dirls->cluster, dirls->sector, 0))
{
// Maximum of 16 directory entries
for (item = dirls->offset; item < FAT_DIR_ENTRIES_PER_SECTOR; item++)
{
// Increase directory offset
recordoffset = FAT_DIR_ENTRY_SIZE * item;
// Overlay directory entry over buffer
directoryEntry = (struct fat_dir_entry*)(fs->currentsector.sector+recordoffset);
#if FATFS_INC_LFN_SUPPORT
// Long File Name Text Found
if ( fatfs_entry_lfn_text(directoryEntry) )
fatfs_lfn_cache_entry(&lfn, fs->currentsector.sector+recordoffset);
// If Invalid record found delete any long file name information collated
else if ( fatfs_entry_lfn_invalid(directoryEntry) )
fatfs_lfn_cache_init(&lfn, 0);
// Normal SFN Entry and Long text exists
else if (fatfs_entry_lfn_exists(&lfn, directoryEntry) )
{
// Get text
long_filename = fatfs_lfn_cache_get(&lfn);
strncpy(entry->filename, long_filename, FATFS_MAX_LONG_FILENAME-1);
if (fatfs_entry_is_dir(directoryEntry))
entry->is_dir = 1;
else
entry->is_dir = 0;
#if FATFS_INC_TIME_DATE_SUPPORT
// Get time / dates
entry->create_time = ((uint16)directoryEntry->CrtTime[1] << 8) | directoryEntry->CrtTime[0];
entry->create_date = ((uint16)directoryEntry->CrtDate[1] << 8) | directoryEntry->CrtDate[0];
entry->access_date = ((uint16)directoryEntry->LstAccDate[1] << 8) | directoryEntry->LstAccDate[0];
entry->write_time = ((uint16)directoryEntry->WrtTime[1] << 8) | directoryEntry->WrtTime[0];
entry->write_date = ((uint16)directoryEntry->WrtDate[1] << 8) | directoryEntry->WrtDate[0];
#endif
entry->size = FAT_HTONL(directoryEntry->FileSize);
entry->cluster = (FAT_HTONS(directoryEntry->FstClusHI)<<16) | FAT_HTONS(directoryEntry->FstClusLO);
// Next starting position
dirls->offset = item + 1;
result = 1;
return 1;
}
// Normal Entry, only 8.3 Text
else
#endif
if ( fatfs_entry_sfn_only(directoryEntry) )
{
fatfs_lfn_cache_init(&lfn, 0);
memset(short_filename, 0, sizeof(short_filename));
// Copy name to string
for (i=0; i<8; i++)
short_filename[i] = directoryEntry->Name[i];
// Extension
dotRequired = 0;
for (i=8; i<11; i++)
{
short_filename[i+1] = directoryEntry->Name[i];
if (directoryEntry->Name[i] != ' ')
dotRequired = 1;
}
// Dot only required if extension present
if (dotRequired)
{
// If not . or .. entry
if (short_filename[0]!='.')
short_filename[8] = '.';
else
short_filename[8] = ' ';
}
else
short_filename[8] = ' ';
fatfs_get_sfn_display_name(entry->filename, short_filename);
if (fatfs_entry_is_dir(directoryEntry))
entry->is_dir = 1;
else
entry->is_dir = 0;
#if FATFS_INC_TIME_DATE_SUPPORT
// Get time / dates
entry->create_time = ((uint16)directoryEntry->CrtTime[1] << 8) | directoryEntry->CrtTime[0];
entry->create_date = ((uint16)directoryEntry->CrtDate[1] << 8) | directoryEntry->CrtDate[0];
entry->access_date = ((uint16)directoryEntry->LstAccDate[1] << 8) | directoryEntry->LstAccDate[0];
entry->write_time = ((uint16)directoryEntry->WrtTime[1] << 8) | directoryEntry->WrtTime[0];
entry->write_date = ((uint16)directoryEntry->WrtDate[1] << 8) | directoryEntry->WrtDate[0];
#endif
entry->size = FAT_HTONL(directoryEntry->FileSize);
entry->cluster = (FAT_HTONS(directoryEntry->FstClusHI)<<16) | FAT_HTONS(directoryEntry->FstClusLO);
// Next starting position
dirls->offset = item + 1;
result = 1;
return 1;
}
}// end of for
// If reached end of the dir move onto next sector
dirls->sector++;
dirls->offset = 0;
}
else
break;
}
return result;
}
#endif

@ -0,0 +1,133 @@
#ifndef __FAT_ACCESS_H__
#define __FAT_ACCESS_H__
#include "fat_defs.h"
#include "fat_opts.h"
//-----------------------------------------------------------------------------
// Defines
//-----------------------------------------------------------------------------
#define FAT_INIT_OK 0
#define FAT_INIT_MEDIA_ACCESS_ERROR (-1)
#define FAT_INIT_INVALID_SECTOR_SIZE (-2)
#define FAT_INIT_INVALID_SIGNATURE (-3)
#define FAT_INIT_ENDIAN_ERROR (-4)
#define FAT_INIT_WRONG_FILESYS_TYPE (-5)
#define FAT_INIT_WRONG_PARTITION_TYPE (-6)
#define FAT_INIT_STRUCT_PACKING (-7)
#define FAT_DIR_ENTRIES_PER_SECTOR (FAT_SECTOR_SIZE / FAT_DIR_ENTRY_SIZE)
//-----------------------------------------------------------------------------
// Function Pointers
//-----------------------------------------------------------------------------
typedef int (*fn_diskio_read) (uint32 sector, uint8 *buffer, uint32 sector_count);
typedef int (*fn_diskio_write)(uint32 sector, uint8 *buffer, uint32 sector_count);
//-----------------------------------------------------------------------------
// Structures
//-----------------------------------------------------------------------------
struct disk_if
{
// User supplied function pointers for disk IO
fn_diskio_read read_media;
fn_diskio_write write_media;
};
// Forward declaration
struct fat_buffer;
struct fat_buffer
{
uint8 sector[FAT_SECTOR_SIZE * FAT_BUFFER_SECTORS];
uint32 address;
int dirty;
uint8 * ptr;
// Next in chain of sector buffers
struct fat_buffer *next;
};
typedef enum eFatType
{
FAT_TYPE_16,
FAT_TYPE_32
} tFatType;
struct fatfs
{
// Filesystem globals
uint8 sectors_per_cluster;
uint32 cluster_begin_lba;
uint32 rootdir_first_cluster;
uint32 rootdir_first_sector;
uint32 rootdir_sectors;
uint32 fat_begin_lba;
uint16 fs_info_sector;
uint32 lba_begin;
uint32 fat_sectors;
uint32 next_free_cluster;
uint16 root_entry_count;
uint16 reserved_sectors;
uint8 num_of_fats;
tFatType fat_type;
// Disk/Media API
struct disk_if disk_io;
// [Optional] Thread Safety
void (*fl_lock)(void);
void (*fl_unlock)(void);
// Working buffer
struct fat_buffer currentsector;
// FAT Buffer
struct fat_buffer *fat_buffer_head;
struct fat_buffer fat_buffers[FAT_BUFFERS];
};
struct fs_dir_list_status
{
uint32 sector;
uint32 cluster;
uint8 offset;
};
struct fs_dir_ent
{
char filename[FATFS_MAX_LONG_FILENAME];
uint8 is_dir;
uint32 cluster;
uint32 size;
#if FATFS_INC_TIME_DATE_SUPPORT
uint16 access_date;
uint16 write_time;
uint16 write_date;
uint16 create_date;
uint16 create_time;
#endif
};
//-----------------------------------------------------------------------------
// Prototypes
//-----------------------------------------------------------------------------
int fatfs_init(struct fatfs *fs);
uint32 fatfs_lba_of_cluster(struct fatfs *fs, uint32 Cluster_Number);
int fatfs_sector_reader(struct fatfs *fs, uint32 Startcluster, uint32 offset, uint8 *target);
int fatfs_sector_read(struct fatfs *fs, uint32 lba, uint8 *target, uint32 count);
int fatfs_sector_write(struct fatfs *fs, uint32 lba, uint8 *target, uint32 count);
int fatfs_read_sector(struct fatfs *fs, uint32 cluster, uint32 sector, uint8 *target);
int fatfs_write_sector(struct fatfs *fs, uint32 cluster, uint32 sector, uint8 *target);
void fatfs_show_details(struct fatfs *fs);
uint32 fatfs_get_root_cluster(struct fatfs *fs);
uint32 fatfs_get_file_entry(struct fatfs *fs, uint32 Cluster, char *nametofind, struct fat_dir_entry *sfEntry);
int fatfs_sfn_exists(struct fatfs *fs, uint32 Cluster, char *shortname);
int fatfs_update_file_length(struct fatfs *fs, uint32 Cluster, char *shortname, uint32 fileLength);
int fatfs_mark_file_deleted(struct fatfs *fs, uint32 Cluster, char *shortname);
void fatfs_list_directory_start(struct fatfs *fs, struct fs_dir_list_status *dirls, uint32 StartCluster);
int fatfs_list_directory_next(struct fatfs *fs, struct fs_dir_list_status *dirls, struct fs_dir_ent *entry);
int fatfs_update_timestamps(struct fat_dir_entry *directoryEntry, int create, int modify, int access);
#endif

@ -0,0 +1,91 @@
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// FAT16/32 File IO Library
// V2.6
// Ultra-Embedded.com
// Copyright 2003 - 2012
//
// Email: admin@ultra-embedded.com
//
// License: GPL
// If you would like a version with a more permissive license for use in
// closed source commercial applications please contact me for details.
//-----------------------------------------------------------------------------
//
// This file is part of FAT File IO Library.
//
// FAT File IO Library 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.
//
// FAT File IO Library 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 FAT File IO Library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
#include <string.h>
#include "fat_cache.h"
// Per file cluster chain caching used to improve performance.
// This does not have to be enabled for architectures with low
// memory space.
//-----------------------------------------------------------------------------
// fatfs_cache_init:
//-----------------------------------------------------------------------------
int fatfs_cache_init(struct fatfs *fs, FL_FILE *file)
{
#ifdef FAT_CLUSTER_CACHE_ENTRIES
int i;
for (i=0;i<FAT_CLUSTER_CACHE_ENTRIES;i++)
{
file->cluster_cache_idx[i] = 0xFFFFFFFF; // Not used
file->cluster_cache_data[i] = 0;
}
#endif
return 1;
}
//-----------------------------------------------------------------------------
// fatfs_cache_get_next_cluster:
//-----------------------------------------------------------------------------
int fatfs_cache_get_next_cluster(struct fatfs *fs, FL_FILE *file, uint32 clusterIdx, uint32 *pNextCluster)
{
#ifdef FAT_CLUSTER_CACHE_ENTRIES
uint32 slot = clusterIdx % FAT_CLUSTER_CACHE_ENTRIES;
if (file->cluster_cache_idx[slot] == clusterIdx)
{
*pNextCluster = file->cluster_cache_data[slot];
return 1;
}
#endif
return 0;
}
//-----------------------------------------------------------------------------
// fatfs_cache_set_next_cluster:
//-----------------------------------------------------------------------------
int fatfs_cache_set_next_cluster(struct fatfs *fs, FL_FILE *file, uint32 clusterIdx, uint32 nextCluster)
{
#ifdef FAT_CLUSTER_CACHE_ENTRIES
uint32 slot = clusterIdx % FAT_CLUSTER_CACHE_ENTRIES;
if (file->cluster_cache_idx[slot] == clusterIdx)
file->cluster_cache_data[slot] = nextCluster;
else
{
file->cluster_cache_idx[slot] = clusterIdx;
file->cluster_cache_data[slot] = nextCluster;
}
#endif
return 1;
}

@ -0,0 +1,13 @@
#ifndef __FAT_CACHE_H__
#define __FAT_CACHE_H__
#include "fat_filelib.h"
//-----------------------------------------------------------------------------
// Prototypes
//-----------------------------------------------------------------------------
int fatfs_cache_init(struct fatfs *fs, FL_FILE *file);
int fatfs_cache_get_next_cluster(struct fatfs *fs, FL_FILE *file, uint32 clusterIdx, uint32 *pNextCluster);
int fatfs_cache_set_next_cluster(struct fatfs *fs, FL_FILE *file, uint32 clusterIdx, uint32 nextCluster);
#endif

@ -0,0 +1,128 @@
#ifndef __FAT_DEFS_H__
#define __FAT_DEFS_H__
#include "fat_opts.h"
#include "fat_types.h"
//-----------------------------------------------------------------------------
// FAT32 Offsets
// Name Offset
//-----------------------------------------------------------------------------
// Boot Sector
#define BS_JMPBOOT 0 // Length = 3
#define BS_OEMNAME 3 // Length = 8
#define BPB_BYTSPERSEC 11 // Length = 2
#define BPB_SECPERCLUS 13 // Length = 1
#define BPB_RSVDSECCNT 14 // Length = 2
#define BPB_NUMFATS 16 // Length = 1
#define BPB_ROOTENTCNT 17 // Length = 2
#define BPB_TOTSEC16 19 // Length = 2
#define BPB_MEDIA 21 // Length = 1
#define BPB_FATSZ16 22 // Length = 2
#define BPB_SECPERTRK 24 // Length = 2
#define BPB_NUMHEADS 26 // Length = 2
#define BPB_HIDDSEC 28 // Length = 4
#define BPB_TOTSEC32 32 // Length = 4
// FAT 12/16
#define BS_FAT_DRVNUM 36 // Length = 1
#define BS_FAT_BOOTSIG 38 // Length = 1
#define BS_FAT_VOLID 39 // Length = 4
#define BS_FAT_VOLLAB 43 // Length = 11
#define BS_FAT_FILSYSTYPE 54 // Length = 8
// FAT 32
#define BPB_FAT32_FATSZ32 36 // Length = 4
#define BPB_FAT32_EXTFLAGS 40 // Length = 2
#define BPB_FAT32_FSVER 42 // Length = 2
#define BPB_FAT32_ROOTCLUS 44 // Length = 4
#define BPB_FAT32_FSINFO 48 // Length = 2
#define BPB_FAT32_BKBOOTSEC 50 // Length = 2
#define BS_FAT32_DRVNUM 64 // Length = 1
#define BS_FAT32_BOOTSIG 66 // Length = 1
#define BS_FAT32_VOLID 67 // Length = 4
#define BS_FAT32_VOLLAB 71 // Length = 11
#define BS_FAT32_FILSYSTYPE 82 // Length = 8
//-----------------------------------------------------------------------------
// FAT Types
//-----------------------------------------------------------------------------
#define FAT_TYPE_FAT12 1
#define FAT_TYPE_FAT16 2
#define FAT_TYPE_FAT32 3
//-----------------------------------------------------------------------------
// FAT32 Specific Statics
//-----------------------------------------------------------------------------
#define SIGNATURE_POSITION 510
#define SIGNATURE_VALUE 0xAA55
#define PARTITION1_TYPECODE_LOCATION 450
#define FAT32_TYPECODE1 0x0B
#define FAT32_TYPECODE2 0x0C
#define PARTITION1_LBA_BEGIN_LOCATION 454
#define PARTITION1_SIZE_LOCATION 458
#define FAT_DIR_ENTRY_SIZE 32
#define FAT_SFN_SIZE_FULL 11
#define FAT_SFN_SIZE_PARTIAL 8
//-----------------------------------------------------------------------------
// FAT32 File Attributes and Types
//-----------------------------------------------------------------------------
#define FILE_ATTR_READ_ONLY 0x01
#define FILE_ATTR_HIDDEN 0x02
#define FILE_ATTR_SYSTEM 0x04
#define FILE_ATTR_SYSHID 0x06
#define FILE_ATTR_VOLUME_ID 0x08
#define FILE_ATTR_DIRECTORY 0x10
#define FILE_ATTR_ARCHIVE 0x20
#define FILE_ATTR_LFN_TEXT 0x0F
#define FILE_HEADER_BLANK 0x00
#define FILE_HEADER_DELETED 0xE5
#define FILE_TYPE_DIR 0x10
#define FILE_TYPE_FILE 0x20
//-----------------------------------------------------------------------------
// Time / Date details
//-----------------------------------------------------------------------------
#define FAT_TIME_HOURS_SHIFT 11
#define FAT_TIME_HOURS_MASK 0x1F
#define FAT_TIME_MINUTES_SHIFT 5
#define FAT_TIME_MINUTES_MASK 0x3F
#define FAT_TIME_SECONDS_SHIFT 0
#define FAT_TIME_SECONDS_MASK 0x1F
#define FAT_TIME_SECONDS_SCALE 2
#define FAT_DATE_YEAR_SHIFT 9
#define FAT_DATE_YEAR_MASK 0x7F
#define FAT_DATE_MONTH_SHIFT 5
#define FAT_DATE_MONTH_MASK 0xF
#define FAT_DATE_DAY_SHIFT 0
#define FAT_DATE_DAY_MASK 0x1F
#define FAT_DATE_YEAR_OFFSET 1980
//-----------------------------------------------------------------------------
// Other Defines
//-----------------------------------------------------------------------------
#define FAT32_LAST_CLUSTER 0xFFFFFFFF
#define FAT32_INVALID_CLUSTER 0xFFFFFFFF
STRUCT_PACK_BEGIN
struct fat_dir_entry STRUCT_PACK
{
uint8 Name[11];
uint8 Attr;
uint8 NTRes;
uint8 CrtTimeTenth;
uint8 CrtTime[2];
uint8 CrtDate[2];
uint8 LstAccDate[2];
uint16 FstClusHI;
uint8 WrtTime[2];
uint8 WrtDate[2];
uint16 FstClusLO;
uint32 FileSize;
} STRUCT_PACKED;
STRUCT_PACK_END
#endif

File diff suppressed because it is too large Load Diff

@ -0,0 +1,146 @@
#ifndef __FAT_FILELIB_H__
#define __FAT_FILELIB_H__
#include "fat_opts.h"
#include "fat_access.h"
#include "fat_list.h"
//-----------------------------------------------------------------------------
// Defines
//-----------------------------------------------------------------------------
#ifndef SEEK_CUR
#define SEEK_CUR 1
#endif
#ifndef SEEK_END
#define SEEK_END 2
#endif
#ifndef SEEK_SET
#define SEEK_SET 0
#endif
#ifndef EOF
#define EOF (-1)
#endif
//-----------------------------------------------------------------------------
// Structures
//-----------------------------------------------------------------------------
struct sFL_FILE;
struct cluster_lookup
{
uint32 ClusterIdx;
uint32 CurrentCluster;
};
typedef struct sFL_FILE
{
uint32 parentcluster;
uint32 startcluster;
uint32 bytenum;
uint32 filelength;
int filelength_changed;
char path[FATFS_MAX_LONG_FILENAME];
char filename[FATFS_MAX_LONG_FILENAME];
uint8 shortfilename[11];
#ifdef FAT_CLUSTER_CACHE_ENTRIES
uint32 cluster_cache_idx[FAT_CLUSTER_CACHE_ENTRIES];
uint32 cluster_cache_data[FAT_CLUSTER_CACHE_ENTRIES];
#endif
// Cluster Lookup
struct cluster_lookup last_fat_lookup;
// Read/Write sector buffer
uint8 file_data_sector[FAT_SECTOR_SIZE];
uint32 file_data_address;
int file_data_dirty;
// File fopen flags
uint8 flags;
#define FILE_READ (1 << 0)
#define FILE_WRITE (1 << 1)
#define FILE_APPEND (1 << 2)
#define FILE_BINARY (1 << 3)
#define FILE_ERASE (1 << 4)
#define FILE_CREATE (1 << 5)
struct fat_node list_node;
} FL_FILE;
//-----------------------------------------------------------------------------
// Prototypes
//-----------------------------------------------------------------------------
// External
void fl_init(void);
void fl_attach_locks(void (*lock)(void), void (*unlock)(void));
int fl_attach_media(fn_diskio_read rd, fn_diskio_write wr);
void fl_shutdown(void);
// Standard API
void* fl_fopen(const char *path, const char *modifiers);
void fl_fclose(void *file);
int fl_fflush(void *file);
int fl_fgetc(void *file);
char * fl_fgets(char *s, int n, void *f);
int fl_fputc(int c, void *file);
int fl_fputs(const char * str, void *file);
int fl_fwrite(const void * data, int size, int count, void *file );
int fl_fread(void * data, int size, int count, void *file );
int fl_fseek(void *file , long offset , int origin );
int fl_fgetpos(void *file , uint32 * position);
long fl_ftell(void *f);
int fl_feof(void *f);
int fl_remove(const char * filename);
// Equivelant dirent.h
typedef struct fs_dir_list_status FL_DIR;
typedef struct fs_dir_ent fl_dirent;
FL_DIR* fl_opendir(const char* path, FL_DIR *dir);
int fl_readdir(FL_DIR *dirls, fl_dirent *entry);
int fl_closedir(FL_DIR* dir);
// Extensions
void fl_listdirectory(const char *path);
int fl_createdirectory(const char *path);
int fl_is_dir(const char *path);
int fl_format(uint32 volume_sectors, const char *name);
// Test hooks
#ifdef FATFS_INC_TEST_HOOKS
struct fatfs* fl_get_fs(void);
#endif
//-----------------------------------------------------------------------------
// Stdio file I/O names
//-----------------------------------------------------------------------------
#ifdef USE_FILELIB_STDIO_COMPAT_NAMES
#define FILE FL_FILE
#define fopen(a,b) fl_fopen(a, b)
#define fclose(a) fl_fclose(a)
#define fflush(a) fl_fflush(a)
#define fgetc(a) fl_fgetc(a)
#define fgets(a,b,c) fl_fgets(a, b, c)
#define fputc(a,b) fl_fputc(a, b)
#define fputs(a,b) fl_fputs(a, b)
#define fwrite(a,b,c,d) fl_fwrite(a, b, c, d)
#define fread(a,b,c,d) fl_fread(a, b, c, d)
#define fseek(a,b,c) fl_fseek(a, b, c)
#define fgetpos(a,b) fl_fgetpos(a, b)
#define ftell(a) fl_ftell(a)
#define feof(a) fl_feof(a)
#define remove(a) fl_remove(a)
#define mkdir(a) fl_createdirectory(a)
#define rmdir(a) 0
#endif
#endif

@ -0,0 +1,532 @@
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// FAT16/32 File IO Library
// V2.6
// Ultra-Embedded.com
// Copyright 2003 - 2012
//
// Email: admin@ultra-embedded.com
//
// License: GPL
// If you would like a version with a more permissive license for use in
// closed source commercial applications please contact me for details.
//-----------------------------------------------------------------------------
//
// This file is part of FAT File IO Library.
//
// FAT File IO Library 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.
//
// FAT File IO Library 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 FAT File IO Library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
#include <string.h>
#include "fat_defs.h"
#include "fat_access.h"
#include "fat_table.h"
#include "fat_write.h"
#include "fat_string.h"
#include "fat_misc.h"
#include "fat_format.h"
#if FATFS_INC_FORMAT_SUPPORT
//-----------------------------------------------------------------------------
// Tables
//-----------------------------------------------------------------------------
struct sec_per_clus_table
{
uint32 sectors;
uint8 sectors_per_cluster;
};
struct sec_per_clus_table _cluster_size_table16[] =
{
{ 32680, 2}, // 16MB - 1K
{ 262144, 4}, // 128MB - 2K
{ 524288, 8}, // 256MB - 4K
{ 1048576, 16}, // 512MB - 8K
{ 2097152, 32}, // 1GB - 16K
{ 4194304, 64}, // 2GB - 32K
{ 8388608, 128},// 2GB - 64K [Warning only supported by Windows XP onwards]
{ 0 , 0 } // Invalid
};
struct sec_per_clus_table _cluster_size_table32[] =
{
{ 532480, 1}, // 260MB - 512b
{ 16777216, 8}, // 8GB - 4K
{ 33554432, 16}, // 16GB - 8K
{ 67108864, 32}, // 32GB - 16K
{ 0xFFFFFFFF, 64},// >32GB - 32K
{ 0 , 0 } // Invalid
};
//-----------------------------------------------------------------------------
// fatfs_calc_cluster_size: Calculate what cluster size should be used
//-----------------------------------------------------------------------------
static uint8 fatfs_calc_cluster_size(uint32 sectors, int is_fat32)
{
int i;
if (!is_fat32)
{
for (i=0; _cluster_size_table16[i].sectors_per_cluster != 0;i++)
if (sectors <= _cluster_size_table16[i].sectors)
return _cluster_size_table16[i].sectors_per_cluster;
}
else
{
for (i=0; _cluster_size_table32[i].sectors_per_cluster != 0;i++)
if (sectors <= _cluster_size_table32[i].sectors)
return _cluster_size_table32[i].sectors_per_cluster;
}
return 0;
}
//-----------------------------------------------------------------------------
// fatfs_erase_sectors: Erase a number of sectors
//-----------------------------------------------------------------------------
static int fatfs_erase_sectors(struct fatfs *fs, uint32 lba, int count)
{
int i;
// Zero sector first
memset(fs->currentsector.sector, 0, FAT_SECTOR_SIZE);
for (i=0;i<count;i++)
if (!fs->disk_io.write_media(lba + i, fs->currentsector.sector, 1))
return 0;
return 1;
}
//-----------------------------------------------------------------------------
// fatfs_create_boot_sector: Create the boot sector
//-----------------------------------------------------------------------------
static int fatfs_create_boot_sector(struct fatfs *fs, uint32 boot_sector_lba, uint32 vol_sectors, const char *name, int is_fat32)
{
uint32 total_clusters;
int i;
// Zero sector initially
memset(fs->currentsector.sector, 0, FAT_SECTOR_SIZE);
// OEM Name & Jump Code
fs->currentsector.sector[0] = 0xEB;
fs->currentsector.sector[1] = 0x3C;
fs->currentsector.sector[2] = 0x90;
fs->currentsector.sector[3] = 0x4D;
fs->currentsector.sector[4] = 0x53;
fs->currentsector.sector[5] = 0x44;
fs->currentsector.sector[6] = 0x4F;
fs->currentsector.sector[7] = 0x53;
fs->currentsector.sector[8] = 0x35;
fs->currentsector.sector[9] = 0x2E;
fs->currentsector.sector[10] = 0x30;
// Bytes per sector
fs->currentsector.sector[11] = (FAT_SECTOR_SIZE >> 0) & 0xFF;
fs->currentsector.sector[12] = (FAT_SECTOR_SIZE >> 8) & 0xFF;
// Get sectors per cluster size for the disk
fs->sectors_per_cluster = fatfs_calc_cluster_size(vol_sectors, is_fat32);
if (!fs->sectors_per_cluster)
return 0; // Invalid disk size
// Sectors per cluster
fs->currentsector.sector[13] = fs->sectors_per_cluster;
// Reserved Sectors
if (!is_fat32)
fs->reserved_sectors = 8;
else
fs->reserved_sectors = 32;
fs->currentsector.sector[14] = (fs->reserved_sectors >> 0) & 0xFF;
fs->currentsector.sector[15] = (fs->reserved_sectors >> 8) & 0xFF;
// Number of FATS
fs->num_of_fats = 2;
fs->currentsector.sector[16] = fs->num_of_fats;
// Max entries in root dir (FAT16 only)
if (!is_fat32)
{
fs->root_entry_count = 512;
fs->currentsector.sector[17] = (fs->root_entry_count >> 0) & 0xFF;
fs->currentsector.sector[18] = (fs->root_entry_count >> 8) & 0xFF;
}
else
{
fs->root_entry_count = 0;
fs->currentsector.sector[17] = 0;
fs->currentsector.sector[18] = 0;
}
// [FAT16] Total sectors (use FAT32 count instead)
fs->currentsector.sector[19] = 0x00;
fs->currentsector.sector[20] = 0x00;
// Media type
fs->currentsector.sector[21] = 0xF8;
// FAT16 BS Details
if (!is_fat32)
{
// Count of sectors used by the FAT table (FAT16 only)
total_clusters = (vol_sectors / fs->sectors_per_cluster) + 1;
fs->fat_sectors = (total_clusters/(FAT_SECTOR_SIZE/2)) + 1;
fs->currentsector.sector[22] = (uint8)((fs->fat_sectors >> 0) & 0xFF);
fs->currentsector.sector[23] = (uint8)((fs->fat_sectors >> 8) & 0xFF);
// Sectors per track
fs->currentsector.sector[24] = 0x00;
fs->currentsector.sector[25] = 0x00;
// Heads
fs->currentsector.sector[26] = 0x00;
fs->currentsector.sector[27] = 0x00;
// Hidden sectors
fs->currentsector.sector[28] = 0x20;
fs->currentsector.sector[29] = 0x00;
fs->currentsector.sector[30] = 0x00;
fs->currentsector.sector[31] = 0x00;
// Total sectors for this volume
fs->currentsector.sector[32] = (uint8)((vol_sectors>>0)&0xFF);
fs->currentsector.sector[33] = (uint8)((vol_sectors>>8)&0xFF);
fs->currentsector.sector[34] = (uint8)((vol_sectors>>16)&0xFF);
fs->currentsector.sector[35] = (uint8)((vol_sectors>>24)&0xFF);
// Drive number
fs->currentsector.sector[36] = 0x00;
// Reserved
fs->currentsector.sector[37] = 0x00;
// Boot signature
fs->currentsector.sector[38] = 0x29;
// Volume ID
fs->currentsector.sector[39] = 0x12;
fs->currentsector.sector[40] = 0x34;
fs->currentsector.sector[41] = 0x56;
fs->currentsector.sector[42] = 0x78;
// Volume name
for (i=0;i<11;i++)
{
if (i < (int)strlen(name))
fs->currentsector.sector[i+43] = name[i];
else
fs->currentsector.sector[i+43] = ' ';
}
// File sys type
fs->currentsector.sector[54] = 'F';
fs->currentsector.sector[55] = 'A';
fs->currentsector.sector[56] = 'T';
fs->currentsector.sector[57] = '1';
fs->currentsector.sector[58] = '6';
fs->currentsector.sector[59] = ' ';
fs->currentsector.sector[60] = ' ';
fs->currentsector.sector[61] = ' ';
// Signature
fs->currentsector.sector[510] = 0x55;
fs->currentsector.sector[511] = 0xAA;
}
// FAT32 BS Details
else
{
// Count of sectors used by the FAT table (FAT16 only)
fs->currentsector.sector[22] = 0;
fs->currentsector.sector[23] = 0;
// Sectors per track (default)
fs->currentsector.sector[24] = 0x3F;
fs->currentsector.sector[25] = 0x00;
// Heads (default)
fs->currentsector.sector[26] = 0xFF;
fs->currentsector.sector[27] = 0x00;
// Hidden sectors
fs->currentsector.sector[28] = 0x00;
fs->currentsector.sector[29] = 0x00;
fs->currentsector.sector[30] = 0x00;
fs->currentsector.sector[31] = 0x00;
// Total sectors for this volume
fs->currentsector.sector[32] = (uint8)((vol_sectors>>0)&0xFF);
fs->currentsector.sector[33] = (uint8)((vol_sectors>>8)&0xFF);
fs->currentsector.sector[34] = (uint8)((vol_sectors>>16)&0xFF);
fs->currentsector.sector[35] = (uint8)((vol_sectors>>24)&0xFF);
total_clusters = (vol_sectors / fs->sectors_per_cluster) + 1;
fs->fat_sectors = (total_clusters/(FAT_SECTOR_SIZE/4)) + 1;
// BPB_FATSz32
fs->currentsector.sector[36] = (uint8)((fs->fat_sectors>>0)&0xFF);
fs->currentsector.sector[37] = (uint8)((fs->fat_sectors>>8)&0xFF);
fs->currentsector.sector[38] = (uint8)((fs->fat_sectors>>16)&0xFF);
fs->currentsector.sector[39] = (uint8)((fs->fat_sectors>>24)&0xFF);
// BPB_ExtFlags
fs->currentsector.sector[40] = 0;
fs->currentsector.sector[41] = 0;
// BPB_FSVer
fs->currentsector.sector[42] = 0;
fs->currentsector.sector[43] = 0;
// BPB_RootClus
fs->currentsector.sector[44] = (uint8)((fs->rootdir_first_cluster>>0)&0xFF);
fs->currentsector.sector[45] = (uint8)((fs->rootdir_first_cluster>>8)&0xFF);
fs->currentsector.sector[46] = (uint8)((fs->rootdir_first_cluster>>16)&0xFF);
fs->currentsector.sector[47] = (uint8)((fs->rootdir_first_cluster>>24)&0xFF);
// BPB_FSInfo
fs->currentsector.sector[48] = (uint8)((fs->fs_info_sector>>0)&0xFF);
fs->currentsector.sector[49] = (uint8)((fs->fs_info_sector>>8)&0xFF);
// BPB_BkBootSec
fs->currentsector.sector[50] = 6;
fs->currentsector.sector[51] = 0;
// Drive number
fs->currentsector.sector[64] = 0x00;
// Boot signature
fs->currentsector.sector[66] = 0x29;
// Volume ID
fs->currentsector.sector[67] = 0x12;
fs->currentsector.sector[68] = 0x34;
fs->currentsector.sector[69] = 0x56;
fs->currentsector.sector[70] = 0x78;
// Volume name
for (i=0;i<11;i++)
{
if (i < (int)strlen(name))
fs->currentsector.sector[i+71] = name[i];
else
fs->currentsector.sector[i+71] = ' ';
}
// File sys type
fs->currentsector.sector[82] = 'F';
fs->currentsector.sector[83] = 'A';
fs->currentsector.sector[84] = 'T';
fs->currentsector.sector[85] = '3';
fs->currentsector.sector[86] = '2';
fs->currentsector.sector[87] = ' ';
fs->currentsector.sector[88] = ' ';
fs->currentsector.sector[89] = ' ';
// Signature
fs->currentsector.sector[510] = 0x55;
fs->currentsector.sector[511] = 0xAA;
}
if (fs->disk_io.write_media(boot_sector_lba, fs->currentsector.sector, 1))
return 1;
else
return 0;
}
//-----------------------------------------------------------------------------
// fatfs_create_fsinfo_sector: Create the FSInfo sector (FAT32)
//-----------------------------------------------------------------------------
static int fatfs_create_fsinfo_sector(struct fatfs *fs, uint32 sector_lba)
{
// Zero sector initially
memset(fs->currentsector.sector, 0, FAT_SECTOR_SIZE);
// FSI_LeadSig
fs->currentsector.sector[0] = 0x52;
fs->currentsector.sector[1] = 0x52;
fs->currentsector.sector[2] = 0x61;
fs->currentsector.sector[3] = 0x41;
// FSI_StrucSig
fs->currentsector.sector[484] = 0x72;
fs->currentsector.sector[485] = 0x72;
fs->currentsector.sector[486] = 0x41;
fs->currentsector.sector[487] = 0x61;
// FSI_Free_Count
fs->currentsector.sector[488] = 0xFF;
fs->currentsector.sector[489] = 0xFF;
fs->currentsector.sector[490] = 0xFF;
fs->currentsector.sector[491] = 0xFF;
// FSI_Nxt_Free
fs->currentsector.sector[492] = 0xFF;
fs->currentsector.sector[493] = 0xFF;
fs->currentsector.sector[494] = 0xFF;
fs->currentsector.sector[495] = 0xFF;
// Signature
fs->currentsector.sector[510] = 0x55;
fs->currentsector.sector[511] = 0xAA;
if (fs->disk_io.write_media(sector_lba, fs->currentsector.sector, 1))
return 1;
else
return 0;
}
//-----------------------------------------------------------------------------
// fatfs_erase_fat: Erase FAT table using fs details in fs struct
//-----------------------------------------------------------------------------
static int fatfs_erase_fat(struct fatfs *fs, int is_fat32)
{
uint32 i;
// Zero sector initially
memset(fs->currentsector.sector, 0, FAT_SECTOR_SIZE);
// Initialise default allocate / reserved clusters
if (!is_fat32)
{
SET_16BIT_WORD(fs->currentsector.sector, 0, 0xFFF8);
SET_16BIT_WORD(fs->currentsector.sector, 2, 0xFFFF);
}
else
{
SET_32BIT_WORD(fs->currentsector.sector, 0, 0x0FFFFFF8);
SET_32BIT_WORD(fs->currentsector.sector, 4, 0xFFFFFFFF);
SET_32BIT_WORD(fs->currentsector.sector, 8, 0x0FFFFFFF);
}
if (!fs->disk_io.write_media(fs->fat_begin_lba + 0, fs->currentsector.sector, 1))
return 0;
// Zero remaining FAT sectors
memset(fs->currentsector.sector, 0, FAT_SECTOR_SIZE);
for (i=1;i<fs->fat_sectors*fs->num_of_fats;i++)
if (!fs->disk_io.write_media(fs->fat_begin_lba + i, fs->currentsector.sector, 1))
return 0;
return 1;
}
//-----------------------------------------------------------------------------
// fatfs_format_fat16: Format a FAT16 partition
//-----------------------------------------------------------------------------
int fatfs_format_fat16(struct fatfs *fs, uint32 volume_sectors, const char *name)
{
fs->currentsector.address = FAT32_INVALID_CLUSTER;
fs->currentsector.dirty = 0;
fs->next_free_cluster = 0; // Invalid
fatfs_fat_init(fs);
// Make sure we have read + write functions
if (!fs->disk_io.read_media || !fs->disk_io.write_media)
return FAT_INIT_MEDIA_ACCESS_ERROR;
// Volume is FAT16
fs->fat_type = FAT_TYPE_16;
// Not valid for FAT16
fs->fs_info_sector = 0;
fs->rootdir_first_cluster = 0;
// Sector 0: Boot sector
// NOTE: We don't need an MBR, it is a waste of a good sector!
fs->lba_begin = 0;
if (!fatfs_create_boot_sector(fs, fs->lba_begin, volume_sectors, name, 0))
return 0;
// For FAT16 (which this may be), rootdir_first_cluster is actuall rootdir_first_sector
fs->rootdir_first_sector = fs->reserved_sectors + (fs->num_of_fats * fs->fat_sectors);
fs->rootdir_sectors = ((fs->root_entry_count * 32) + (FAT_SECTOR_SIZE - 1)) / FAT_SECTOR_SIZE;
// First FAT LBA address
fs->fat_begin_lba = fs->lba_begin + fs->reserved_sectors;
// The address of the first data cluster on this volume
fs->cluster_begin_lba = fs->fat_begin_lba + (fs->num_of_fats * fs->fat_sectors);
// Initialise FAT sectors
if (!fatfs_erase_fat(fs, 0))
return 0;
// Erase Root directory
if (!fatfs_erase_sectors(fs, fs->lba_begin + fs->rootdir_first_sector, fs->rootdir_sectors))
return 0;
return 1;
}
//-----------------------------------------------------------------------------
// fatfs_format_fat32: Format a FAT32 partition
//-----------------------------------------------------------------------------
int fatfs_format_fat32(struct fatfs *fs, uint32 volume_sectors, const char *name)
{
fs->currentsector.address = FAT32_INVALID_CLUSTER;
fs->currentsector.dirty = 0;
fs->next_free_cluster = 0; // Invalid
fatfs_fat_init(fs);
// Make sure we have read + write functions
if (!fs->disk_io.read_media || !fs->disk_io.write_media)
return FAT_INIT_MEDIA_ACCESS_ERROR;
// Volume is FAT32
fs->fat_type = FAT_TYPE_32;
// Basic defaults for normal FAT32 partitions
fs->fs_info_sector = 1;
fs->rootdir_first_cluster = 2;
// Sector 0: Boot sector
// NOTE: We don't need an MBR, it is a waste of a good sector!
fs->lba_begin = 0;
if (!fatfs_create_boot_sector(fs, fs->lba_begin, volume_sectors, name, 1))
return 0;
// First FAT LBA address
fs->fat_begin_lba = fs->lba_begin + fs->reserved_sectors;
// The address of the first data cluster on this volume
fs->cluster_begin_lba = fs->fat_begin_lba + (fs->num_of_fats * fs->fat_sectors);
// Initialise FSInfo sector
if (!fatfs_create_fsinfo_sector(fs, fs->fs_info_sector))
return 0;
// Initialise FAT sectors
if (!fatfs_erase_fat(fs, 1))
return 0;
// Erase Root directory
if (!fatfs_erase_sectors(fs, fatfs_lba_of_cluster(fs, fs->rootdir_first_cluster), fs->sectors_per_cluster))
return 0;
return 1;
}
//-----------------------------------------------------------------------------
// fatfs_format: Format a partition with either FAT16 or FAT32 based on size
//-----------------------------------------------------------------------------
int fatfs_format(struct fatfs *fs, uint32 volume_sectors, const char *name)
{
// 2GB - 32K limit for safe behaviour for FAT16
if (volume_sectors <= 4194304)
return fatfs_format_fat16(fs, volume_sectors, name);
else
return fatfs_format_fat32(fs, volume_sectors, name);
}
#endif /*FATFS_INC_FORMAT_SUPPORT*/

@ -0,0 +1,15 @@
#ifndef __FAT_FORMAT_H__
#define __FAT_FORMAT_H__
#include "fat_defs.h"
#include "fat_opts.h"
#include "fat_access.h"
//-----------------------------------------------------------------------------
// Prototypes
//-----------------------------------------------------------------------------
int fatfs_format(struct fatfs *fs, uint32 volume_sectors, const char *name);
int fatfs_format_fat16(struct fatfs *fs, uint32 volume_sectors, const char *name);
int fatfs_format_fat32(struct fatfs *fs, uint32 volume_sectors, const char *name);
#endif

@ -0,0 +1,161 @@
#ifndef __FAT_LIST_H__
#define __FAT_LIST_H__
#ifndef FAT_ASSERT
#define FAT_ASSERT(x)
#endif
#ifndef FAT_INLINE
#define FAT_INLINE
#endif
//-----------------------------------------------------------------
// Types
//-----------------------------------------------------------------
struct fat_list;
struct fat_node
{
struct fat_node *previous;
struct fat_node *next;
};
struct fat_list
{
struct fat_node *head;
struct fat_node *tail;
};
//-----------------------------------------------------------------
// Macros
//-----------------------------------------------------------------
#define fat_list_entry(p, t, m) p ? ((t *)((char *)(p)-(char*)(&((t *)0)->m))) : 0
#define fat_list_next(l, p) (p)->next
#define fat_list_prev(l, p) (p)->previous
#define fat_list_first(l) (l)->head
#define fat_list_last(l) (l)->tail
#define fat_list_for_each(l, p) for ((p) = (l)->head; (p); (p) = (p)->next)
//-----------------------------------------------------------------
// Inline Functions
//-----------------------------------------------------------------
//-----------------------------------------------------------------
// fat_list_init:
//-----------------------------------------------------------------
static FAT_INLINE void fat_list_init(struct fat_list *list)
{
FAT_ASSERT(list);
list->head = list->tail = 0;
}
//-----------------------------------------------------------------
// fat_list_remove:
//-----------------------------------------------------------------
static FAT_INLINE void fat_list_remove(struct fat_list *list, struct fat_node *node)
{
FAT_ASSERT(list);
FAT_ASSERT(node);
if(!node->previous)
list->head = node->next;
else
node->previous->next = node->next;
if(!node->next)
list->tail = node->previous;
else
node->next->previous = node->previous;
}
//-----------------------------------------------------------------
// fat_list_insert_after:
//-----------------------------------------------------------------
static FAT_INLINE void fat_list_insert_after(struct fat_list *list, struct fat_node *node, struct fat_node *new_node)
{
FAT_ASSERT(list);
FAT_ASSERT(node);
FAT_ASSERT(new_node);
new_node->previous = node;
new_node->next = node->next;
if (!node->next)
list->tail = new_node;
else
node->next->previous = new_node;
node->next = new_node;
}
//-----------------------------------------------------------------
// fat_list_insert_before:
//-----------------------------------------------------------------
static FAT_INLINE void fat_list_insert_before(struct fat_list *list, struct fat_node *node, struct fat_node *new_node)
{
FAT_ASSERT(list);
FAT_ASSERT(node);
FAT_ASSERT(new_node);
new_node->previous = node->previous;
new_node->next = node;
if (!node->previous)
list->head = new_node;
else
node->previous->next = new_node;
node->previous = new_node;
}
//-----------------------------------------------------------------
// fat_list_insert_first:
//-----------------------------------------------------------------
static FAT_INLINE void fat_list_insert_first(struct fat_list *list, struct fat_node *node)
{
FAT_ASSERT(list);
FAT_ASSERT(node);
if (!list->head)
{
list->head = node;
list->tail = node;
node->previous = 0;
node->next = 0;
}
else
fat_list_insert_before(list, list->head, node);
}
//-----------------------------------------------------------------
// fat_list_insert_last:
//-----------------------------------------------------------------
static FAT_INLINE void fat_list_insert_last(struct fat_list *list, struct fat_node *node)
{
FAT_ASSERT(list);
FAT_ASSERT(node);
if (!list->tail)
fat_list_insert_first(list, node);
else
fat_list_insert_after(list, list->tail, node);
}
//-----------------------------------------------------------------
// fat_list_is_empty:
//-----------------------------------------------------------------
static FAT_INLINE int fat_list_is_empty(struct fat_list *list)
{
FAT_ASSERT(list);
return !list->head;
}
//-----------------------------------------------------------------
// fat_list_pop_head:
//-----------------------------------------------------------------
static FAT_INLINE struct fat_node * fat_list_pop_head(struct fat_list *list)
{
struct fat_node * node;
FAT_ASSERT(list);
node = fat_list_first(list);
if (node)
fat_list_remove(list, node);
return node;
}
#endif

@ -0,0 +1,505 @@
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// FAT16/32 File IO Library
// V2.6
// Ultra-Embedded.com
// Copyright 2003 - 2012
//
// Email: admin@ultra-embedded.com
//
// License: GPL
// If you would like a version with a more permissive license for use in
// closed source commercial applications please contact me for details.
//-----------------------------------------------------------------------------
//
// This file is part of FAT File IO Library.
//
// FAT File IO Library 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.
//
// FAT File IO Library 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 FAT File IO Library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
#include <stdlib.h>
#include <string.h>
#include "fat_misc.h"
//-----------------------------------------------------------------------------
// fatfs_lfn_cache_init: Clear long file name cache
//-----------------------------------------------------------------------------
void fatfs_lfn_cache_init(struct lfn_cache *lfn, int wipeTable)
{
int i = 0;
lfn->no_of_strings = 0;
#if FATFS_INC_LFN_SUPPORT
// Zero out buffer also
if (wipeTable)
for (i=0;i<MAX_LONGFILENAME_ENTRIES;i++)
memset(lfn->String[i], 0x00, MAX_LFN_ENTRY_LENGTH);
#endif
}
//-----------------------------------------------------------------------------
// fatfs_lfn_cache_entry - Function extracts long file name text from sector
// at a specific offset
//-----------------------------------------------------------------------------
#if FATFS_INC_LFN_SUPPORT
void fatfs_lfn_cache_entry(struct lfn_cache *lfn, uint8 *entryBuffer)
{
uint8 LFNIndex, i;
LFNIndex = entryBuffer[0] & 0x1F;
// Limit file name to cache size!
if (LFNIndex > MAX_LONGFILENAME_ENTRIES)
return ;
// This is an error condition
if (LFNIndex == 0)
return ;
if (lfn->no_of_strings == 0)
lfn->no_of_strings = LFNIndex;
lfn->String[LFNIndex-1][0] = entryBuffer[1];
lfn->String[LFNIndex-1][1] = entryBuffer[3];
lfn->String[LFNIndex-1][2] = entryBuffer[5];
lfn->String[LFNIndex-1][3] = entryBuffer[7];
lfn->String[LFNIndex-1][4] = entryBuffer[9];
lfn->String[LFNIndex-1][5] = entryBuffer[0x0E];
lfn->String[LFNIndex-1][6] = entryBuffer[0x10];
lfn->String[LFNIndex-1][7] = entryBuffer[0x12];
lfn->String[LFNIndex-1][8] = entryBuffer[0x14];
lfn->String[LFNIndex-1][9] = entryBuffer[0x16];
lfn->String[LFNIndex-1][10] = entryBuffer[0x18];
lfn->String[LFNIndex-1][11] = entryBuffer[0x1C];
lfn->String[LFNIndex-1][12] = entryBuffer[0x1E];
for (i=0; i<MAX_LFN_ENTRY_LENGTH; i++)
if (lfn->String[LFNIndex-1][i]==0xFF)
lfn->String[LFNIndex-1][i] = 0x20; // Replace with spaces
}
#endif
//-----------------------------------------------------------------------------
// fatfs_lfn_cache_get: Get a reference to the long filename
//-----------------------------------------------------------------------------
#if FATFS_INC_LFN_SUPPORT
char* fatfs_lfn_cache_get(struct lfn_cache *lfn)
{
// Null terminate long filename
if (lfn->no_of_strings == MAX_LONGFILENAME_ENTRIES)
lfn->Null = '\0';
else if (lfn->no_of_strings)
lfn->String[lfn->no_of_strings][0] = '\0';
else
lfn->String[0][0] = '\0';
return (char*)&lfn->String[0][0];
}
#endif
//-----------------------------------------------------------------------------
// fatfs_entry_lfn_text: If LFN text entry found
//-----------------------------------------------------------------------------
#if FATFS_INC_LFN_SUPPORT
int fatfs_entry_lfn_text(struct fat_dir_entry *entry)
{
if ((entry->Attr & FILE_ATTR_LFN_TEXT) == FILE_ATTR_LFN_TEXT)
return 1;
else
return 0;
}
#endif
//-----------------------------------------------------------------------------
// fatfs_entry_lfn_invalid: If SFN found not relating to LFN
//-----------------------------------------------------------------------------
#if FATFS_INC_LFN_SUPPORT
int fatfs_entry_lfn_invalid(struct fat_dir_entry *entry)
{
if ( (entry->Name[0]==FILE_HEADER_BLANK) ||
(entry->Name[0]==FILE_HEADER_DELETED)||
(entry->Attr==FILE_ATTR_VOLUME_ID) ||
(entry->Attr & FILE_ATTR_SYSHID) )
return 1;
else
return 0;
}
#endif
//-----------------------------------------------------------------------------
// fatfs_entry_lfn_exists: If LFN exists and correlation SFN found
//-----------------------------------------------------------------------------
#if FATFS_INC_LFN_SUPPORT
int fatfs_entry_lfn_exists(struct lfn_cache *lfn, struct fat_dir_entry *entry)
{
if ( (entry->Attr!=FILE_ATTR_LFN_TEXT) &&
(entry->Name[0]!=FILE_HEADER_BLANK) &&
(entry->Name[0]!=FILE_HEADER_DELETED) &&
(entry->Attr!=FILE_ATTR_VOLUME_ID) &&
(!(entry->Attr&FILE_ATTR_SYSHID)) &&
(lfn->no_of_strings) )
return 1;
else
return 0;
}
#endif
//-----------------------------------------------------------------------------
// fatfs_entry_sfn_only: If SFN only exists
//-----------------------------------------------------------------------------
int fatfs_entry_sfn_only(struct fat_dir_entry *entry)
{
if ( (entry->Attr!=FILE_ATTR_LFN_TEXT) &&
(entry->Name[0]!=FILE_HEADER_BLANK) &&
(entry->Name[0]!=FILE_HEADER_DELETED) &&
(entry->Attr!=FILE_ATTR_VOLUME_ID) &&
(!(entry->Attr&FILE_ATTR_SYSHID)) )
return 1;
else
return 0;
}
// TODO: FILE_ATTR_SYSHID ?!?!??!
//-----------------------------------------------------------------------------
// fatfs_entry_is_dir: Returns 1 if a directory
//-----------------------------------------------------------------------------
int fatfs_entry_is_dir(struct fat_dir_entry *entry)
{
if (entry->Attr & FILE_TYPE_DIR)
return 1;
else
return 0;
}
//-----------------------------------------------------------------------------
// fatfs_entry_is_file: Returns 1 is a file entry
//-----------------------------------------------------------------------------
int fatfs_entry_is_file(struct fat_dir_entry *entry)
{
if (entry->Attr & FILE_TYPE_FILE)
return 1;
else
return 0;
}
//-----------------------------------------------------------------------------
// fatfs_lfn_entries_required: Calculate number of 13 characters entries
//-----------------------------------------------------------------------------
#if FATFS_INC_LFN_SUPPORT
int fatfs_lfn_entries_required(char *filename)
{
int length = (int)strlen(filename);
if (length)
return (length + MAX_LFN_ENTRY_LENGTH - 1) / MAX_LFN_ENTRY_LENGTH;
else
return 0;
}
#endif
//-----------------------------------------------------------------------------
// fatfs_filename_to_lfn:
//-----------------------------------------------------------------------------
#if FATFS_INC_LFN_SUPPORT
void fatfs_filename_to_lfn(char *filename, uint8 *buffer, int entry, uint8 sfnChk)
{
int i;
int nameIndexes[MAX_LFN_ENTRY_LENGTH] = {1,3,5,7,9,0x0E,0x10,0x12,0x14,0x16,0x18,0x1C,0x1E};
// 13 characters entries
int length = (int)strlen(filename);
int entriesRequired = fatfs_lfn_entries_required(filename);
// Filename offset
int start = entry * MAX_LFN_ENTRY_LENGTH;
// Initialise to zeros
memset(buffer, 0x00, FAT_DIR_ENTRY_SIZE);
// LFN entry number
buffer[0] = (uint8)(((entriesRequired-1)==entry)?(0x40|(entry+1)):(entry+1));
// LFN flag
buffer[11] = 0x0F;
// Checksum of short filename
buffer[13] = sfnChk;
// Copy to buffer
for (i=0;i<MAX_LFN_ENTRY_LENGTH;i++)
{
if ( (start+i) < length )
buffer[nameIndexes[i]] = filename[start+i];
else if ( (start+i) == length )
buffer[nameIndexes[i]] = 0x00;
else
{
buffer[nameIndexes[i]] = 0xFF;
buffer[nameIndexes[i]+1] = 0xFF;
}
}
}
#endif
//-----------------------------------------------------------------------------
// fatfs_sfn_create_entry: Create the short filename directory entry
//-----------------------------------------------------------------------------
#if FATFS_INC_WRITE_SUPPORT
void fatfs_sfn_create_entry(char *shortfilename, uint32 size, uint32 startCluster, struct fat_dir_entry *entry, int dir)
{
int i;
// Copy short filename
for (i=0;i<FAT_SFN_SIZE_FULL;i++)
entry->Name[i] = shortfilename[i];
// Unless we have a RTC we might as well set these to 1980
entry->CrtTimeTenth = 0x00;
entry->CrtTime[1] = entry->CrtTime[0] = 0x00;
entry->CrtDate[1] = 0x00;
entry->CrtDate[0] = 0x20;
entry->LstAccDate[1] = 0x00;
entry->LstAccDate[0] = 0x20;
entry->WrtTime[1] = entry->WrtTime[0] = 0x00;
entry->WrtDate[1] = 0x00;
entry->WrtDate[0] = 0x20;
if (!dir)
entry->Attr = FILE_TYPE_FILE;
else
entry->Attr = FILE_TYPE_DIR;
entry->NTRes = 0x00;
entry->FstClusHI = FAT_HTONS((uint16)((startCluster>>16) & 0xFFFF));
entry->FstClusLO = FAT_HTONS((uint16)((startCluster>>0) & 0xFFFF));
entry->FileSize = FAT_HTONL(size);
}
#endif
//-----------------------------------------------------------------------------
// fatfs_lfn_create_sfn: Create a padded SFN
//-----------------------------------------------------------------------------
#if FATFS_INC_WRITE_SUPPORT
int fatfs_lfn_create_sfn(char *sfn_output, char *filename)
{
int i;
int dotPos = -1;
char ext[3];
int pos;
int len = (int)strlen(filename);
// Invalid to start with .
if (filename[0]=='.')
return 0;
memset(sfn_output, ' ', FAT_SFN_SIZE_FULL);
memset(ext, ' ', 3);
// Find dot seperator
for (i = 0; i< len; i++)
{
if (filename[i]=='.')
dotPos = i;
}
// Extract extensions
if (dotPos!=-1)
{
// Copy first three chars of extension
for (i = (dotPos+1); i < (dotPos+1+3); i++)
if (i<len)
ext[i-(dotPos+1)] = filename[i];
// Shorten the length to the dot position
len = dotPos;
}
// Add filename part
pos = 0;
for (i=0;i<len;i++)
{
if ( (filename[i]!=' ') && (filename[i]!='.') )
{
if (filename[i] >= 'a' && filename[i] <= 'z')
sfn_output[pos++] = filename[i] - 'a' + 'A';
else
sfn_output[pos++] = filename[i];
}
// Fill upto 8 characters
if (pos==FAT_SFN_SIZE_PARTIAL)
break;
}
// Add extension part
for (i=FAT_SFN_SIZE_PARTIAL;i<FAT_SFN_SIZE_FULL;i++)
{
if (ext[i-FAT_SFN_SIZE_PARTIAL] >= 'a' && ext[i-FAT_SFN_SIZE_PARTIAL] <= 'z')
sfn_output[i] = ext[i-FAT_SFN_SIZE_PARTIAL] - 'a' + 'A';
else
sfn_output[i] = ext[i-FAT_SFN_SIZE_PARTIAL];
}
return 1;
}
//-----------------------------------------------------------------------------
// fatfs_itoa:
//-----------------------------------------------------------------------------
static void fatfs_itoa(uint32 num, char *s)
{
char* cp;
char outbuf[12];
const char digits[] = "0123456789ABCDEF";
// Build string backwards
cp = outbuf;
do
{
*cp++ = digits[(int)(num % 10)];
}
while ((num /= 10) > 0);
*cp-- = 0;
// Copy in forwards
while (cp >= outbuf)
*s++ = *cp--;
*s = 0;
}
#endif
//-----------------------------------------------------------------------------
// fatfs_lfn_generate_tail:
// sfn_input = Input short filename, spaced format & in upper case
// sfn_output = Output short filename with tail
//-----------------------------------------------------------------------------
#if FATFS_INC_LFN_SUPPORT
#if FATFS_INC_WRITE_SUPPORT
int fatfs_lfn_generate_tail(char *sfn_output, char *sfn_input, uint32 tailNum)
{
int tail_chars;
char tail_str[12];
if (tailNum > 99999)
return 0;
// Convert to number
memset(tail_str, 0x00, sizeof(tail_str));
tail_str[0] = '~';
fatfs_itoa(tailNum, tail_str+1);
// Copy in base filename
memcpy(sfn_output, sfn_input, FAT_SFN_SIZE_FULL);
// Overwrite with tail
tail_chars = (int)strlen(tail_str);
memcpy(sfn_output+(FAT_SFN_SIZE_PARTIAL-tail_chars), tail_str, tail_chars);
return 1;
}
#endif
#endif
//-----------------------------------------------------------------------------
// fatfs_convert_from_fat_time: Convert FAT time to h/m/s
//-----------------------------------------------------------------------------
#if FATFS_INC_TIME_DATE_SUPPORT
void fatfs_convert_from_fat_time(uint16 fat_time, int *hours, int *minutes, int *seconds)
{
*hours = (fat_time >> FAT_TIME_HOURS_SHIFT) & FAT_TIME_HOURS_MASK;
*minutes = (fat_time >> FAT_TIME_MINUTES_SHIFT) & FAT_TIME_MINUTES_MASK;
*seconds = (fat_time >> FAT_TIME_SECONDS_SHIFT) & FAT_TIME_SECONDS_MASK;
*seconds = *seconds * FAT_TIME_SECONDS_SCALE;
}
//-----------------------------------------------------------------------------
// fatfs_convert_from_fat_date: Convert FAT date to d/m/y
//-----------------------------------------------------------------------------
void fatfs_convert_from_fat_date(uint16 fat_date, int *day, int *month, int *year)
{
*day = (fat_date >> FAT_DATE_DAY_SHIFT) & FAT_DATE_DAY_MASK;
*month = (fat_date >> FAT_DATE_MONTH_SHIFT) & FAT_DATE_MONTH_MASK;
*year = (fat_date >> FAT_DATE_YEAR_SHIFT) & FAT_DATE_YEAR_MASK;
*year = *year + FAT_DATE_YEAR_OFFSET;
}
//-----------------------------------------------------------------------------
// fatfs_convert_to_fat_time: Convert h/m/s to FAT time
//-----------------------------------------------------------------------------
uint16 fatfs_convert_to_fat_time(int hours, int minutes, int seconds)
{
uint16 fat_time = 0;
// Most FAT times are to a resolution of 2 seconds
seconds /= FAT_TIME_SECONDS_SCALE;
fat_time = (hours & FAT_TIME_HOURS_MASK) << FAT_TIME_HOURS_SHIFT;
fat_time|= (minutes & FAT_TIME_MINUTES_MASK) << FAT_TIME_MINUTES_SHIFT;
fat_time|= (seconds & FAT_TIME_SECONDS_MASK) << FAT_TIME_SECONDS_SHIFT;
return fat_time;
}
//-----------------------------------------------------------------------------
// fatfs_convert_to_fat_date: Convert d/m/y to FAT date
//-----------------------------------------------------------------------------
uint16 fatfs_convert_to_fat_date(int day, int month, int year)
{
uint16 fat_date = 0;
// FAT dates are relative to 1980
if (year >= FAT_DATE_YEAR_OFFSET)
year -= FAT_DATE_YEAR_OFFSET;
fat_date = (day & FAT_DATE_DAY_MASK) << FAT_DATE_DAY_SHIFT;
fat_date|= (month & FAT_DATE_MONTH_MASK) << FAT_DATE_MONTH_SHIFT;
fat_date|= (year & FAT_DATE_YEAR_MASK) << FAT_DATE_YEAR_SHIFT;
return fat_date;
}
#endif
//-----------------------------------------------------------------------------
// fatfs_print_sector:
//-----------------------------------------------------------------------------
#ifdef FATFS_DEBUG
void fatfs_print_sector(uint32 sector, uint8 *data)
{
int i;
int j;
FAT_PRINTF(("Sector %d:\n", sector));
for (i=0;i<FAT_SECTOR_SIZE;i++)
{
if (!((i) % 16))
{
FAT_PRINTF((" %04d: ", i));
}
FAT_PRINTF(("%02x", data[i]));
if (!((i+1) % 4))
{
FAT_PRINTF((" "));
}
if (!((i+1) % 16))
{
FAT_PRINTF((" "));
for (j=0;j<16;j++)
{
char ch = data[i-15+j];
// Is printable?
if (ch > 31 && ch < 127)
{
FAT_PRINTF(("%c", ch));
}
else
{
FAT_PRINTF(("."));
}
}
FAT_PRINTF(("\n"));
}
}
}
#endif

@ -0,0 +1,63 @@
#ifndef __FAT_MISC_H__
#define __FAT_MISC_H__
#include "fat_defs.h"
#include "fat_opts.h"
//-----------------------------------------------------------------------------
// Defines
//-----------------------------------------------------------------------------
#define MAX_LONGFILENAME_ENTRIES 20
#define MAX_LFN_ENTRY_LENGTH 13
//-----------------------------------------------------------------------------
// Macros
//-----------------------------------------------------------------------------
#define GET_32BIT_WORD(buffer, location) ( ((uint32)buffer[location+3]<<24) + ((uint32)buffer[location+2]<<16) + ((uint32)buffer[location+1]<<8) + (uint32)buffer[location+0] )
#define GET_16BIT_WORD(buffer, location) ( ((uint16)buffer[location+1]<<8) + (uint16)buffer[location+0] )
#define SET_32BIT_WORD(buffer, location, value) { buffer[location+0] = (uint8)((value)&0xFF); \
buffer[location+1] = (uint8)((value>>8)&0xFF); \
buffer[location+2] = (uint8)((value>>16)&0xFF); \
buffer[location+3] = (uint8)((value>>24)&0xFF); }
#define SET_16BIT_WORD(buffer, location, value) { buffer[location+0] = (uint8)((value)&0xFF); \
buffer[location+1] = (uint8)((value>>8)&0xFF); }
//-----------------------------------------------------------------------------
// Structures
//-----------------------------------------------------------------------------
struct lfn_cache
{
#if FATFS_INC_LFN_SUPPORT
// Long File Name Structure (max 260 LFN length)
uint8 String[MAX_LONGFILENAME_ENTRIES][MAX_LFN_ENTRY_LENGTH];
uint8 Null;
#endif
uint8 no_of_strings;
};
//-----------------------------------------------------------------------------
// Prototypes
//-----------------------------------------------------------------------------
void fatfs_lfn_cache_init(struct lfn_cache *lfn, int wipeTable);
void fatfs_lfn_cache_entry(struct lfn_cache *lfn, uint8 *entryBuffer);
char* fatfs_lfn_cache_get(struct lfn_cache *lfn);
int fatfs_entry_lfn_text(struct fat_dir_entry *entry);
int fatfs_entry_lfn_invalid(struct fat_dir_entry *entry);
int fatfs_entry_lfn_exists(struct lfn_cache *lfn, struct fat_dir_entry *entry);
int fatfs_entry_sfn_only(struct fat_dir_entry *entry);
int fatfs_entry_is_dir(struct fat_dir_entry *entry);
int fatfs_entry_is_file(struct fat_dir_entry *entry);
int fatfs_lfn_entries_required(char *filename);
void fatfs_filename_to_lfn(char *filename, uint8 *buffer, int entry, uint8 sfnChk);
void fatfs_sfn_create_entry(char *shortfilename, uint32 size, uint32 startCluster, struct fat_dir_entry *entry, int dir);
int fatfs_lfn_create_sfn(char *sfn_output, char *filename);
int fatfs_lfn_generate_tail(char *sfn_output, char *sfn_input, uint32 tailNum);
void fatfs_convert_from_fat_time(uint16 fat_time, int *hours, int *minutes, int *seconds);
void fatfs_convert_from_fat_date(uint16 fat_date, int *day, int *month, int *year);
uint16 fatfs_convert_to_fat_time(int hours, int minutes, int seconds);
uint16 fatfs_convert_to_fat_date(int day, int month, int year);
void fatfs_print_sector(uint32 sector, uint8 *data);
#endif

@ -0,0 +1,90 @@
#ifndef __FAT_OPTS_H__
#define __FAT_OPTS_H__
#ifdef FATFS_USE_CUSTOM_OPTS_FILE
#include "fat_custom.h"
#endif
//-------------------------------------------------------------
// Configuration
//-------------------------------------------------------------
// Is the processor little endian (1) or big endian (0)
#ifndef FATFS_IS_LITTLE_ENDIAN
#define FATFS_IS_LITTLE_ENDIAN 1
#endif
// Max filename Length
#ifndef FATFS_MAX_LONG_FILENAME
#define FATFS_MAX_LONG_FILENAME 260
#endif
// Max open files (reduce to lower memory requirements)
#ifndef FATFS_MAX_OPEN_FILES
#define FATFS_MAX_OPEN_FILES 2
#endif
// Number of sectors per FAT_BUFFER (min 1)
#ifndef FAT_BUFFER_SECTORS
#define FAT_BUFFER_SECTORS 1
#endif
// Max FAT sectors to buffer (min 1)
// (mem used is FAT_BUFFERS * FAT_BUFFER_SECTORS * FAT_SECTOR_SIZE)
#ifndef FAT_BUFFERS
#define FAT_BUFFERS 1
#endif
// Size of cluster chain cache (can be undefined)
// Mem used = FAT_CLUSTER_CACHE_ENTRIES * 4 * 2
// Improves access speed considerably
//#define FAT_CLUSTER_CACHE_ENTRIES 128
// Include support for writing files (1 / 0)?
#ifndef FATFS_INC_WRITE_SUPPORT
#define FATFS_INC_WRITE_SUPPORT 1
#endif
// Support long filenames (1 / 0)?
// (if not (0) only 8.3 format is supported)
#ifndef FATFS_INC_LFN_SUPPORT
#define FATFS_INC_LFN_SUPPORT 1
#endif
// Support directory listing (1 / 0)?
#ifndef FATFS_DIR_LIST_SUPPORT
#define FATFS_DIR_LIST_SUPPORT 1
#endif
// Support time/date (1 / 0)?
#ifndef FATFS_INC_TIME_DATE_SUPPORT
#define FATFS_INC_TIME_DATE_SUPPORT 0
#endif
// Include support for formatting disks (1 / 0)?
#ifndef FATFS_INC_FORMAT_SUPPORT
#define FATFS_INC_FORMAT_SUPPORT 1
#endif
// Sector size used
#define FAT_SECTOR_SIZE 512
// Printf output (directory listing / debug)
#ifndef FAT_PRINTF
// Don't include stdio, but there is a printf function available
#ifdef FAT_PRINTF_NOINC_STDIO
extern int printf(const char* ctrl1, ... );
#define FAT_PRINTF(a) printf a
// Include stdio to use printf
#else
#include <stdio.h>
#define FAT_PRINTF(a) printf a
#endif
#endif
// Time/Date support requires time.h
#if FATFS_INC_TIME_DATE_SUPPORT
#include <time.h>
#endif
#endif

@ -0,0 +1,514 @@
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// FAT16/32 File IO Library
// V2.6
// Ultra-Embedded.com
// Copyright 2003 - 2012
//
// Email: admin@ultra-embedded.com
//
// License: GPL
// If you would like a version with a more permissive license for use in
// closed source commercial applications please contact me for details.
//-----------------------------------------------------------------------------
//
// This file is part of FAT File IO Library.
//
// FAT File IO Library 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.
//
// FAT File IO Library 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 FAT File IO Library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
#include <string.h>
#include <assert.h>
#include "fat_string.h"
//-----------------------------------------------------------------------------
// fatfs_total_path_levels: Take a filename and path and count the sub levels
// of folders. E.g. C:\folder\file.zip = 1 level
// Acceptable input formats are:
// c:\folder\file.zip
// /dev/etc/samba.conf
// Returns: -1 = Error, 0 or more = Ok
//-----------------------------------------------------------------------------
int fatfs_total_path_levels(char *path)
{
int levels = 0;
char expectedchar;
if (!path)
return -1;
// Acceptable formats:
// c:\folder\file.zip
// /dev/etc/samba.conf
if (*path == '/')
{
expectedchar = '/';
path++;
}
else if (path[1] == ':' || path[2] == '\\')
{
expectedchar = '\\';
path += 3;
}
else
return -1;
// Count levels in path string
while (*path)
{
// Fast forward through actual subdir text to next slash
for (; *path; )
{
// If slash detected escape from for loop
if (*path == expectedchar) { path++; break; }
path++;
}
// Increase number of subdirs founds
levels++;
}
// Subtract the file itself
return levels-1;
}
//-----------------------------------------------------------------------------
// fatfs_get_substring: Get a substring from 'path' which contains the folder
// (or file) at the specified level.
// E.g. C:\folder\file.zip : Level 0 = C:\folder, Level 1 = file.zip
// Returns: -1 = Error, 0 = Ok
//-----------------------------------------------------------------------------
int fatfs_get_substring(char *path, int levelreq, char *output, int max_len)
{
int i;
int pathlen=0;
int levels=0;
int copypnt=0;
char expectedchar;
if (!path || max_len <= 0)
return -1;
// Acceptable formats:
// c:\folder\file.zip
// /dev/etc/samba.conf
if (*path == '/')
{
expectedchar = '/';
path++;
}
else if (path[1] == ':' || path[2] == '\\')
{
expectedchar = '\\';
path += 3;
}
else
return -1;
// Get string length of path
pathlen = (int)strlen (path);
// Loop through the number of times as characters in 'path'
for (i = 0; i<pathlen; i++)
{
// If a '\' is found then increase level
if (*path == expectedchar) levels++;
// If correct level and the character is not a '\' or '/' then copy text to 'output'
if ( (levels == levelreq) && (*path != expectedchar) && (copypnt < (max_len-1)))
output[copypnt++] = *path;
// Increment through path string
path++;
}
// Null Terminate
output[copypnt] = '\0';
// If a string was copied return 0 else return 1
if (output[0] != '\0')
return 0; // OK
else
return -1; // Error
}
//-----------------------------------------------------------------------------
// fatfs_split_path: Full path contains the passed in string.
// Returned is the path string and file Name string
// E.g. C:\folder\file.zip -> path = C:\folder filename = file.zip
// E.g. C:\file.zip -> path = [blank] filename = file.zip
//-----------------------------------------------------------------------------
int fatfs_split_path(char *full_path, char *path, int max_path, char *filename, int max_filename)
{
int strindex;
// Count the levels to the filepath
int levels = fatfs_total_path_levels(full_path);
if (levels == -1)
return -1;
// Get filename part of string
if (fatfs_get_substring(full_path, levels, filename, max_filename) != 0)
return -1;
// If root file
if (levels == 0)
path[0] = '\0';
else
{
strindex = (int)strlen(full_path) - (int)strlen(filename);
if (strindex > max_path)
strindex = max_path;
memcpy(path, full_path, strindex);
path[strindex-1] = '\0';
}
return 0;
}
//-----------------------------------------------------------------------------
// FileString_StrCmpNoCase: Compare two strings case with case sensitivity
//-----------------------------------------------------------------------------
static int FileString_StrCmpNoCase(char *s1, char *s2, int n)
{
int diff;
char a,b;
while (n--)
{
a = *s1;
b = *s2;
// Make lower case if uppercase
if ((a>='A') && (a<='Z'))
a+= 32;
if ((b>='A') && (b<='Z'))
b+= 32;
diff = a - b;
// If different
if (diff)
return diff;
// If run out of strings
if ( (*s1 == 0) || (*s2 == 0) )
break;
s1++;
s2++;
}
return 0;
}
//-----------------------------------------------------------------------------
// FileString_GetExtension: Get index to extension within filename
// Returns -1 if not found or index otherwise
//-----------------------------------------------------------------------------
static int FileString_GetExtension(char *str)
{
int dotPos = -1;
char *strSrc = str;
// Find last '.' in string (if at all)
while (*strSrc)
{
if (*strSrc=='.')
dotPos = (int)(strSrc-str);
strSrc++;
}
return dotPos;
}
//-----------------------------------------------------------------------------
// FileString_TrimLength: Get length of string excluding trailing spaces
// Returns -1 if not found or index otherwise
//-----------------------------------------------------------------------------
static int FileString_TrimLength(char *str, int strLen)
{
int length = strLen;
char *strSrc = str+strLen-1;
// Find last non white space
while (strLen != 0)
{
if (*strSrc == ' ')
length = (int)(strSrc - str);
else
break;
strSrc--;
strLen--;
}
return length;
}
//-----------------------------------------------------------------------------
// fatfs_compare_names: Compare two filenames (without copying or changing origonals)
// Returns 1 if match, 0 if not
//-----------------------------------------------------------------------------
int fatfs_compare_names(char* strA, char* strB)
{
char *ext1 = NULL;
char *ext2 = NULL;
int ext1Pos, ext2Pos;
int file1Len, file2Len;
// Get both files extension
ext1Pos = FileString_GetExtension(strA);
ext2Pos = FileString_GetExtension(strB);
// NOTE: Extension position can be different for matching
// filename if trailing space are present before it!
// Check that if one has an extension, so does the other
if ((ext1Pos==-1) && (ext2Pos!=-1))
return 0;
if ((ext2Pos==-1) && (ext1Pos!=-1))
return 0;
// If they both have extensions, compare them
if (ext1Pos!=-1)
{
// Set pointer to start of extension
ext1 = strA+ext1Pos+1;
ext2 = strB+ext2Pos+1;
// Verify that the file extension lengths match!
if (strlen(ext1) != strlen(ext2))
return 0;
// If they dont match
if (FileString_StrCmpNoCase(ext1, ext2, (int)strlen(ext1))!=0)
return 0;
// Filelength is upto extensions
file1Len = ext1Pos;
file2Len = ext2Pos;
}
// No extensions
else
{
// Filelength is actual filelength
file1Len = (int)strlen(strA);
file2Len = (int)strlen(strB);
}
// Find length without trailing spaces (before ext)
file1Len = FileString_TrimLength(strA, file1Len);
file2Len = FileString_TrimLength(strB, file2Len);
// Check the file lengths match
if (file1Len!=file2Len)
return 0;
// Compare main part of filenames
if (FileString_StrCmpNoCase(strA, strB, file1Len)!=0)
return 0;
else
return 1;
}
//-----------------------------------------------------------------------------
// fatfs_string_ends_with_slash: Does the string end with a slash (\ or /)
//-----------------------------------------------------------------------------
int fatfs_string_ends_with_slash(char *path)
{
if (path)
{
while (*path)
{
// Last character?
if (!(*(path+1)))
{
if (*path == '\\' || *path == '/')
return 1;
}
path++;
}
}
return 0;
}
//-----------------------------------------------------------------------------
// fatfs_get_sfn_display_name: Get display name for SFN entry
//-----------------------------------------------------------------------------
int fatfs_get_sfn_display_name(char* out, char* in)
{
int len = 0;
while (*in && len <= 11)
{
char a = *in++;
if (a == ' ')
continue;
// Make lower case if uppercase
else if ((a>='A') && (a<='Z'))
a+= 32;
*out++ = a;
len++;
}
*out = '\0';
return 1;
}
//-----------------------------------------------------------------------------
// fatfs_get_extension: Get extension of filename passed in 'filename'.
// Returned extension is always lower case.
// Returns: 1 if ok, 0 if not.
//-----------------------------------------------------------------------------
int fatfs_get_extension(char* filename, char* out, int maxlen)
{
int len = 0;
// Get files extension offset
int ext_pos = FileString_GetExtension(filename);
if (ext_pos > 0 && out && maxlen)
{
filename += ext_pos + 1;
while (*filename && len < (maxlen-1))
{
char a = *filename++;
// Make lowercase if uppercase
if ((a>='A') && (a<='Z'))
a+= 32;
*out++ = a;
len++;
}
*out = '\0';
return 1;
}
return 0;
}
//-----------------------------------------------------------------------------
// fatfs_create_path_string: Append path & filename to create file path string.
// Returns: 1 if ok, 0 if not.
//-----------------------------------------------------------------------------
int fatfs_create_path_string(char* path, char *filename, char* out, int maxlen)
{
int len = 0;
char last = 0;
char seperator = '/';
if (path && filename && out && maxlen > 0)
{
while (*path && len < (maxlen-2))
{
last = *path++;
if (last == '\\')
seperator = '\\';
*out++ = last;
len++;
}
// Add a seperator if trailing one not found
if (last != '\\' && last != '/')
*out++ = seperator;
while (*filename && len < (maxlen-1))
{
*out++ = *filename++;
len++;
}
*out = '\0';
return 1;
}
return 0;
}
//-----------------------------------------------------------------------------
// Test Bench
//-----------------------------------------------------------------------------
#ifdef FAT_STRING_TESTBENCH
void main(void)
{
char output[255];
char output2[255];
assert(fatfs_total_path_levels("C:\\folder\\file.zip") == 1);
assert(fatfs_total_path_levels("C:\\file.zip") == 0);
assert(fatfs_total_path_levels("C:\\folder\\folder2\\file.zip") == 2);
assert(fatfs_total_path_levels("C:\\") == -1);
assert(fatfs_total_path_levels("") == -1);
assert(fatfs_total_path_levels("/dev/etc/file.zip") == 2);
assert(fatfs_total_path_levels("/dev/file.zip") == 1);
assert(fatfs_get_substring("C:\\folder\\file.zip", 0, output, sizeof(output)) == 0);
assert(strcmp(output, "folder") == 0);
assert(fatfs_get_substring("C:\\folder\\file.zip", 1, output, sizeof(output)) == 0);
assert(strcmp(output, "file.zip") == 0);
assert(fatfs_get_substring("/dev/etc/file.zip", 0, output, sizeof(output)) == 0);
assert(strcmp(output, "dev") == 0);
assert(fatfs_get_substring("/dev/etc/file.zip", 1, output, sizeof(output)) == 0);
assert(strcmp(output, "etc") == 0);
assert(fatfs_get_substring("/dev/etc/file.zip", 2, output, sizeof(output)) == 0);
assert(strcmp(output, "file.zip") == 0);
assert(fatfs_split_path("C:\\folder\\file.zip", output, sizeof(output), output2, sizeof(output2)) == 0);
assert(strcmp(output, "C:\\folder") == 0);
assert(strcmp(output2, "file.zip") == 0);
assert(fatfs_split_path("C:\\file.zip", output, sizeof(output), output2, sizeof(output2)) == 0);
assert(output[0] == 0);
assert(strcmp(output2, "file.zip") == 0);
assert(fatfs_split_path("/dev/etc/file.zip", output, sizeof(output), output2, sizeof(output2)) == 0);
assert(strcmp(output, "/dev/etc") == 0);
assert(strcmp(output2, "file.zip") == 0);
assert(FileString_GetExtension("C:\\file.zip") == strlen("C:\\file"));
assert(FileString_GetExtension("C:\\file.zip.ext") == strlen("C:\\file.zip"));
assert(FileString_GetExtension("C:\\file.zip.") == strlen("C:\\file.zip"));
assert(FileString_TrimLength("C:\\file.zip", strlen("C:\\file.zip")) == strlen("C:\\file.zip"));
assert(FileString_TrimLength("C:\\file.zip ", strlen("C:\\file.zip ")) == strlen("C:\\file.zip"));
assert(FileString_TrimLength(" ", strlen(" ")) == 0);
assert(fatfs_compare_names("C:\\file.ext", "C:\\file.ext") == 1);
assert(fatfs_compare_names("C:\\file2.ext", "C:\\file.ext") == 0);
assert(fatfs_compare_names("C:\\file .ext", "C:\\file.ext") == 1);
assert(fatfs_compare_names("C:\\file .ext", "C:\\file2.ext") == 0);
assert(fatfs_string_ends_with_slash("C:\\folder") == 0);
assert(fatfs_string_ends_with_slash("C:\\folder\\") == 1);
assert(fatfs_string_ends_with_slash("/path") == 0);
assert(fatfs_string_ends_with_slash("/path/a") == 0);
assert(fatfs_string_ends_with_slash("/path/") == 1);
assert(fatfs_get_extension("/mypath/file.wav", output, 4) == 1);
assert(strcmp(output, "wav") == 0);
assert(fatfs_get_extension("/mypath/file.WAV", output, 4) == 1);
assert(strcmp(output, "wav") == 0);
assert(fatfs_get_extension("/mypath/file.zip", output, 4) == 1);
assert(strcmp(output, "ext") != 0);
assert(fatfs_create_path_string("/mydir1", "myfile.txt", output, sizeof(output)) == 1);
assert(strcmp(output, "/mydir1/myfile.txt") == 0);
assert(fatfs_create_path_string("/mydir2/", "myfile2.txt", output, sizeof(output)) == 1);
assert(strcmp(output, "/mydir2/myfile2.txt") == 0);
assert(fatfs_create_path_string("C:\\mydir3", "myfile3.txt", output, sizeof(output)) == 1);
assert(strcmp(output, "C:\\mydir3\\myfile3.txt") == 0);
}
#endif

@ -0,0 +1,20 @@
#ifndef __FILESTRING_H__
#define __FILESTRING_H__
//-----------------------------------------------------------------------------
// Prototypes
//-----------------------------------------------------------------------------
int fatfs_total_path_levels(char *path);
int fatfs_get_substring(char *Path, int levelreq, char *output, int max_len);
int fatfs_split_path(char *FullPath, char *Path, int max_path, char *FileName, int max_filename);
int fatfs_compare_names(char* strA, char* strB);
int fatfs_string_ends_with_slash(char *path);
int fatfs_get_sfn_display_name(char* out, char* in);
int fatfs_get_extension(char* filename, char* out, int maxlen);
int fatfs_create_path_string(char* path, char *filename, char* out, int maxlen);
#ifndef NULL
#define NULL 0
#endif
#endif

@ -0,0 +1,478 @@
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// FAT16/32 File IO Library
// V2.6
// Ultra-Embedded.com
// Copyright 2003 - 2012
//
// Email: admin@ultra-embedded.com
//
// License: GPL
// If you would like a version with a more permissive license for use in
// closed source commercial applications please contact me for details.
//-----------------------------------------------------------------------------
//
// This file is part of FAT File IO Library.
//
// FAT File IO Library 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.
//
// FAT File IO Library 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 FAT File IO Library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
#include <string.h>
#include "fat_defs.h"
#include "fat_access.h"
#include "fat_table.h"
#ifndef FAT_BUFFERS
#define FAT_BUFFERS 1
#endif
#ifndef FAT_BUFFER_SECTORS
#define FAT_BUFFER_SECTORS 1
#endif
#if FAT_BUFFERS < 1 || FAT_BUFFER_SECTORS < 1
#error "FAT_BUFFERS & FAT_BUFFER_SECTORS must be at least 1"
#endif
//-----------------------------------------------------------------------------
// FAT Sector Buffer
//-----------------------------------------------------------------------------
#define FAT32_GET_32BIT_WORD(pbuf, location) ( GET_32BIT_WORD(pbuf->ptr, location) )
#define FAT32_SET_32BIT_WORD(pbuf, location, value) { SET_32BIT_WORD(pbuf->ptr, location, value); pbuf->dirty = 1; }
#define FAT16_GET_16BIT_WORD(pbuf, location) ( GET_16BIT_WORD(pbuf->ptr, location) )
#define FAT16_SET_16BIT_WORD(pbuf, location, value) { SET_16BIT_WORD(pbuf->ptr, location, value); pbuf->dirty = 1; }
//-----------------------------------------------------------------------------
// fatfs_fat_init:
//-----------------------------------------------------------------------------
void fatfs_fat_init(struct fatfs *fs)
{
int i;
// FAT buffer chain head
fs->fat_buffer_head = NULL;
for (i=0;i<FAT_BUFFERS;i++)
{
// Initialise buffers to invalid
fs->fat_buffers[i].address = FAT32_INVALID_CLUSTER;
fs->fat_buffers[i].dirty = 0;
memset(fs->fat_buffers[i].sector, 0x00, sizeof(fs->fat_buffers[i].sector));
fs->fat_buffers[i].ptr = NULL;
// Add to head of queue
fs->fat_buffers[i].next = fs->fat_buffer_head;
fs->fat_buffer_head = &fs->fat_buffers[i];
}
}
//-----------------------------------------------------------------------------
// fatfs_fat_writeback: Writeback 'dirty' FAT sectors to disk
//-----------------------------------------------------------------------------
static int fatfs_fat_writeback(struct fatfs *fs, struct fat_buffer *pcur)
{
if (pcur)
{
// Writeback sector if changed
if (pcur->dirty)
{
if (fs->disk_io.write_media)
{
uint32 sectors = FAT_BUFFER_SECTORS;
uint32 offset = pcur->address - fs->fat_begin_lba;
// Limit to sectors used for the FAT
if ((offset + FAT_BUFFER_SECTORS) <= fs->fat_sectors)
sectors = FAT_BUFFER_SECTORS;
else
sectors = fs->fat_sectors - offset;
if (!fs->disk_io.write_media(pcur->address, pcur->sector, sectors))
return 0;
}
pcur->dirty = 0;
}
return 1;
}
else
return 0;
}
//-----------------------------------------------------------------------------
// fatfs_fat_read_sector: Read a FAT sector
//-----------------------------------------------------------------------------
static struct fat_buffer *fatfs_fat_read_sector(struct fatfs *fs, uint32 sector)
{
struct fat_buffer *last = NULL;
struct fat_buffer *pcur = fs->fat_buffer_head;
// Itterate through sector buffer list
while (pcur)
{
// Sector within this buffer?
if ((sector >= pcur->address) && (sector < (pcur->address + FAT_BUFFER_SECTORS)))
break;
// End of list?
if (pcur->next == NULL)
{
// Remove buffer from list
if (last)
last->next = NULL;
// We the first and last buffer in the chain?
else
fs->fat_buffer_head = NULL;
}
last = pcur;
pcur = pcur->next;
}
// We found the sector already in FAT buffer chain
if (pcur)
{
pcur->ptr = (uint8 *)(pcur->sector + ((sector - pcur->address) * FAT_SECTOR_SIZE));
return pcur;
}
// Else, we removed the last item from the list
pcur = last;
// Add to start of sector buffer list (now newest sector)
pcur->next = fs->fat_buffer_head;
fs->fat_buffer_head = pcur;
// Writeback sector if changed
if (pcur->dirty)
if (!fatfs_fat_writeback(fs, pcur))
return 0;
// Address is now new sector
pcur->address = sector;
// Read next sector
if (!fs->disk_io.read_media(pcur->address, pcur->sector, FAT_BUFFER_SECTORS))
{
// Read failed, invalidate buffer address
pcur->address = FAT32_INVALID_CLUSTER;
return NULL;
}
pcur->ptr = pcur->sector;
return pcur;
}
//-----------------------------------------------------------------------------
// fatfs_fat_purge: Purge 'dirty' FAT sectors to disk
//-----------------------------------------------------------------------------
int fatfs_fat_purge(struct fatfs *fs)
{
struct fat_buffer *pcur = fs->fat_buffer_head;
// Itterate through sector buffer list
while (pcur)
{
// Writeback sector if changed
if (pcur->dirty)
if (!fatfs_fat_writeback(fs, pcur))
return 0;
pcur = pcur->next;
}
return 1;
}
//-----------------------------------------------------------------------------
// General FAT Table Operations
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// fatfs_find_next_cluster: Return cluster number of next cluster in chain by
// reading FAT table and traversing it. Return 0xffffffff for end of chain.
//-----------------------------------------------------------------------------
uint32 fatfs_find_next_cluster(struct fatfs *fs, uint32 current_cluster)
{
uint32 fat_sector_offset, position;
uint32 nextcluster;
struct fat_buffer *pbuf;
// Why is '..' labelled with cluster 0 when it should be 2 ??
if (current_cluster == 0)
current_cluster = 2;
// Find which sector of FAT table to read
if (fs->fat_type == FAT_TYPE_16)
fat_sector_offset = current_cluster / 256;
else
fat_sector_offset = current_cluster / 128;
// Read FAT sector into buffer
pbuf = fatfs_fat_read_sector(fs, fs->fat_begin_lba+fat_sector_offset);
if (!pbuf)
return (FAT32_LAST_CLUSTER);
if (fs->fat_type == FAT_TYPE_16)
{
// Find 32 bit entry of current sector relating to cluster number
position = (current_cluster - (fat_sector_offset * 256)) * 2;
// Read Next Clusters value from Sector Buffer
nextcluster = FAT16_GET_16BIT_WORD(pbuf, (uint16)position);
// If end of chain found
if (nextcluster >= 0xFFF8 && nextcluster <= 0xFFFF)
return (FAT32_LAST_CLUSTER);
}
else
{
// Find 32 bit entry of current sector relating to cluster number
position = (current_cluster - (fat_sector_offset * 128)) * 4;
// Read Next Clusters value from Sector Buffer
nextcluster = FAT32_GET_32BIT_WORD(pbuf, (uint16)position);
// Mask out MS 4 bits (its 28bit addressing)
nextcluster = nextcluster & 0x0FFFFFFF;
// If end of chain found
if (nextcluster >= 0x0FFFFFF8 && nextcluster <= 0x0FFFFFFF)
return (FAT32_LAST_CLUSTER);
}
// Else return next cluster
return (nextcluster);
}
//-----------------------------------------------------------------------------
// fatfs_set_fs_info_next_free_cluster: Write the next free cluster to the FSINFO table
//-----------------------------------------------------------------------------
void fatfs_set_fs_info_next_free_cluster(struct fatfs *fs, uint32 newValue)
{
if (fs->fat_type == FAT_TYPE_16)
;
else
{
// Load sector to change it
struct fat_buffer *pbuf = fatfs_fat_read_sector(fs, fs->lba_begin+fs->fs_info_sector);
if (!pbuf)
return ;
// Change
FAT32_SET_32BIT_WORD(pbuf, 492, newValue);
fs->next_free_cluster = newValue;
// Write back FSINFO sector to disk
if (fs->disk_io.write_media)
fs->disk_io.write_media(pbuf->address, pbuf->sector, 1);
// Invalidate cache entry
pbuf->address = FAT32_INVALID_CLUSTER;
pbuf->dirty = 0;
}
}
//-----------------------------------------------------------------------------
// fatfs_find_blank_cluster: Find a free cluster entry by reading the FAT
//-----------------------------------------------------------------------------
#if FATFS_INC_WRITE_SUPPORT
int fatfs_find_blank_cluster(struct fatfs *fs, uint32 start_cluster, uint32 *free_cluster)
{
uint32 fat_sector_offset, position;
uint32 nextcluster;
uint32 current_cluster = start_cluster;
struct fat_buffer *pbuf;
do
{
// Find which sector of FAT table to read
if (fs->fat_type == FAT_TYPE_16)
fat_sector_offset = current_cluster / 256;
else
fat_sector_offset = current_cluster / 128;
if ( fat_sector_offset < fs->fat_sectors)
{
// Read FAT sector into buffer
pbuf = fatfs_fat_read_sector(fs, fs->fat_begin_lba+fat_sector_offset);
if (!pbuf)
return 0;
if (fs->fat_type == FAT_TYPE_16)
{
// Find 32 bit entry of current sector relating to cluster number
position = (current_cluster - (fat_sector_offset * 256)) * 2;
// Read Next Clusters value from Sector Buffer
nextcluster = FAT16_GET_16BIT_WORD(pbuf, (uint16)position);
}
else
{
// Find 32 bit entry of current sector relating to cluster number
position = (current_cluster - (fat_sector_offset * 128)) * 4;
// Read Next Clusters value from Sector Buffer
nextcluster = FAT32_GET_32BIT_WORD(pbuf, (uint16)position);
// Mask out MS 4 bits (its 28bit addressing)
nextcluster = nextcluster & 0x0FFFFFFF;
}
if (nextcluster !=0 )
current_cluster++;
}
else
// Otherwise, run out of FAT sectors to check...
return 0;
}
while (nextcluster != 0x0);
// Found blank entry
*free_cluster = current_cluster;
return 1;
}
#endif
//-----------------------------------------------------------------------------
// fatfs_fat_set_cluster: Set a cluster link in the chain. NOTE: Immediate
// write (slow).
//-----------------------------------------------------------------------------
#if FATFS_INC_WRITE_SUPPORT
int fatfs_fat_set_cluster(struct fatfs *fs, uint32 cluster, uint32 next_cluster)
{
struct fat_buffer *pbuf;
uint32 fat_sector_offset, position;
// Find which sector of FAT table to read
if (fs->fat_type == FAT_TYPE_16)
fat_sector_offset = cluster / 256;
else
fat_sector_offset = cluster / 128;
// Read FAT sector into buffer
pbuf = fatfs_fat_read_sector(fs, fs->fat_begin_lba+fat_sector_offset);
if (!pbuf)
return 0;
if (fs->fat_type == FAT_TYPE_16)
{
// Find 16 bit entry of current sector relating to cluster number
position = (cluster - (fat_sector_offset * 256)) * 2;
// Write Next Clusters value to Sector Buffer
FAT16_SET_16BIT_WORD(pbuf, (uint16)position, ((uint16)next_cluster));
}
else
{
// Find 32 bit entry of current sector relating to cluster number
position = (cluster - (fat_sector_offset * 128)) * 4;
// Write Next Clusters value to Sector Buffer
FAT32_SET_32BIT_WORD(pbuf, (uint16)position, next_cluster);
}
return 1;
}
#endif
//-----------------------------------------------------------------------------
// fatfs_free_cluster_chain: Follow a chain marking each element as free
//-----------------------------------------------------------------------------
#if FATFS_INC_WRITE_SUPPORT
int fatfs_free_cluster_chain(struct fatfs *fs, uint32 start_cluster)
{
uint32 last_cluster;
uint32 next_cluster = start_cluster;
// Loop until end of chain
while ( (next_cluster != FAT32_LAST_CLUSTER) && (next_cluster != 0x00000000) )
{
last_cluster = next_cluster;
// Find next link
next_cluster = fatfs_find_next_cluster(fs, next_cluster);
// Clear last link
fatfs_fat_set_cluster(fs, last_cluster, 0x00000000);
}
return 1;
}
#endif
//-----------------------------------------------------------------------------
// fatfs_fat_add_cluster_to_chain: Follow a chain marking and then add a new entry
// to the current tail.
//-----------------------------------------------------------------------------
#if FATFS_INC_WRITE_SUPPORT
int fatfs_fat_add_cluster_to_chain(struct fatfs *fs, uint32 start_cluster, uint32 newEntry)
{
uint32 last_cluster = FAT32_LAST_CLUSTER;
uint32 next_cluster = start_cluster;
if (start_cluster == FAT32_LAST_CLUSTER)
return 0;
// Loop until end of chain
while ( next_cluster != FAT32_LAST_CLUSTER )
{
last_cluster = next_cluster;
// Find next link
next_cluster = fatfs_find_next_cluster(fs, next_cluster);
if (!next_cluster)
return 0;
}
// Add link in for new cluster
fatfs_fat_set_cluster(fs, last_cluster, newEntry);
// Mark new cluster as end of chain
fatfs_fat_set_cluster(fs, newEntry, FAT32_LAST_CLUSTER);
return 1;
}
#endif
//-----------------------------------------------------------------------------
// fatfs_count_free_clusters:
//-----------------------------------------------------------------------------
uint32 fatfs_count_free_clusters(struct fatfs *fs)
{
uint32 i,j;
uint32 count = 0;
struct fat_buffer *pbuf;
for (i = 0; i < fs->fat_sectors; i++)
{
// Read FAT sector into buffer
pbuf = fatfs_fat_read_sector(fs, fs->fat_begin_lba + i);
if (!pbuf)
break;
for (j = 0; j < FAT_SECTOR_SIZE; )
{
if (fs->fat_type == FAT_TYPE_16)
{
if (FAT16_GET_16BIT_WORD(pbuf, (uint16)j) == 0)
count++;
j += 2;
}
else
{
if (FAT32_GET_32BIT_WORD(pbuf, (uint16)j) == 0)
count++;
j += 4;
}
}
}
return count;
}

@ -0,0 +1,20 @@
#ifndef __FAT_TABLE_H__
#define __FAT_TABLE_H__
#include "fat_opts.h"
#include "fat_misc.h"
//-----------------------------------------------------------------------------
// Prototypes
//-----------------------------------------------------------------------------
void fatfs_fat_init(struct fatfs *fs);
int fatfs_fat_purge(struct fatfs *fs);
uint32 fatfs_find_next_cluster(struct fatfs *fs, uint32 current_cluster);
void fatfs_set_fs_info_next_free_cluster(struct fatfs *fs, uint32 newValue);
int fatfs_find_blank_cluster(struct fatfs *fs, uint32 start_cluster, uint32 *free_cluster);
int fatfs_fat_set_cluster(struct fatfs *fs, uint32 cluster, uint32 next_cluster);
int fatfs_fat_add_cluster_to_chain(struct fatfs *fs, uint32 start_cluster, uint32 newEntry);
int fatfs_free_cluster_chain(struct fatfs *fs, uint32 start_cluster);
uint32 fatfs_count_free_clusters(struct fatfs *fs);
#endif

@ -0,0 +1,69 @@
#ifndef __FAT_TYPES_H__
#define __FAT_TYPES_H__
// Detect 64-bit compilation on GCC
#if defined(__GNUC__) && defined(__SIZEOF_LONG__)
#if __SIZEOF_LONG__ == 8
#define FATFS_DEF_UINT32_AS_INT
#endif
#endif
//-------------------------------------------------------------
// System specific types
//-------------------------------------------------------------
#ifndef FATFS_NO_DEF_TYPES
typedef unsigned char uint8;
typedef unsigned short uint16;
// If compiling on a 64-bit machine, use int as 32-bits
#ifdef FATFS_DEF_UINT32_AS_INT
typedef unsigned int uint32;
// Else for 32-bit machines & embedded systems, use long...
#else
typedef unsigned long uint32;
#endif
#endif
#ifndef NULL
#define NULL 0
#endif
//-------------------------------------------------------------
// Endian Macros
//-------------------------------------------------------------
// FAT is little endian so big endian systems need to swap words
// Little Endian - No swap required
#if FATFS_IS_LITTLE_ENDIAN == 1
#define FAT_HTONS(n) (n)
#define FAT_HTONL(n) (n)
// Big Endian - Swap required
#else
#define FAT_HTONS(n) ((((uint16)((n) & 0xff)) << 8) | (((n) & 0xff00) >> 8))
#define FAT_HTONL(n) (((((uint32)(n) & 0xFF)) << 24) | \
((((uint32)(n) & 0xFF00)) << 8) | \
((((uint32)(n) & 0xFF0000)) >> 8) | \
((((uint32)(n) & 0xFF000000)) >> 24))
#endif
//-------------------------------------------------------------
// Structure Packing Compile Options
//-------------------------------------------------------------
#ifdef __GNUC__
#define STRUCT_PACK
#define STRUCT_PACK_BEGIN
#define STRUCT_PACK_END
#define STRUCT_PACKED __attribute__ ((packed))
#else
// Other compilers may require other methods of packing structures
#define STRUCT_PACK
#define STRUCT_PACK_BEGIN
#define STRUCT_PACK_END
#define STRUCT_PACKED
#endif
#endif

@ -0,0 +1,373 @@
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// FAT16/32 File IO Library
// V2.6
// Ultra-Embedded.com
// Copyright 2003 - 2012
//
// Email: admin@ultra-embedded.com
//
// License: GPL
// If you would like a version with a more permissive license for use in
// closed source commercial applications please contact me for details.
//-----------------------------------------------------------------------------
//
// This file is part of FAT File IO Library.
//
// FAT File IO Library 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.
//
// FAT File IO Library 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 FAT File IO Library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
#include <string.h>
#include "fat_defs.h"
#include "fat_access.h"
#include "fat_table.h"
#include "fat_write.h"
#include "fat_string.h"
#include "fat_misc.h"
#if FATFS_INC_WRITE_SUPPORT
//-----------------------------------------------------------------------------
// fatfs_add_free_space: Allocate another cluster of free space to the end
// of a files cluster chain.
//-----------------------------------------------------------------------------
int fatfs_add_free_space(struct fatfs *fs, uint32 *startCluster, uint32 clusters)
{
uint32 i;
uint32 nextcluster;
uint32 start = *startCluster;
// Set the next free cluster hint to unknown
if (fs->next_free_cluster != FAT32_LAST_CLUSTER)
fatfs_set_fs_info_next_free_cluster(fs, FAT32_LAST_CLUSTER);
for (i=0;i<clusters;i++)
{
// Start looking for free clusters from the beginning
if (fatfs_find_blank_cluster(fs, fs->rootdir_first_cluster, &nextcluster))
{
// Point last to this
fatfs_fat_set_cluster(fs, start, nextcluster);
// Point this to end of file
fatfs_fat_set_cluster(fs, nextcluster, FAT32_LAST_CLUSTER);
// Adjust argument reference
start = nextcluster;
if (i == 0)
*startCluster = nextcluster;
}
else
return 0;
}
return 1;
}
//-----------------------------------------------------------------------------
// fatfs_allocate_free_space: Add an ammount of free space to a file either from
// 'startCluster' if newFile = false, or allocating a new start to the chain if
// newFile = true.
//-----------------------------------------------------------------------------
int fatfs_allocate_free_space(struct fatfs *fs, int newFile, uint32 *startCluster, uint32 size)
{
uint32 clusterSize;
uint32 clusterCount;
uint32 nextcluster;
if (size==0)
return 0;
// Set the next free cluster hint to unknown
if (fs->next_free_cluster != FAT32_LAST_CLUSTER)
fatfs_set_fs_info_next_free_cluster(fs, FAT32_LAST_CLUSTER);
// Work out size and clusters
clusterSize = fs->sectors_per_cluster * FAT_SECTOR_SIZE;
clusterCount = (size / clusterSize);
// If any left over
if (size-(clusterSize*clusterCount))
clusterCount++;
// Allocated first link in the chain if a new file
if (newFile)
{
if (!fatfs_find_blank_cluster(fs, fs->rootdir_first_cluster, &nextcluster))
return 0;
// If this is all that is needed then all done
if (clusterCount==1)
{
fatfs_fat_set_cluster(fs, nextcluster, FAT32_LAST_CLUSTER);
*startCluster = nextcluster;
return 1;
}
}
// Allocate from end of current chain (startCluster is end of chain)
else
nextcluster = *startCluster;
if (!fatfs_add_free_space(fs, &nextcluster, clusterCount))
return 0;
return 1;
}
//-----------------------------------------------------------------------------
// fatfs_find_free_dir_offset: Find a free space in the directory for a new entry
// which takes up 'entryCount' blocks (or allocate some more)
//-----------------------------------------------------------------------------
static int fatfs_find_free_dir_offset(struct fatfs *fs, uint32 dirCluster, int entryCount, uint32 *pSector, uint8 *pOffset)
{
struct fat_dir_entry *directoryEntry;
uint8 item=0;
uint16 recordoffset = 0;
uint8 i=0;
int x=0;
int possible_spaces = 0;
int start_recorded = 0;
// No entries required?
if (entryCount == 0)
return 0;
// Main cluster following loop
while (1)
{
// Read sector
if (fatfs_sector_reader(fs, dirCluster, x++, 0))
{
// Analyse Sector
for (item = 0; item < FAT_DIR_ENTRIES_PER_SECTOR; item++)
{
// Create the multiplier for sector access
recordoffset = FAT_DIR_ENTRY_SIZE * item;
// Overlay directory entry over buffer
directoryEntry = (struct fat_dir_entry*)(fs->currentsector.sector+recordoffset);
// LFN Entry
if (fatfs_entry_lfn_text(directoryEntry))
{
// First entry?
if (possible_spaces == 0)
{
// Store start
*pSector = x-1;
*pOffset = item;
start_recorded = 1;
}
// Increment the count in-case the file turns
// out to be deleted...
possible_spaces++;
}
// SFN Entry
else
{
// Has file been deleted?
if (fs->currentsector.sector[recordoffset] == FILE_HEADER_DELETED)
{
// First entry?
if (possible_spaces == 0)
{
// Store start
*pSector = x-1;
*pOffset = item;
start_recorded = 1;
}
possible_spaces++;
// We have found enough space?
if (possible_spaces >= entryCount)
return 1;
// Else continue counting until we find a valid entry!
}
// Is the file entry empty?
else if (fs->currentsector.sector[recordoffset] == FILE_HEADER_BLANK)
{
// First entry?
if (possible_spaces == 0)
{
// Store start
*pSector = x-1;
*pOffset = item;
start_recorded = 1;
}
// Increment the blank entries count
possible_spaces++;
// We have found enough space?
if (possible_spaces >= entryCount)
return 1;
}
// File entry is valid
else
{
// Reset all flags
possible_spaces = 0;
start_recorded = 0;
}
}
} // End of for
} // End of if
// Run out of free space in the directory, allocate some more
else
{
uint32 newCluster;
// Get a new cluster for directory
if (!fatfs_find_blank_cluster(fs, fs->rootdir_first_cluster, &newCluster))
return 0;
// Add cluster to end of directory tree
if (!fatfs_fat_add_cluster_to_chain(fs, dirCluster, newCluster))
return 0;
// Erase new directory cluster
memset(fs->currentsector.sector, 0x00, FAT_SECTOR_SIZE);
for (i=0;i<fs->sectors_per_cluster;i++)
{
if (!fatfs_write_sector(fs, newCluster, i, 0))
return 0;
}
// If non of the name fitted on previous sectors
if (!start_recorded)
{
// Store start
*pSector = (x-1);
*pOffset = 0;
start_recorded = 1;
}
return 1;
}
} // End of while loop
return 0;
}
//-----------------------------------------------------------------------------
// fatfs_add_file_entry: Add a directory entry to a location found by FindFreeOffset
//-----------------------------------------------------------------------------
int fatfs_add_file_entry(struct fatfs *fs, uint32 dirCluster, char *filename, char *shortfilename, uint32 startCluster, uint32 size, int dir)
{
uint8 item=0;
uint16 recordoffset = 0;
uint8 i=0;
uint32 x=0;
int entryCount;
struct fat_dir_entry shortEntry;
int dirtySector = 0;
uint32 dirSector = 0;
uint8 dirOffset = 0;
int foundEnd = 0;
uint8 checksum;
uint8 *pSname;
// No write access?
if (!fs->disk_io.write_media)
return 0;
#if FATFS_INC_LFN_SUPPORT
// How many LFN entries are required?
// NOTE: We always request one LFN even if it would fit in a SFN!
entryCount = fatfs_lfn_entries_required(filename);
if (!entryCount)
return 0;
#else
entryCount = 0;
#endif
// Find space in the directory for this filename (or allocate some more)
// NOTE: We need to find space for at least the LFN + SFN (or just the SFN if LFNs not supported).
if (!fatfs_find_free_dir_offset(fs, dirCluster, entryCount + 1, &dirSector, &dirOffset))
return 0;
// Generate checksum of short filename
pSname = (uint8*)shortfilename;
checksum = 0;
for (i=11; i!=0; i--) checksum = ((checksum & 1) ? 0x80 : 0) + (checksum >> 1) + *pSname++;
// Start from current sector where space was found!
x = dirSector;
// Main cluster following loop
while (1)
{
// Read sector
if (fatfs_sector_reader(fs, dirCluster, x++, 0))
{
// Analyse Sector
for (item = 0; item < FAT_DIR_ENTRIES_PER_SECTOR; item++)
{
// Create the multiplier for sector access
recordoffset = FAT_DIR_ENTRY_SIZE * item;
// If the start position for the entry has been found
if (foundEnd==0)
if ( (dirSector==(x-1)) && (dirOffset==item) )
foundEnd = 1;
// Start adding filename
if (foundEnd)
{
if (entryCount==0)
{
// Short filename
fatfs_sfn_create_entry(shortfilename, size, startCluster, &shortEntry, dir);
#if FATFS_INC_TIME_DATE_SUPPORT
// Update create, access & modify time & date
fatfs_update_timestamps(&shortEntry, 1, 1, 1);
#endif
memcpy(&fs->currentsector.sector[recordoffset], &shortEntry, sizeof(shortEntry));
// Writeback
return fs->disk_io.write_media(fs->currentsector.address, fs->currentsector.sector, 1);
}
#if FATFS_INC_LFN_SUPPORT
else
{
entryCount--;
// Copy entry to directory buffer
fatfs_filename_to_lfn(filename, &fs->currentsector.sector[recordoffset], entryCount, checksum);
dirtySector = 1;
}
#endif
}
} // End of if
// Write back to disk before loading another sector
if (dirtySector)
{
if (!fs->disk_io.write_media(fs->currentsector.address, fs->currentsector.sector, 1))
return 0;
dirtySector = 0;
}
}
else
return 0;
} // End of while loop
return 0;
}
#endif

@ -0,0 +1,14 @@
#ifndef __FAT_WRITE_H__
#define __FAT_WRITE_H__
#include "fat_defs.h"
#include "fat_opts.h"
//-----------------------------------------------------------------------------
// Prototypes
//-----------------------------------------------------------------------------
int fatfs_add_file_entry(struct fatfs *fs, uint32 dirCluster, char *filename, char *shortfilename, uint32 startCluster, uint32 size, int dir);
int fatfs_add_free_space(struct fatfs *fs, uint32 *startCluster, uint32 clusters);
int fatfs_allocate_free_space(struct fatfs *fs, int newFile, uint32 *startCluster, uint32 size);
#endif

@ -0,0 +1,682 @@
/******************************************************************************
* partresize.c ---- ventoy part resize util
*
* Copyright (c) 2021, longpanda <admin@ventoy.net>
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include <stdio.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <dirent.h>
#include <fat_filelib.h>
#include "vtoycli.h"
static int g_disk_fd = 0;
static UINT64 g_disk_offset = 0;
static GUID g_ZeroGuid = {0};
static GUID g_WindowsDataPartGuid = { 0xebd0a0a2, 0xb9e5, 0x4433, { 0x87, 0xc0, 0x68, 0xb6, 0xb7, 0x26, 0x99, 0xc7 } };
static int vtoy_disk_read(uint32 sector, uint8 *buffer, uint32 sector_count)
{
UINT64 offset = sector * 512ULL;
lseek(g_disk_fd, g_disk_offset + offset, SEEK_SET);
read(g_disk_fd, buffer, sector_count * 512);
return 1;
}
static int vtoy_disk_write(uint32 sector, uint8 *buffer, uint32 sector_count)
{
UINT64 offset = sector * 512ULL;
lseek(g_disk_fd, g_disk_offset + offset, SEEK_SET);
write(g_disk_fd, buffer, sector_count * 512);
return 1;
}
static int gpt_check(const char *disk)
{
int fd = -1;
int rc = 1;
VTOY_GPT_INFO *pGPT = NULL;
fd = open(disk, O_RDONLY);
if (fd < 0)
{
printf("Failed to open %s\n", disk);
goto out;
}
pGPT = malloc(sizeof(VTOY_GPT_INFO));
if (NULL == pGPT)
{
goto out;
}
memset(pGPT, 0, sizeof(VTOY_GPT_INFO));
read(fd, pGPT, sizeof(VTOY_GPT_INFO));
if (pGPT->MBR.PartTbl[0].FsFlag == 0xEE && memcmp(pGPT->Head.Signature, "EFI PART", 8) == 0)
{
rc = 0;
}
out:
check_close(fd);
check_free(pGPT);
return rc;
}
static int part_check(const char *disk)
{
int i;
int fd = -1;
int rc = 0;
int Index = 0;
int Count = 0;
int PartStyle = 0;
UINT64 Part1Start;
UINT64 Part1End;
UINT64 NextPartStart;
UINT64 DiskSizeInBytes;
VTOY_GPT_INFO *pGPT = NULL;
DiskSizeInBytes = get_disk_size_in_byte(disk);
if (DiskSizeInBytes == 0)
{
printf("Failed to get disk size of %s\n", disk);
goto out;
}
fd = open(disk, O_RDONLY);
if (fd < 0)
{
printf("Failed to open %s\n", disk);
goto out;
}
pGPT = malloc(sizeof(VTOY_GPT_INFO));
if (NULL == pGPT)
{
goto out;
}
memset(pGPT, 0, sizeof(VTOY_GPT_INFO));
read(fd, pGPT, sizeof(VTOY_GPT_INFO));
if (pGPT->MBR.PartTbl[0].FsFlag == 0xEE && memcmp(pGPT->Head.Signature, "EFI PART", 8) == 0)
{
PartStyle = 1;
}
else
{
PartStyle = 0;
}
if (PartStyle == 0)
{
PART_TABLE *PartTbl = pGPT->MBR.PartTbl;
for (Count = 0, i = 0; i < 4; i++)
{
if (PartTbl[i].SectorCount > 0)
{
printf("MBR Part%d SectorStart:%u SectorCount:%u\n", i + 1, PartTbl[i].StartSectorId, PartTbl[i].SectorCount);
Count++;
}
}
//We must have a free partition table for VTOYEFI partition
if (Count >= 4)
{
printf("###[FAIL] 4 MBR partition tables are all used.\n");
goto out;
}
if (PartTbl[0].SectorCount > 0)
{
Part1Start = PartTbl[0].StartSectorId;
Part1End = PartTbl[0].SectorCount + Part1Start;
}
else
{
printf("###[FAIL] MBR Partition 1 is invalid\n");
goto out;
}
Index = -1;
NextPartStart = DiskSizeInBytes / 512ULL;
for (i = 1; i < 4; i++)
{
if (PartTbl[i].SectorCount > 0 && NextPartStart > PartTbl[i].StartSectorId)
{
Index = i;
NextPartStart = PartTbl[i].StartSectorId;
}
}
NextPartStart *= 512ULL;
printf("DiskSize:%llu NextPartStart:%llu(LBA:%llu) Index:%d\n",
DiskSizeInBytes, NextPartStart, NextPartStart / 512ULL, Index);
}
else
{
VTOY_GPT_PART_TBL *PartTbl = pGPT->PartTbl;
for (Count = 0, i = 0; i < 128; i++)
{
if (memcmp(&(PartTbl[i].PartGuid), &g_ZeroGuid, sizeof(GUID)))
{
printf("GPT Part%d StartLBA:%llu LastLBA:%llu\n", i + 1, PartTbl[i].StartLBA, PartTbl[i].LastLBA);
Count++;
}
}
if (Count >= 128)
{
printf("###[FAIL] 128 GPT partition tables are all used.\n");
goto out;
}
if (memcmp(&(PartTbl[0].PartGuid), &g_ZeroGuid, sizeof(GUID)))
{
Part1Start = PartTbl[0].StartLBA;
Part1End = PartTbl[0].LastLBA + 1;
}
else
{
printf("###[FAIL] GPT Partition 1 is invalid\n");
goto out;
}
Index = -1;
NextPartStart = (pGPT->Head.PartAreaEndLBA + 1);
for (i = 1; i < 128; i++)
{
if (memcmp(&(PartTbl[i].PartGuid), &g_ZeroGuid, sizeof(GUID)) && NextPartStart > PartTbl[i].StartLBA)
{
Index = i;
NextPartStart = PartTbl[i].StartLBA;
}
}
NextPartStart *= 512ULL;
printf("DiskSize:%llu NextPartStart:%llu(LBA:%llu) Index:%d\n",
DiskSizeInBytes, NextPartStart, NextPartStart / 512ULL, Index);
}
printf("Valid partition table (%s): Valid partition count:%d\n", (PartStyle == 0) ? "MBR" : "GPT", Count);
//Partition 1 MUST start at 1MB
Part1Start *= 512ULL;
Part1End *= 512ULL;
printf("Partition 1 start at: %llu %lluKB, end:%llu, NextPartStart:%llu\n",
Part1Start, Part1Start / 1024, Part1End, NextPartStart);
if (Part1Start != SIZE_1MB)
{
printf("###[FAIL] Partition 1 is not start at 1MB\n");
goto out;
}
//If we have free space after partition 1
if (NextPartStart - Part1End >= VENTOY_EFI_PART_SIZE)
{
printf("Free space after partition 1 (%llu) is enough for VTOYEFI part\n", NextPartStart - Part1End);
rc = 1;
}
else if (NextPartStart == Part1End)
{
printf("There is no free space after partition 1\n");
rc = 2;
}
else
{
printf("The free space after partition 1 is not enough\n");
rc = 2;
}
out:
check_close(fd);
check_free(pGPT);
return rc;
}
static int secureboot_proc(char *disk, UINT64 part2start)
{
int rc = 0;
int size;
int fd = -1;
char *filebuf = NULL;
void *file = NULL;
fd = open(disk, O_RDWR);
if (fd < 0)
{
printf("Failed to open %s\n", disk);
return 1;
}
g_disk_fd = fd;
g_disk_offset = part2start * 512ULL;
fl_init();
if (0 == fl_attach_media(vtoy_disk_read, vtoy_disk_write))
{
file = fl_fopen("/EFI/BOOT/grubx64_real.efi", "rb");
printf("Open ventoy efi file %p\n", file);
if (file)
{
fl_fseek(file, 0, SEEK_END);
size = (int)fl_ftell(file);
fl_fseek(file, 0, SEEK_SET);
printf("ventoy x64 efi file size %d ...\n", size);
filebuf = (char *)malloc(size);
if (filebuf)
{
fl_fread(filebuf, 1, size, file);
}
fl_fclose(file);
fl_remove("/EFI/BOOT/BOOTX64.EFI");
fl_remove("/EFI/BOOT/grubx64.efi");
fl_remove("/EFI/BOOT/grubx64_real.efi");
fl_remove("/EFI/BOOT/MokManager.efi");
fl_remove("/ENROLL_THIS_KEY_IN_MOKMANAGER.cer");
file = fl_fopen("/EFI/BOOT/BOOTX64.EFI", "wb");
printf("Open bootx64 efi file %p\n", file);
if (file)
{
if (filebuf)
{
fl_fwrite(filebuf, 1, size, file);
}
fl_fflush(file);
fl_fclose(file);
}
if (filebuf)
{
free(filebuf);
}
}
file = fl_fopen("/EFI/BOOT/grubia32_real.efi", "rb");
printf("Open ventoy ia32 efi file %p\n", file);
if (file)
{
fl_fseek(file, 0, SEEK_END);
size = (int)fl_ftell(file);
fl_fseek(file, 0, SEEK_SET);
printf("ventoy efi file size %d ...\n", size);
filebuf = (char *)malloc(size);
if (filebuf)
{
fl_fread(filebuf, 1, size, file);
}
fl_fclose(file);
fl_remove("/EFI/BOOT/BOOTIA32.EFI");
fl_remove("/EFI/BOOT/grubia32.efi");
fl_remove("/EFI/BOOT/grubia32_real.efi");
fl_remove("/EFI/BOOT/mmia32.efi");
file = fl_fopen("/EFI/BOOT/BOOTIA32.EFI", "wb");
printf("Open bootia32 efi file %p\n", file);
if (file)
{
if (filebuf)
{
fl_fwrite(filebuf, 1, size, file);
}
fl_fflush(file);
fl_fclose(file);
}
if (filebuf)
{
free(filebuf);
}
}
}
else
{
rc = 1;
}
fl_shutdown();
fsync(fd);
return rc;
}
static int VentoyFillMBRLocation(UINT64 DiskSizeInBytes, UINT32 StartSectorId, UINT32 SectorCount, PART_TABLE *Table)
{
UINT8 Head;
UINT8 Sector;
UINT8 nSector = 63;
UINT8 nHead = 8;
UINT32 Cylinder;
UINT32 EndSectorId;
while (nHead != 0 && (DiskSizeInBytes / 512 / nSector / nHead) > 1024)
{
nHead = (UINT8)nHead * 2;
}
if (nHead == 0)
{
nHead = 255;
}
Cylinder = StartSectorId / nSector / nHead;
Head = StartSectorId / nSector % nHead;
Sector = StartSectorId % nSector + 1;
Table->StartHead = Head;
Table->StartSector = Sector;
Table->StartCylinder = Cylinder;
EndSectorId = StartSectorId + SectorCount - 1;
Cylinder = EndSectorId / nSector / nHead;
Head = EndSectorId / nSector % nHead;
Sector = EndSectorId % nSector + 1;
Table->EndHead = Head;
Table->EndSector = Sector;
Table->EndCylinder = Cylinder;
Table->StartSectorId = StartSectorId;
Table->SectorCount = SectorCount;
return 0;
}
static int WriteDataToPhyDisk(int fd, UINT64 offset, void *buffer, int len)
{
ssize_t wrlen;
off_t newseek;
newseek = lseek(fd, offset, SEEK_SET);
if (newseek != offset)
{
printf("Failed to lseek %llu %lld %d\n", offset, (long long)newseek, errno);
return 0;
}
wrlen = write(fd, buffer, len);
if ((int)wrlen != len)
{
printf("Failed to write %d %d %d\n", len, (int)wrlen, errno);
return 0;
}
return 1;
}
static int VentoyFillBackupGptHead(VTOY_GPT_INFO *pInfo, VTOY_GPT_HDR *pHead)
{
UINT64 LBA;
UINT64 BackupLBA;
memcpy(pHead, &pInfo->Head, sizeof(VTOY_GPT_HDR));
LBA = pHead->EfiStartLBA;
BackupLBA = pHead->EfiBackupLBA;
pHead->EfiStartLBA = BackupLBA;
pHead->EfiBackupLBA = LBA;
pHead->PartTblStartLBA = BackupLBA + 1 - 33;
pHead->Crc = 0;
pHead->Crc = VtoyCrc32(pHead, pHead->Length);
return 0;
}
static int update_part_table(char *disk, UINT64 part2start)
{
int i;
int j;
int fd = -1;
int rc = 1;
int PartStyle = 0;
ssize_t len = 0;
UINT64 DiskSizeInBytes;
VTOY_GPT_INFO *pGPT = NULL;
VTOY_GPT_HDR *pBack = NULL;
DiskSizeInBytes = get_disk_size_in_byte(disk);
if (DiskSizeInBytes == 0)
{
printf("Failed to get disk size of %s\n", disk);
goto out;
}
fd = open(disk, O_RDWR);
if (fd < 0)
{
printf("Failed to open %s\n", disk);
goto out;
}
pGPT = malloc(sizeof(VTOY_GPT_INFO) + sizeof(VTOY_GPT_HDR));
if (NULL == pGPT)
{
goto out;
}
memset(pGPT, 0, sizeof(VTOY_GPT_INFO) + sizeof(VTOY_GPT_HDR));
pBack = (VTOY_GPT_HDR *)(pGPT + 1);
len = read(fd, pGPT, sizeof(VTOY_GPT_INFO));
if (len != (ssize_t)sizeof(VTOY_GPT_INFO))
{
printf("Failed to read partition table %d err:%d\n", (int)len, errno);
goto out;
}
if (pGPT->MBR.PartTbl[0].FsFlag == 0xEE && memcmp(pGPT->Head.Signature, "EFI PART", 8) == 0)
{
PartStyle = 1;
}
else
{
PartStyle = 0;
}
if (PartStyle == 0)
{
PART_TABLE *PartTbl = pGPT->MBR.PartTbl;
for (i = 1; i < 4; i++)
{
if (PartTbl[i].SectorCount == 0)
{
break;
}
}
if (i >= 4)
{
printf("###[FAIL] Can not find a free MBR partition table.\n");
goto out;
}
for (j = i - 1; j > 0; j--)
{
printf("Move MBR partition table %d --> %d\n", j + 1, j + 2);
memcpy(PartTbl + (j + 1), PartTbl + j, sizeof(PART_TABLE));
}
memset(PartTbl + 1, 0, sizeof(PART_TABLE));
VentoyFillMBRLocation(DiskSizeInBytes, (UINT32)part2start, VENTOY_EFI_PART_SIZE / 512, PartTbl + 1);
PartTbl[1].Active = 0x00;
PartTbl[1].FsFlag = 0xEF; // EFI System Partition
PartTbl[0].Active = 0x80; // bootable
PartTbl[0].SectorCount = (UINT32)part2start - 2048;
if (!WriteDataToPhyDisk(fd, 0, &(pGPT->MBR), 512))
{
printf("MBR write MBR failed\n");
goto out;
}
fsync(fd);
printf("MBR update partition table success.\n");
rc = 0;
}
else
{
VTOY_GPT_PART_TBL *PartTbl = pGPT->PartTbl;
for (i = 1; i < 128; i++)
{
if (memcmp(&(PartTbl[i].PartGuid), &g_ZeroGuid, sizeof(GUID)) == 0)
{
break;
}
}
if (i >= 128)
{
printf("###[FAIL] Can not find a free GPT partition table.\n");
goto out;
}
for (j = i - 1; j > 0; j--)
{
printf("Move GPT partition table %d --> %d\n", j + 1, j + 2);
memcpy(PartTbl + (j + 1), PartTbl + j, sizeof(VTOY_GPT_PART_TBL));
}
// to fix windows issue
memset(PartTbl + 1, 0, sizeof(VTOY_GPT_PART_TBL));
memcpy(&(PartTbl[1].PartType), &g_WindowsDataPartGuid, sizeof(GUID));
ventoy_gen_preudo_uuid(&(PartTbl[1].PartGuid));
PartTbl[0].LastLBA = part2start - 1;
PartTbl[1].StartLBA = PartTbl[0].LastLBA + 1;
PartTbl[1].LastLBA = PartTbl[1].StartLBA + VENTOY_EFI_PART_SIZE / 512 - 1;
PartTbl[1].Attr = 0xC000000000000001ULL;
PartTbl[1].Name[0] = 'V';
PartTbl[1].Name[1] = 'T';
PartTbl[1].Name[2] = 'O';
PartTbl[1].Name[3] = 'Y';
PartTbl[1].Name[4] = 'E';
PartTbl[1].Name[5] = 'F';
PartTbl[1].Name[6] = 'I';
PartTbl[1].Name[7] = 0;
//Update CRC
pGPT->Head.PartTblCrc = VtoyCrc32(pGPT->PartTbl, sizeof(pGPT->PartTbl));
pGPT->Head.Crc = 0;
pGPT->Head.Crc = VtoyCrc32(&(pGPT->Head), pGPT->Head.Length);
printf("pGPT->Head.EfiStartLBA=%llu\n", pGPT->Head.EfiStartLBA);
printf("pGPT->Head.EfiBackupLBA=%llu\n", pGPT->Head.EfiBackupLBA);
VentoyFillBackupGptHead(pGPT, pBack);
if (!WriteDataToPhyDisk(fd, pGPT->Head.EfiBackupLBA * 512, pBack, 512))
{
printf("GPT write backup head failed\n");
goto out;
}
if (!WriteDataToPhyDisk(fd, (pGPT->Head.EfiBackupLBA - 32) * 512, pGPT->PartTbl, 512 * 32))
{
printf("GPT write backup partition table failed\n");
goto out;
}
if (!WriteDataToPhyDisk(fd, 0, pGPT, 512 * 34))
{
printf("GPT write MBR & Main partition table failed\n");
goto out;
}
fsync(fd);
printf("GPT update partition table success.\n");
rc = 0;
}
out:
check_close(fd);
check_free(pGPT);
return rc;
}
int partresize_main(int argc, char **argv)
{
UINT64 sector;
if (argc != 3 && argc != 4)
{
printf("usage: partresize -c/-f /dev/sdb\n");
return 1;
}
if (strcmp(argv[1], "-c") == 0)
{
return part_check(argv[2]);
}
else if (strcmp(argv[1], "-s") == 0)
{
sector = strtoull(argv[3], NULL, 10);
return secureboot_proc(argv[2], sector);
}
else if (strcmp(argv[1], "-p") == 0)
{
sector = strtoull(argv[3], NULL, 10);
return update_part_table(argv[2], sector);
}
else if (strcmp(argv[1], "-t") == 0)
{
return gpt_check(argv[2]);
}
else
{
return 1;
}
}

@ -0,0 +1,120 @@
/******************************************************************************
* vtoycli.c
*
* Copyright (c) 2021, longpanda <admin@ventoy.net>
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include <stdio.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <errno.h>
#include <time.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <dirent.h>
#include "vtoycli.h"
void ventoy_gen_preudo_uuid(void *uuid)
{
int i;
int fd;
fd = open("/dev/urandom", O_RDONLY);
if (fd < 0)
{
srand(time(NULL));
for (i = 0; i < 8; i++)
{
*((uint16_t *)uuid + i) = (uint16_t)(rand() & 0xFFFF);
}
}
else
{
read(fd, uuid, 16);
close(fd);
}
}
UINT64 get_disk_size_in_byte(const char *disk)
{
int fd;
int rc;
const char *pos = disk;
unsigned long long size = 0;
char diskpath[256] = {0};
char sizebuf[64] = {0};
if (strncmp(disk, "/dev/", 5) == 0)
{
pos = disk + 5;
}
// Try 1: get size from sysfs
snprintf(diskpath, sizeof(diskpath) - 1, "/sys/block/%s/size", pos);
if (access(diskpath, F_OK) >= 0)
{
fd = open(diskpath, O_RDONLY);
if (fd >= 0)
{
read(fd, sizebuf, sizeof(sizebuf));
size = strtoull(sizebuf, NULL, 10);
close(fd);
return (size * 512);
}
}
else
{
printf("%s not exist \n", diskpath);
}
printf("disk %s size %llu bytes\n", disk, (unsigned long long)size);
return size;
}
int main(int argc, char **argv)
{
if (argc < 2)
{
return 1;
}
else if (strcmp(argv[1], "fat") == 0)
{
return vtoyfat_main(argc - 1, argv + 1);
}
else if (strcmp(argv[1], "gpt") == 0)
{
return vtoygpt_main(argc - 1, argv + 1);
}
else if (strcmp(argv[1], "partresize") == 0)
{
return partresize_main(argc - 1, argv + 1);
}
else
{
return 1;
}
}

@ -0,0 +1,138 @@
/******************************************************************************
* vtoycli.h
*
* Copyright (c) 2021, longpanda <admin@ventoy.net>
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef __VTOYCLI_H__
#define __VTOYCLI_H__
#define VENTOY_EFI_PART_ATTR 0xC000000000000001ULL
#define SIZE_1MB (1024 * 1024)
#define VENTOY_EFI_PART_SIZE (32 * SIZE_1MB)
#define check_free(p) if (p) free(p)
#define check_close(fd) if (fd >= 0) close(fd)
#define VOID void
#define CHAR char
#define UINT64 unsigned long long
#define UINT32 unsigned int
#define UINT16 unsigned short
#define CHAR16 unsigned short
#define UINT8 unsigned char
UINT32 VtoyCrc32(VOID *Buffer, UINT32 Length);
#define COMPILE_ASSERT(expr) extern char __compile_assert[(expr) ? 1 : -1]
#pragma pack(1)
typedef struct PART_TABLE
{
UINT8 Active;
UINT8 StartHead;
UINT16 StartSector : 6;
UINT16 StartCylinder : 10;
UINT8 FsFlag;
UINT8 EndHead;
UINT16 EndSector : 6;
UINT16 EndCylinder : 10;
UINT32 StartSectorId;
UINT32 SectorCount;
}PART_TABLE;
typedef struct MBR_HEAD
{
UINT8 BootCode[446];
PART_TABLE PartTbl[4];
UINT8 Byte55;
UINT8 ByteAA;
}MBR_HEAD;
typedef struct GUID
{
UINT32 data1;
UINT16 data2;
UINT16 data3;
UINT8 data4[8];
}GUID;
typedef struct VTOY_GPT_HDR
{
CHAR Signature[8]; /* EFI PART */
UINT8 Version[4];
UINT32 Length;
UINT32 Crc;
UINT8 Reserved1[4];
UINT64 EfiStartLBA;
UINT64 EfiBackupLBA;
UINT64 PartAreaStartLBA;
UINT64 PartAreaEndLBA;
GUID DiskGuid;
UINT64 PartTblStartLBA;
UINT32 PartTblTotNum;
UINT32 PartTblEntryLen;
UINT32 PartTblCrc;
UINT8 Reserved2[420];
}VTOY_GPT_HDR;
COMPILE_ASSERT(sizeof(VTOY_GPT_HDR) == 512);
typedef struct VTOY_GPT_PART_TBL
{
GUID PartType;
GUID PartGuid;
UINT64 StartLBA;
UINT64 LastLBA;
UINT64 Attr;
CHAR16 Name[36];
}VTOY_GPT_PART_TBL;
COMPILE_ASSERT(sizeof(VTOY_GPT_PART_TBL) == 128);
typedef struct VTOY_GPT_INFO
{
MBR_HEAD MBR;
VTOY_GPT_HDR Head;
VTOY_GPT_PART_TBL PartTbl[128];
}VTOY_GPT_INFO;
typedef struct VTOY_BK_GPT_INFO
{
VTOY_GPT_PART_TBL PartTbl[128];
VTOY_GPT_HDR Head;
}VTOY_BK_GPT_INFO;
COMPILE_ASSERT(sizeof(VTOY_GPT_INFO) == 512 * 34);
COMPILE_ASSERT(sizeof(VTOY_BK_GPT_INFO) == 512 * 33);
#pragma pack()
UINT32 VtoyCrc32(VOID *Buffer, UINT32 Length);
int vtoygpt_main(int argc, char **argv);
int vtoyfat_main(int argc, char **argv);
int partresize_main(int argc, char **argv);
void ventoy_gen_preudo_uuid(void *uuid);
UINT64 get_disk_size_in_byte(const char *disk);
#endif /* __VTOYCLI_H__ */

@ -0,0 +1,159 @@
/******************************************************************************
* vtoyfat.c ---- Parse fat file system
*
* Copyright (c) 2021, longpanda <admin@ventoy.net>
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <fat_filelib.h>
static int g_disk_fd = 0;
static int vtoy_disk_read(uint32 sector, uint8 *buffer, uint32 sector_count)
{
lseek(g_disk_fd, sector * 512, SEEK_SET);
read(g_disk_fd, buffer, sector_count * 512);
return 1;
}
static int check_secure_boot(void)
{
void *flfile = NULL;
flfile = fl_fopen("/EFI/BOOT/grubx64_real.efi", "rb");
if (flfile)
{
fl_fclose(flfile);
return 0;
}
return 1;
}
static int get_ventoy_version(void)
{
int rc = 1;
int size = 0;
char *buf = NULL;
char *pos = NULL;
char *end = NULL;
void *flfile = NULL;
flfile = fl_fopen("/grub/grub.cfg", "rb");
if (flfile)
{
fl_fseek(flfile, 0, SEEK_END);
size = (int)fl_ftell(flfile);
fl_fseek(flfile, 0, SEEK_SET);
buf = malloc(size + 1);
if (buf)
{
fl_fread(buf, 1, size, flfile);
buf[size] = 0;
pos = strstr(buf, "VENTOY_VERSION=");
if (pos)
{
pos += strlen("VENTOY_VERSION=");
if (*pos == '"')
{
pos++;
}
end = pos;
while (*end != 0 && *end != '"' && *end != '\r' && *end != '\n')
{
end++;
}
*end = 0;
printf("%s\n", pos);
rc = 0;
}
free(buf);
}
fl_fclose(flfile);
}
return rc;
}
int vtoyfat_main(int argc, char **argv)
{
int op = 0;
int rc = 1;
char *disk;
if (argc != 2 && argc != 3)
{
printf("Usage: vtoyfat /dev/sdbs \n");
printf("Usage: vtoyfat -s /dev/sdbs \n");
return 1;
}
if (argv[1][0] == '-' && argv[1][1] == 'T')
{
return 0;
}
disk = argv[1];
if (argv[1][0] == '-' && argv[1][1] == 's')
{
op = 1;
disk = argv[2];
}
g_disk_fd = open(disk, O_RDONLY);
if (g_disk_fd < 0)
{
printf("Failed to open %s\n", disk);
return 1;
}
fl_init();
if (0 == fl_attach_media(vtoy_disk_read, NULL))
{
if (op == 0)
{
rc = get_ventoy_version();
}
else
{
rc = check_secure_boot();
}
}
fl_shutdown();
close(g_disk_fd);
return rc;
}

@ -0,0 +1,220 @@
/******************************************************************************
* vtoygpt.c ---- ventoy gpt util
*
* Copyright (c) 2021, longpanda <admin@ventoy.net>
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include <stdio.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <dirent.h>
#include "vtoycli.h"
void DumpGuid(const char *prefix, GUID *guid)
{
printf("%s: %08x-%04x-%04x-%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x\n",
prefix,
guid->data1, guid->data2, guid->data3,
guid->data4[0], guid->data4[1], guid->data4[2], guid->data4[3],
guid->data4[4], guid->data4[5], guid->data4[6], guid->data4[7]
);
}
void DumpHead(VTOY_GPT_HDR *pHead)
{
UINT32 CrcRead;
UINT32 CrcCalc;
printf("Signature:<%s>\n", pHead->Signature);
printf("Version:<%02x %02x %02x %02x>\n", pHead->Version[0], pHead->Version[1], pHead->Version[2], pHead->Version[3]);
printf("Length:%u\n", pHead->Length);
printf("Crc:0x%08x\n", pHead->Crc);
printf("EfiStartLBA:%lu\n", pHead->EfiStartLBA);
printf("EfiBackupLBA:%lu\n", pHead->EfiBackupLBA);
printf("PartAreaStartLBA:%lu\n", pHead->PartAreaStartLBA);
printf("PartAreaEndLBA:%lu\n", pHead->PartAreaEndLBA);
DumpGuid("DiskGuid", &pHead->DiskGuid);
printf("PartTblStartLBA:%lu\n", pHead->PartTblStartLBA);
printf("PartTblTotNum:%u\n", pHead->PartTblTotNum);
printf("PartTblEntryLen:%u\n", pHead->PartTblEntryLen);
printf("PartTblCrc:0x%08x\n", pHead->PartTblCrc);
CrcRead = pHead->Crc;
pHead->Crc = 0;
CrcCalc = VtoyCrc32(pHead, pHead->Length);
if (CrcCalc != CrcRead)
{
printf("Head CRC Check Failed\n");
}
else
{
printf("Head CRC Check SUCCESS [%x] [%x]\n", CrcCalc, CrcRead);
}
CrcRead = pHead->PartTblCrc;
CrcCalc = VtoyCrc32(pHead + 1, pHead->PartTblEntryLen * pHead->PartTblTotNum);
if (CrcCalc != CrcRead)
{
printf("Part Table CRC Check Failed\n");
}
else
{
printf("Part Table CRC Check SUCCESS [%x] [%x]\n", CrcCalc, CrcRead);
}
}
void DumpPartTable(VTOY_GPT_PART_TBL *Tbl)
{
int i;
DumpGuid("PartType", &Tbl->PartType);
DumpGuid("PartGuid", &Tbl->PartGuid);
printf("StartLBA:%lu\n", Tbl->StartLBA);
printf("LastLBA:%lu\n", Tbl->LastLBA);
printf("Attr:0x%lx\n", Tbl->Attr);
printf("Name:");
for (i = 0; i < 36 && Tbl->Name[i]; i++)
{
printf("%c", (CHAR)(Tbl->Name[i]));
}
printf("\n");
}
void DumpMBR(MBR_HEAD *pMBR)
{
int i;
for (i = 0; i < 4; i++)
{
printf("=========== Partition Table %d ============\n", i + 1);
printf("PartTbl.Active = 0x%x\n", pMBR->PartTbl[i].Active);
printf("PartTbl.FsFlag = 0x%x\n", pMBR->PartTbl[i].FsFlag);
printf("PartTbl.StartSectorId = %u\n", pMBR->PartTbl[i].StartSectorId);
printf("PartTbl.SectorCount = %u\n", pMBR->PartTbl[i].SectorCount);
printf("PartTbl.StartHead = %u\n", pMBR->PartTbl[i].StartHead);
printf("PartTbl.StartSector = %u\n", pMBR->PartTbl[i].StartSector);
printf("PartTbl.StartCylinder = %u\n", pMBR->PartTbl[i].StartCylinder);
printf("PartTbl.EndHead = %u\n", pMBR->PartTbl[i].EndHead);
printf("PartTbl.EndSector = %u\n", pMBR->PartTbl[i].EndSector);
printf("PartTbl.EndCylinder = %u\n", pMBR->PartTbl[i].EndCylinder);
}
}
int DumpGptInfo(VTOY_GPT_INFO *pGptInfo)
{
int i;
DumpMBR(&pGptInfo->MBR);
DumpHead(&pGptInfo->Head);
for (i = 0; i < 128; i++)
{
if (pGptInfo->PartTbl[i].StartLBA == 0)
{
break;
}
printf("=====Part %d=====\n", i);
DumpPartTable(pGptInfo->PartTbl + i);
}
return 0;
}
int vtoygpt_main(int argc, char **argv)
{
int i;
int fd;
UINT64 DiskSize;
CHAR16 *Name = NULL;
VTOY_GPT_INFO *pMainGptInfo = NULL;
VTOY_BK_GPT_INFO *pBackGptInfo = NULL;
if (argc != 3)
{
printf("usage: vtoygpt -f /dev/sdb\n");
return 1;
}
fd = open(argv[2], O_RDWR);
if (fd < 0)
{
printf("Failed to open %s\n", argv[2]);
return 1;
}
pMainGptInfo = malloc(sizeof(VTOY_GPT_INFO));
pBackGptInfo = malloc(sizeof(VTOY_BK_GPT_INFO));
if (NULL == pMainGptInfo || NULL == pBackGptInfo)
{
close(fd);
return 1;
}
read(fd, pMainGptInfo, sizeof(VTOY_GPT_INFO));
if (argv[1][0] == '-' && argv[1][1] == 'd')
{
DumpGptInfo(pMainGptInfo);
}
else
{
DiskSize = lseek(fd, 0, SEEK_END);
lseek(fd, DiskSize - 33 * 512, SEEK_SET);
read(fd, pBackGptInfo, sizeof(VTOY_BK_GPT_INFO));
Name = pMainGptInfo->PartTbl[1].Name;
if (Name[0] == 'V' && Name[1] == 'T' && Name[2] == 'O' && Name[3] == 'Y')
{
pMainGptInfo->PartTbl[1].Attr = VENTOY_EFI_PART_ATTR;
pMainGptInfo->Head.PartTblCrc = VtoyCrc32(pMainGptInfo->PartTbl, sizeof(pMainGptInfo->PartTbl));
pMainGptInfo->Head.Crc = 0;
pMainGptInfo->Head.Crc = VtoyCrc32(&pMainGptInfo->Head, pMainGptInfo->Head.Length);
pBackGptInfo->PartTbl[1].Attr = VENTOY_EFI_PART_ATTR;
pBackGptInfo->Head.PartTblCrc = VtoyCrc32(pBackGptInfo->PartTbl, sizeof(pBackGptInfo->PartTbl));
pBackGptInfo->Head.Crc = 0;
pBackGptInfo->Head.Crc = VtoyCrc32(&pBackGptInfo->Head, pBackGptInfo->Head.Length);
lseek(fd, 512, SEEK_SET);
write(fd, (UINT8 *)pMainGptInfo + 512, sizeof(VTOY_GPT_INFO) - 512);
lseek(fd, DiskSize - 33 * 512, SEEK_SET);
write(fd, pBackGptInfo, sizeof(VTOY_BK_GPT_INFO));
fsync(fd);
}
}
free(pMainGptInfo);
free(pBackGptInfo);
close(fd);
return 0;
}
Loading…
Cancel
Save