mirror of
https://github.com/ventoy/Ventoy.git
synced 2025-12-13 23:36:21 +00:00
Experimental Linux GUI based on web browser
This commit is contained in:
30
LinuxGUI/Ventoy2Disk/Lib/exfat/buidexfat.sh
Normal file
30
LinuxGUI/Ventoy2Disk/Lib/exfat/buidexfat.sh
Normal file
@@ -0,0 +1,30 @@
|
||||
#!/bin/sh
|
||||
|
||||
CUR="$PWD"
|
||||
|
||||
rm -rf src
|
||||
mkdir -p src/libexfat
|
||||
mkdir -p src/mkfs
|
||||
|
||||
rm -rf exfat-1.3.0
|
||||
unzip exfat-1.3.0.zip
|
||||
|
||||
cd exfat-1.3.0
|
||||
autoreconf --install
|
||||
./configure --prefix="$CUR" CFLAGS='-O2 -D_FILE_OFFSET_BITS=64'
|
||||
make
|
||||
|
||||
cp -a libexfat/*.c ../src/libexfat/
|
||||
cp -a libexfat/*.h ../src/libexfat/
|
||||
cp -a mkfs/*.c ../src/mkfs/
|
||||
cp -a mkfs/*.h ../src/mkfs/
|
||||
rm -f ../src/libexfat/log.c
|
||||
|
||||
cd ..
|
||||
rm -rf exfat-1.3.0
|
||||
|
||||
mv src/mkfs/main.c src/mkfs/mkexfat_main.c
|
||||
sed 's/<exfat.h>/"exfat.h"/g' -i src/mkfs/mkexfat_main.c
|
||||
sed 's/<exfat.h>/"exfat.h"/g' -i src/mkfs/mkexfat.h
|
||||
sed 's/int main/int mkexfat_main/g' -i src/mkfs/mkexfat_main.c
|
||||
|
||||
BIN
LinuxGUI/Ventoy2Disk/Lib/exfat/exfat-1.3.0.zip
Normal file
BIN
LinuxGUI/Ventoy2Disk/Lib/exfat/exfat-1.3.0.zip
Normal file
Binary file not shown.
68
LinuxGUI/Ventoy2Disk/Lib/exfat/src/libexfat/byteorder.h
Normal file
68
LinuxGUI/Ventoy2Disk/Lib/exfat/src/libexfat/byteorder.h
Normal file
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
byteorder.h (12.01.10)
|
||||
Endianness stuff. exFAT uses little-endian byte order.
|
||||
|
||||
Free exFAT implementation.
|
||||
Copyright (C) 2010-2018 Andrew Nayenko
|
||||
|
||||
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.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef BYTEORDER_H_INCLUDED
|
||||
#define BYTEORDER_H_INCLUDED
|
||||
|
||||
#include "platform.h"
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
typedef struct { uint16_t __u16; } le16_t;
|
||||
typedef struct { uint32_t __u32; } le32_t;
|
||||
typedef struct { uint64_t __u64; } le64_t;
|
||||
|
||||
#if EXFAT_BYTE_ORDER == EXFAT_LITTLE_ENDIAN
|
||||
|
||||
static inline uint16_t le16_to_cpu(le16_t v) { return v.__u16; }
|
||||
static inline uint32_t le32_to_cpu(le32_t v) { return v.__u32; }
|
||||
static inline uint64_t le64_to_cpu(le64_t v) { return v.__u64; }
|
||||
|
||||
static inline le16_t cpu_to_le16(uint16_t v) { le16_t t = {v}; return t; }
|
||||
static inline le32_t cpu_to_le32(uint32_t v) { le32_t t = {v}; return t; }
|
||||
static inline le64_t cpu_to_le64(uint64_t v) { le64_t t = {v}; return t; }
|
||||
|
||||
typedef size_t bitmap_t;
|
||||
|
||||
#elif EXFAT_BYTE_ORDER == EXFAT_BIG_ENDIAN
|
||||
|
||||
static inline uint16_t le16_to_cpu(le16_t v)
|
||||
{ return exfat_bswap16(v.__u16); }
|
||||
static inline uint32_t le32_to_cpu(le32_t v)
|
||||
{ return exfat_bswap32(v.__u32); }
|
||||
static inline uint64_t le64_to_cpu(le64_t v)
|
||||
{ return exfat_bswap64(v.__u64); }
|
||||
|
||||
static inline le16_t cpu_to_le16(uint16_t v)
|
||||
{ le16_t t = {exfat_bswap16(v)}; return t; }
|
||||
static inline le32_t cpu_to_le32(uint32_t v)
|
||||
{ le32_t t = {exfat_bswap32(v)}; return t; }
|
||||
static inline le64_t cpu_to_le64(uint64_t v)
|
||||
{ le64_t t = {exfat_bswap64(v)}; return t; }
|
||||
|
||||
typedef unsigned char bitmap_t;
|
||||
|
||||
#else
|
||||
#error Wow! You have a PDP machine?!
|
||||
#endif
|
||||
|
||||
#endif /* ifndef BYTEORDER_H_INCLUDED */
|
||||
491
LinuxGUI/Ventoy2Disk/Lib/exfat/src/libexfat/cluster.c
Normal file
491
LinuxGUI/Ventoy2Disk/Lib/exfat/src/libexfat/cluster.c
Normal file
@@ -0,0 +1,491 @@
|
||||
/*
|
||||
cluster.c (03.09.09)
|
||||
exFAT file system implementation library.
|
||||
|
||||
Free exFAT implementation.
|
||||
Copyright (C) 2010-2018 Andrew Nayenko
|
||||
|
||||
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.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "exfat.h"
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
/*
|
||||
* Sector to absolute offset.
|
||||
*/
|
||||
static off_t s2o(const struct exfat* ef, off_t sector)
|
||||
{
|
||||
return sector << ef->sb->sector_bits;
|
||||
}
|
||||
|
||||
/*
|
||||
* Cluster to sector.
|
||||
*/
|
||||
static off_t c2s(const struct exfat* ef, cluster_t cluster)
|
||||
{
|
||||
if (cluster < EXFAT_FIRST_DATA_CLUSTER)
|
||||
exfat_bug("invalid cluster number %u", cluster);
|
||||
return le32_to_cpu(ef->sb->cluster_sector_start) +
|
||||
((off_t) (cluster - EXFAT_FIRST_DATA_CLUSTER) << ef->sb->spc_bits);
|
||||
}
|
||||
|
||||
/*
|
||||
* Cluster to absolute offset.
|
||||
*/
|
||||
off_t exfat_c2o(const struct exfat* ef, cluster_t cluster)
|
||||
{
|
||||
return s2o(ef, c2s(ef, cluster));
|
||||
}
|
||||
|
||||
/*
|
||||
* Sector to cluster.
|
||||
*/
|
||||
static cluster_t s2c(const struct exfat* ef, off_t sector)
|
||||
{
|
||||
return ((sector - le32_to_cpu(ef->sb->cluster_sector_start)) >>
|
||||
ef->sb->spc_bits) + EXFAT_FIRST_DATA_CLUSTER;
|
||||
}
|
||||
|
||||
/*
|
||||
* Size in bytes to size in clusters (rounded upwards).
|
||||
*/
|
||||
static uint32_t bytes2clusters(const struct exfat* ef, uint64_t bytes)
|
||||
{
|
||||
uint64_t cluster_size = CLUSTER_SIZE(*ef->sb);
|
||||
return DIV_ROUND_UP(bytes, cluster_size);
|
||||
}
|
||||
|
||||
cluster_t exfat_next_cluster(const struct exfat* ef,
|
||||
const struct exfat_node* node, cluster_t cluster)
|
||||
{
|
||||
le32_t next;
|
||||
off_t fat_offset;
|
||||
|
||||
if (cluster < EXFAT_FIRST_DATA_CLUSTER)
|
||||
exfat_bug("bad cluster 0x%x", cluster);
|
||||
|
||||
if (node->is_contiguous)
|
||||
return cluster + 1;
|
||||
fat_offset = s2o(ef, le32_to_cpu(ef->sb->fat_sector_start))
|
||||
+ cluster * sizeof(cluster_t);
|
||||
if (exfat_pread(ef->dev, &next, sizeof(next), fat_offset) < 0)
|
||||
return EXFAT_CLUSTER_BAD; /* the caller should handle this and print
|
||||
appropriate error message */
|
||||
return le32_to_cpu(next);
|
||||
}
|
||||
|
||||
cluster_t exfat_advance_cluster(const struct exfat* ef,
|
||||
struct exfat_node* node, uint32_t count)
|
||||
{
|
||||
uint32_t i;
|
||||
|
||||
if (node->fptr_index > count)
|
||||
{
|
||||
node->fptr_index = 0;
|
||||
node->fptr_cluster = node->start_cluster;
|
||||
}
|
||||
|
||||
for (i = node->fptr_index; i < count; i++)
|
||||
{
|
||||
node->fptr_cluster = exfat_next_cluster(ef, node, node->fptr_cluster);
|
||||
if (CLUSTER_INVALID(*ef->sb, node->fptr_cluster))
|
||||
break; /* the caller should handle this and print appropriate
|
||||
error message */
|
||||
}
|
||||
node->fptr_index = count;
|
||||
return node->fptr_cluster;
|
||||
}
|
||||
|
||||
static cluster_t find_bit_and_set(bitmap_t* bitmap, size_t start, size_t end)
|
||||
{
|
||||
const size_t start_index = start / sizeof(bitmap_t) / 8;
|
||||
const size_t end_index = DIV_ROUND_UP(end, sizeof(bitmap_t) * 8);
|
||||
size_t i;
|
||||
size_t start_bitindex;
|
||||
size_t end_bitindex;
|
||||
size_t c;
|
||||
|
||||
for (i = start_index; i < end_index; i++)
|
||||
{
|
||||
if (bitmap[i] == ~((bitmap_t) 0))
|
||||
continue;
|
||||
start_bitindex = MAX(i * sizeof(bitmap_t) * 8, start);
|
||||
end_bitindex = MIN((i + 1) * sizeof(bitmap_t) * 8, end);
|
||||
for (c = start_bitindex; c < end_bitindex; c++)
|
||||
if (BMAP_GET(bitmap, c) == 0)
|
||||
{
|
||||
BMAP_SET(bitmap, c);
|
||||
return c + EXFAT_FIRST_DATA_CLUSTER;
|
||||
}
|
||||
}
|
||||
return EXFAT_CLUSTER_END;
|
||||
}
|
||||
|
||||
static int flush_nodes(struct exfat* ef, struct exfat_node* node)
|
||||
{
|
||||
struct exfat_node* p;
|
||||
|
||||
for (p = node->child; p != NULL; p = p->next)
|
||||
{
|
||||
int rc = flush_nodes(ef, p);
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
}
|
||||
return exfat_flush_node(ef, node);
|
||||
}
|
||||
|
||||
int exfat_flush_nodes(struct exfat* ef)
|
||||
{
|
||||
return flush_nodes(ef, ef->root);
|
||||
}
|
||||
|
||||
int exfat_flush(struct exfat* ef)
|
||||
{
|
||||
if (ef->cmap.dirty)
|
||||
{
|
||||
if (exfat_pwrite(ef->dev, ef->cmap.chunk,
|
||||
BMAP_SIZE(ef->cmap.chunk_size),
|
||||
exfat_c2o(ef, ef->cmap.start_cluster)) < 0)
|
||||
{
|
||||
exfat_error("failed to write clusters bitmap");
|
||||
return -EIO;
|
||||
}
|
||||
ef->cmap.dirty = false;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool set_next_cluster(const struct exfat* ef, bool contiguous,
|
||||
cluster_t current, cluster_t next)
|
||||
{
|
||||
off_t fat_offset;
|
||||
le32_t next_le32;
|
||||
|
||||
if (contiguous)
|
||||
return true;
|
||||
fat_offset = s2o(ef, le32_to_cpu(ef->sb->fat_sector_start))
|
||||
+ current * sizeof(cluster_t);
|
||||
next_le32 = cpu_to_le32(next);
|
||||
if (exfat_pwrite(ef->dev, &next_le32, sizeof(next_le32), fat_offset) < 0)
|
||||
{
|
||||
exfat_error("failed to write the next cluster %#x after %#x", next,
|
||||
current);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static cluster_t allocate_cluster(struct exfat* ef, cluster_t hint)
|
||||
{
|
||||
cluster_t cluster;
|
||||
|
||||
hint -= EXFAT_FIRST_DATA_CLUSTER;
|
||||
if (hint >= ef->cmap.chunk_size)
|
||||
hint = 0;
|
||||
|
||||
cluster = find_bit_and_set(ef->cmap.chunk, hint, ef->cmap.chunk_size);
|
||||
if (cluster == EXFAT_CLUSTER_END)
|
||||
cluster = find_bit_and_set(ef->cmap.chunk, 0, hint);
|
||||
if (cluster == EXFAT_CLUSTER_END)
|
||||
{
|
||||
exfat_error("no free space left");
|
||||
return EXFAT_CLUSTER_END;
|
||||
}
|
||||
|
||||
ef->cmap.dirty = true;
|
||||
return cluster;
|
||||
}
|
||||
|
||||
static void free_cluster(struct exfat* ef, cluster_t cluster)
|
||||
{
|
||||
if (cluster - EXFAT_FIRST_DATA_CLUSTER >= ef->cmap.size)
|
||||
exfat_bug("caller must check cluster validity (%#x, %#x)", cluster,
|
||||
ef->cmap.size);
|
||||
|
||||
BMAP_CLR(ef->cmap.chunk, cluster - EXFAT_FIRST_DATA_CLUSTER);
|
||||
ef->cmap.dirty = true;
|
||||
}
|
||||
|
||||
static bool make_noncontiguous(const struct exfat* ef, cluster_t first,
|
||||
cluster_t last)
|
||||
{
|
||||
cluster_t c;
|
||||
|
||||
for (c = first; c < last; c++)
|
||||
if (!set_next_cluster(ef, false, c, c + 1))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static int shrink_file(struct exfat* ef, struct exfat_node* node,
|
||||
uint32_t current, uint32_t difference);
|
||||
|
||||
static int grow_file(struct exfat* ef, struct exfat_node* node,
|
||||
uint32_t current, uint32_t difference)
|
||||
{
|
||||
cluster_t previous;
|
||||
cluster_t next;
|
||||
uint32_t allocated = 0;
|
||||
|
||||
if (difference == 0)
|
||||
exfat_bug("zero clusters count passed");
|
||||
|
||||
if (node->start_cluster != EXFAT_CLUSTER_FREE)
|
||||
{
|
||||
/* get the last cluster of the file */
|
||||
previous = exfat_advance_cluster(ef, node, current - 1);
|
||||
if (CLUSTER_INVALID(*ef->sb, previous))
|
||||
{
|
||||
exfat_error("invalid cluster 0x%x while growing", previous);
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (node->fptr_index != 0)
|
||||
exfat_bug("non-zero pointer index (%u)", node->fptr_index);
|
||||
/* file does not have clusters (i.e. is empty), allocate
|
||||
the first one for it */
|
||||
previous = allocate_cluster(ef, 0);
|
||||
if (CLUSTER_INVALID(*ef->sb, previous))
|
||||
return -ENOSPC;
|
||||
node->fptr_cluster = node->start_cluster = previous;
|
||||
allocated = 1;
|
||||
/* file consists of only one cluster, so it's contiguous */
|
||||
node->is_contiguous = true;
|
||||
}
|
||||
|
||||
while (allocated < difference)
|
||||
{
|
||||
next = allocate_cluster(ef, previous + 1);
|
||||
if (CLUSTER_INVALID(*ef->sb, next))
|
||||
{
|
||||
if (allocated != 0)
|
||||
shrink_file(ef, node, current + allocated, allocated);
|
||||
return -ENOSPC;
|
||||
}
|
||||
if (next != previous - 1 && node->is_contiguous)
|
||||
{
|
||||
/* it's a pity, but we are not able to keep the file contiguous
|
||||
anymore */
|
||||
if (!make_noncontiguous(ef, node->start_cluster, previous))
|
||||
return -EIO;
|
||||
node->is_contiguous = false;
|
||||
node->is_dirty = true;
|
||||
}
|
||||
if (!set_next_cluster(ef, node->is_contiguous, previous, next))
|
||||
return -EIO;
|
||||
previous = next;
|
||||
allocated++;
|
||||
}
|
||||
|
||||
if (!set_next_cluster(ef, node->is_contiguous, previous,
|
||||
EXFAT_CLUSTER_END))
|
||||
return -EIO;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int shrink_file(struct exfat* ef, struct exfat_node* node,
|
||||
uint32_t current, uint32_t difference)
|
||||
{
|
||||
cluster_t previous;
|
||||
cluster_t next;
|
||||
|
||||
if (difference == 0)
|
||||
exfat_bug("zero difference passed");
|
||||
if (node->start_cluster == EXFAT_CLUSTER_FREE)
|
||||
exfat_bug("unable to shrink empty file (%u clusters)", current);
|
||||
if (current < difference)
|
||||
exfat_bug("file underflow (%u < %u)", current, difference);
|
||||
|
||||
/* crop the file */
|
||||
if (current > difference)
|
||||
{
|
||||
cluster_t last = exfat_advance_cluster(ef, node,
|
||||
current - difference - 1);
|
||||
if (CLUSTER_INVALID(*ef->sb, last))
|
||||
{
|
||||
exfat_error("invalid cluster 0x%x while shrinking", last);
|
||||
return -EIO;
|
||||
}
|
||||
previous = exfat_next_cluster(ef, node, last);
|
||||
if (!set_next_cluster(ef, node->is_contiguous, last,
|
||||
EXFAT_CLUSTER_END))
|
||||
return -EIO;
|
||||
}
|
||||
else
|
||||
{
|
||||
previous = node->start_cluster;
|
||||
node->start_cluster = EXFAT_CLUSTER_FREE;
|
||||
node->is_dirty = true;
|
||||
}
|
||||
node->fptr_index = 0;
|
||||
node->fptr_cluster = node->start_cluster;
|
||||
|
||||
/* free remaining clusters */
|
||||
while (difference--)
|
||||
{
|
||||
if (CLUSTER_INVALID(*ef->sb, previous))
|
||||
{
|
||||
exfat_error("invalid cluster 0x%x while freeing after shrink",
|
||||
previous);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
next = exfat_next_cluster(ef, node, previous);
|
||||
if (!set_next_cluster(ef, node->is_contiguous, previous,
|
||||
EXFAT_CLUSTER_FREE))
|
||||
return -EIO;
|
||||
free_cluster(ef, previous);
|
||||
previous = next;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool erase_raw(struct exfat* ef, size_t size, off_t offset)
|
||||
{
|
||||
if (exfat_pwrite(ef->dev, ef->zero_cluster, size, offset) < 0)
|
||||
{
|
||||
exfat_error("failed to erase %zu bytes at %"PRId64, size, offset);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static int erase_range(struct exfat* ef, struct exfat_node* node,
|
||||
uint64_t begin, uint64_t end)
|
||||
{
|
||||
uint64_t cluster_boundary;
|
||||
cluster_t cluster;
|
||||
|
||||
if (begin >= end)
|
||||
return 0;
|
||||
|
||||
cluster_boundary = (begin | (CLUSTER_SIZE(*ef->sb) - 1)) + 1;
|
||||
cluster = exfat_advance_cluster(ef, node,
|
||||
begin / CLUSTER_SIZE(*ef->sb));
|
||||
if (CLUSTER_INVALID(*ef->sb, cluster))
|
||||
{
|
||||
exfat_error("invalid cluster 0x%x while erasing", cluster);
|
||||
return -EIO;
|
||||
}
|
||||
/* erase from the beginning to the closest cluster boundary */
|
||||
if (!erase_raw(ef, MIN(cluster_boundary, end) - begin,
|
||||
exfat_c2o(ef, cluster) + begin % CLUSTER_SIZE(*ef->sb)))
|
||||
return -EIO;
|
||||
/* erase whole clusters */
|
||||
while (cluster_boundary < end)
|
||||
{
|
||||
cluster = exfat_next_cluster(ef, node, cluster);
|
||||
/* the cluster cannot be invalid because we have just allocated it */
|
||||
if (CLUSTER_INVALID(*ef->sb, cluster))
|
||||
exfat_bug("invalid cluster 0x%x after allocation", cluster);
|
||||
if (!erase_raw(ef, CLUSTER_SIZE(*ef->sb), exfat_c2o(ef, cluster)))
|
||||
return -EIO;
|
||||
cluster_boundary += CLUSTER_SIZE(*ef->sb);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int exfat_truncate(struct exfat* ef, struct exfat_node* node, uint64_t size,
|
||||
bool erase)
|
||||
{
|
||||
uint32_t c1 = bytes2clusters(ef, node->size);
|
||||
uint32_t c2 = bytes2clusters(ef, size);
|
||||
int rc = 0;
|
||||
|
||||
if (node->references == 0 && node->parent)
|
||||
exfat_bug("no references, node changes can be lost");
|
||||
|
||||
if (node->size == size)
|
||||
return 0;
|
||||
|
||||
if (c1 < c2)
|
||||
rc = grow_file(ef, node, c1, c2 - c1);
|
||||
else if (c1 > c2)
|
||||
rc = shrink_file(ef, node, c1, c1 - c2);
|
||||
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
|
||||
if (erase)
|
||||
{
|
||||
rc = erase_range(ef, node, node->size, size);
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
}
|
||||
|
||||
exfat_update_mtime(node);
|
||||
node->size = size;
|
||||
node->is_dirty = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t exfat_count_free_clusters(const struct exfat* ef)
|
||||
{
|
||||
uint32_t free_clusters = 0;
|
||||
uint32_t i;
|
||||
|
||||
for (i = 0; i < ef->cmap.size; i++)
|
||||
if (BMAP_GET(ef->cmap.chunk, i) == 0)
|
||||
free_clusters++;
|
||||
return free_clusters;
|
||||
}
|
||||
|
||||
static int find_used_clusters(const struct exfat* ef,
|
||||
cluster_t* a, cluster_t* b)
|
||||
{
|
||||
const cluster_t end = le32_to_cpu(ef->sb->cluster_count);
|
||||
|
||||
/* find first used cluster */
|
||||
for (*a = *b + 1; *a < end; (*a)++)
|
||||
if (BMAP_GET(ef->cmap.chunk, *a - EXFAT_FIRST_DATA_CLUSTER))
|
||||
break;
|
||||
if (*a >= end)
|
||||
return 1;
|
||||
|
||||
/* find last contiguous used cluster */
|
||||
for (*b = *a; *b < end; (*b)++)
|
||||
if (BMAP_GET(ef->cmap.chunk, *b - EXFAT_FIRST_DATA_CLUSTER) == 0)
|
||||
{
|
||||
(*b)--;
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int exfat_find_used_sectors(const struct exfat* ef, off_t* a, off_t* b)
|
||||
{
|
||||
cluster_t ca, cb;
|
||||
|
||||
if (*a == 0 && *b == 0)
|
||||
ca = cb = EXFAT_FIRST_DATA_CLUSTER - 1;
|
||||
else
|
||||
{
|
||||
ca = s2c(ef, *a);
|
||||
cb = s2c(ef, *b);
|
||||
}
|
||||
if (find_used_clusters(ef, &ca, &cb) != 0)
|
||||
return 1;
|
||||
if (*a != 0 || *b != 0)
|
||||
*a = c2s(ef, ca);
|
||||
*b = c2s(ef, cb) + (CLUSTER_SIZE(*ef->sb) - 1) / SECTOR_SIZE(*ef->sb);
|
||||
return 0;
|
||||
}
|
||||
66
LinuxGUI/Ventoy2Disk/Lib/exfat/src/libexfat/compiler.h
Normal file
66
LinuxGUI/Ventoy2Disk/Lib/exfat/src/libexfat/compiler.h
Normal file
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
compiler.h (09.06.13)
|
||||
Compiler-specific definitions. Note that unknown compiler is not a
|
||||
showstopper.
|
||||
|
||||
Free exFAT implementation.
|
||||
Copyright (C) 2010-2018 Andrew Nayenko
|
||||
|
||||
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.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef COMPILER_H_INCLUDED
|
||||
#define COMPILER_H_INCLUDED
|
||||
|
||||
#if __STDC_VERSION__ < 199901L
|
||||
#error C99-compliant compiler is required
|
||||
#endif
|
||||
|
||||
#if defined(__clang__)
|
||||
|
||||
#define PRINTF __attribute__((format(printf, 1, 2)))
|
||||
#define NORETURN __attribute__((noreturn))
|
||||
#define PACKED __attribute__((packed))
|
||||
#if __has_extension(c_static_assert)
|
||||
#define USE_C11_STATIC_ASSERT
|
||||
#endif
|
||||
|
||||
#elif defined(__GNUC__)
|
||||
|
||||
#define PRINTF __attribute__((format(printf, 1, 2)))
|
||||
#define NORETURN __attribute__((noreturn))
|
||||
#define PACKED __attribute__((packed))
|
||||
#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
|
||||
#define USE_C11_STATIC_ASSERT
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
#define PRINTF
|
||||
#define NORETURN
|
||||
#define PACKED
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef USE_C11_STATIC_ASSERT
|
||||
#define STATIC_ASSERT(cond) _Static_assert(cond, #cond)
|
||||
#else
|
||||
#define CONCAT2(a, b) a ## b
|
||||
#define CONCAT1(a, b) CONCAT2(a, b)
|
||||
#define STATIC_ASSERT(cond) \
|
||||
extern void CONCAT1(static_assert, __LINE__)(int x[(cond) ? 1 : -1])
|
||||
#endif
|
||||
|
||||
#endif /* ifndef COMPILER_H_INCLUDED */
|
||||
40
LinuxGUI/Ventoy2Disk/Lib/exfat/src/libexfat/config.h
Normal file
40
LinuxGUI/Ventoy2Disk/Lib/exfat/src/libexfat/config.h
Normal file
@@ -0,0 +1,40 @@
|
||||
/* libexfat/config.h. Generated from config.h.in by configure. */
|
||||
/* libexfat/config.h.in. Generated from configure.ac by autoheader. */
|
||||
|
||||
/* Name of package */
|
||||
#define PACKAGE "exfat"
|
||||
|
||||
/* Define to the address where bug reports for this package should be sent. */
|
||||
#define PACKAGE_BUGREPORT "relan@users.noreply.github.com"
|
||||
|
||||
/* Define to the full name of this package. */
|
||||
#define PACKAGE_NAME "Free exFAT implementation"
|
||||
|
||||
/* Define to the full name and version of this package. */
|
||||
#define PACKAGE_STRING "Free exFAT implementation 1.3.0"
|
||||
|
||||
/* Define to the one symbol short name of this package. */
|
||||
#define PACKAGE_TARNAME "exfat"
|
||||
|
||||
/* Define to the home page for this package. */
|
||||
#define PACKAGE_URL "https://github.com/relan/exfat"
|
||||
|
||||
/* Define to the version of this package. */
|
||||
#define PACKAGE_VERSION "1.3.0"
|
||||
|
||||
/* Define if block devices are not supported. */
|
||||
/* #undef USE_UBLIO */
|
||||
|
||||
/* Version number of package */
|
||||
#define VERSION "1.3.0"
|
||||
|
||||
/* Enable large inode numbers on Mac OS X 10.5. */
|
||||
#ifndef _DARWIN_USE_64_BIT_INODE
|
||||
# define _DARWIN_USE_64_BIT_INODE 1
|
||||
#endif
|
||||
|
||||
/* Number of bits in a file offset, on hosts where this is settable. */
|
||||
/* #undef _FILE_OFFSET_BITS */
|
||||
|
||||
/* Define for large files, on AIX-style hosts. */
|
||||
/* #undef _LARGE_FILES */
|
||||
255
LinuxGUI/Ventoy2Disk/Lib/exfat/src/libexfat/exfat.h
Normal file
255
LinuxGUI/Ventoy2Disk/Lib/exfat/src/libexfat/exfat.h
Normal file
@@ -0,0 +1,255 @@
|
||||
/*
|
||||
exfat.h (29.08.09)
|
||||
Definitions of structures and constants used in exFAT file system
|
||||
implementation.
|
||||
|
||||
Free exFAT implementation.
|
||||
Copyright (C) 2010-2018 Andrew Nayenko
|
||||
|
||||
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.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef EXFAT_H_INCLUDED
|
||||
#define EXFAT_H_INCLUDED
|
||||
|
||||
#ifndef ANDROID
|
||||
/* Android.bp is used instead of autotools when targeting Android */
|
||||
#include "config.h"
|
||||
#endif
|
||||
#include "compiler.h"
|
||||
#include "exfatfs.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <stdbool.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#define EXFAT_NAME_MAX 255
|
||||
/* UTF-16 encodes code points up to U+FFFF as single 16-bit code units.
|
||||
UTF-8 uses up to 3 bytes (i.e. 8-bit code units) to encode code points
|
||||
up to U+FFFF. One additional character is for null terminator. */
|
||||
#define EXFAT_UTF8_NAME_BUFFER_MAX (EXFAT_NAME_MAX * 3 + 1)
|
||||
#define EXFAT_UTF8_ENAME_BUFFER_MAX (EXFAT_ENAME_MAX * 3 + 1)
|
||||
|
||||
#define SECTOR_SIZE(sb) (1 << (sb).sector_bits)
|
||||
#define CLUSTER_SIZE(sb) (SECTOR_SIZE(sb) << (sb).spc_bits)
|
||||
#define CLUSTER_INVALID(sb, c) ((c) < EXFAT_FIRST_DATA_CLUSTER || \
|
||||
(c) - EXFAT_FIRST_DATA_CLUSTER >= le32_to_cpu((sb).cluster_count))
|
||||
|
||||
#define MIN(a, b) ((a) < (b) ? (a) : (b))
|
||||
#define MAX(a, b) ((a) > (b) ? (a) : (b))
|
||||
#define DIV_ROUND_UP(x, d) (((x) + (d) - 1) / (d))
|
||||
#define ROUND_UP(x, d) (DIV_ROUND_UP(x, d) * (d))
|
||||
|
||||
#define BMAP_SIZE(count) (ROUND_UP(count, sizeof(bitmap_t) * 8) / 8)
|
||||
#define BMAP_BLOCK(index) ((index) / sizeof(bitmap_t) / 8)
|
||||
#define BMAP_MASK(index) ((bitmap_t) 1 << ((index) % (sizeof(bitmap_t) * 8)))
|
||||
#define BMAP_GET(bitmap, index) \
|
||||
((bitmap)[BMAP_BLOCK(index)] & BMAP_MASK(index))
|
||||
#define BMAP_SET(bitmap, index) \
|
||||
((bitmap)[BMAP_BLOCK(index)] |= BMAP_MASK(index))
|
||||
#define BMAP_CLR(bitmap, index) \
|
||||
((bitmap)[BMAP_BLOCK(index)] &= ~BMAP_MASK(index))
|
||||
|
||||
#define EXFAT_REPAIR(hook, ef, ...) \
|
||||
(exfat_ask_to_fix(ef) && exfat_fix_ ## hook(ef, __VA_ARGS__))
|
||||
|
||||
/* The size of off_t type must be 64 bits. File systems larger than 2 GB will
|
||||
be corrupted with 32-bit off_t. */
|
||||
STATIC_ASSERT(sizeof(off_t) == 8);
|
||||
|
||||
struct exfat_node
|
||||
{
|
||||
struct exfat_node* parent;
|
||||
struct exfat_node* child;
|
||||
struct exfat_node* next;
|
||||
struct exfat_node* prev;
|
||||
|
||||
int references;
|
||||
uint32_t fptr_index;
|
||||
cluster_t fptr_cluster;
|
||||
off_t entry_offset;
|
||||
cluster_t start_cluster;
|
||||
uint16_t attrib;
|
||||
uint8_t continuations;
|
||||
bool is_contiguous : 1;
|
||||
bool is_cached : 1;
|
||||
bool is_dirty : 1;
|
||||
bool is_unlinked : 1;
|
||||
uint64_t size;
|
||||
time_t mtime, atime;
|
||||
le16_t name[EXFAT_NAME_MAX + 1];
|
||||
};
|
||||
|
||||
enum exfat_mode
|
||||
{
|
||||
EXFAT_MODE_RO,
|
||||
EXFAT_MODE_RW,
|
||||
EXFAT_MODE_ANY,
|
||||
};
|
||||
|
||||
struct exfat_dev;
|
||||
|
||||
struct exfat
|
||||
{
|
||||
struct exfat_dev* dev;
|
||||
struct exfat_super_block* sb;
|
||||
uint16_t* upcase;
|
||||
struct exfat_node* root;
|
||||
struct
|
||||
{
|
||||
cluster_t start_cluster;
|
||||
uint32_t size; /* in bits */
|
||||
bitmap_t* chunk;
|
||||
uint32_t chunk_size; /* in bits */
|
||||
bool dirty;
|
||||
}
|
||||
cmap;
|
||||
char label[EXFAT_UTF8_ENAME_BUFFER_MAX];
|
||||
void* zero_cluster;
|
||||
int dmask, fmask;
|
||||
uid_t uid;
|
||||
gid_t gid;
|
||||
int ro;
|
||||
bool noatime;
|
||||
enum { EXFAT_REPAIR_NO, EXFAT_REPAIR_ASK, EXFAT_REPAIR_YES } repair;
|
||||
};
|
||||
|
||||
/* in-core nodes iterator */
|
||||
struct exfat_iterator
|
||||
{
|
||||
struct exfat_node* parent;
|
||||
struct exfat_node* current;
|
||||
};
|
||||
|
||||
struct exfat_human_bytes
|
||||
{
|
||||
uint64_t value;
|
||||
const char* unit;
|
||||
};
|
||||
|
||||
extern int exfat_errors;
|
||||
extern int exfat_errors_fixed;
|
||||
|
||||
#define VLOG_LOG 1
|
||||
#define VLOG_DEBUG 2
|
||||
void ventoy_syslog_newline(int level, const char *Fmt, ...);
|
||||
#define exfat_bug(fmt, args...) ventoy_syslog_newline(VLOG_LOG, fmt, ##args)
|
||||
#define exfat_error(fmt, args...) ventoy_syslog_newline(VLOG_LOG, fmt, ##args)
|
||||
#define exfat_error(fmt, args...) ventoy_syslog_newline(VLOG_LOG, fmt, ##args)
|
||||
#define exfat_warn(fmt, args...) ventoy_syslog_newline(VLOG_LOG, fmt, ##args)
|
||||
#define exfat_debug(fmt, args...) ventoy_syslog_newline(VLOG_DEBUG, fmt, ##args)
|
||||
|
||||
#if 0
|
||||
void exfat_bug(const char* format, ...) PRINTF NORETURN;
|
||||
void exfat_error(const char* format, ...) PRINTF;
|
||||
void exfat_warn(const char* format, ...) PRINTF;
|
||||
void exfat_debug(const char* format, ...) PRINTF;
|
||||
#endif /* #if 0 */
|
||||
|
||||
struct exfat_dev* exfat_open(const char* spec, enum exfat_mode mode);
|
||||
int exfat_close(struct exfat_dev* dev);
|
||||
int exfat_fsync(struct exfat_dev* dev);
|
||||
enum exfat_mode exfat_get_mode(const struct exfat_dev* dev);
|
||||
off_t exfat_get_size(const struct exfat_dev* dev);
|
||||
off_t exfat_seek(struct exfat_dev* dev, off_t offset, int whence);
|
||||
ssize_t exfat_read(struct exfat_dev* dev, void* buffer, size_t size);
|
||||
ssize_t exfat_write(struct exfat_dev* dev, const void* buffer, size_t size);
|
||||
ssize_t exfat_pread(struct exfat_dev* dev, void* buffer, size_t size,
|
||||
off_t offset);
|
||||
ssize_t exfat_pwrite(struct exfat_dev* dev, const void* buffer, size_t size,
|
||||
off_t offset);
|
||||
ssize_t exfat_generic_pread(const struct exfat* ef, struct exfat_node* node,
|
||||
void* buffer, size_t size, off_t offset);
|
||||
ssize_t exfat_generic_pwrite(struct exfat* ef, struct exfat_node* node,
|
||||
const void* buffer, size_t size, off_t offset);
|
||||
|
||||
int exfat_opendir(struct exfat* ef, struct exfat_node* dir,
|
||||
struct exfat_iterator* it);
|
||||
void exfat_closedir(struct exfat* ef, struct exfat_iterator* it);
|
||||
struct exfat_node* exfat_readdir(struct exfat_iterator* it);
|
||||
int exfat_lookup(struct exfat* ef, struct exfat_node** node,
|
||||
const char* path);
|
||||
int exfat_split(struct exfat* ef, struct exfat_node** parent,
|
||||
struct exfat_node** node, le16_t* name, const char* path);
|
||||
|
||||
off_t exfat_c2o(const struct exfat* ef, cluster_t cluster);
|
||||
cluster_t exfat_next_cluster(const struct exfat* ef,
|
||||
const struct exfat_node* node, cluster_t cluster);
|
||||
cluster_t exfat_advance_cluster(const struct exfat* ef,
|
||||
struct exfat_node* node, uint32_t count);
|
||||
int exfat_flush_nodes(struct exfat* ef);
|
||||
int exfat_flush(struct exfat* ef);
|
||||
int exfat_truncate(struct exfat* ef, struct exfat_node* node, uint64_t size,
|
||||
bool erase);
|
||||
uint32_t exfat_count_free_clusters(const struct exfat* ef);
|
||||
int exfat_find_used_sectors(const struct exfat* ef, off_t* a, off_t* b);
|
||||
|
||||
void exfat_stat(const struct exfat* ef, const struct exfat_node* node,
|
||||
struct stat* stbuf);
|
||||
void exfat_get_name(const struct exfat_node* node,
|
||||
char buffer[EXFAT_UTF8_NAME_BUFFER_MAX]);
|
||||
uint16_t exfat_start_checksum(const struct exfat_entry_meta1* entry);
|
||||
uint16_t exfat_add_checksum(const void* entry, uint16_t sum);
|
||||
le16_t exfat_calc_checksum(const struct exfat_entry* entries, int n);
|
||||
uint32_t exfat_vbr_start_checksum(const void* sector, size_t size);
|
||||
uint32_t exfat_vbr_add_checksum(const void* sector, size_t size, uint32_t sum);
|
||||
le16_t exfat_calc_name_hash(const struct exfat* ef, const le16_t* name,
|
||||
size_t length);
|
||||
void exfat_humanize_bytes(uint64_t value, struct exfat_human_bytes* hb);
|
||||
void exfat_print_info(const struct exfat_super_block* sb,
|
||||
uint32_t free_clusters);
|
||||
|
||||
int utf16_to_utf8(char* output, const le16_t* input, size_t outsize,
|
||||
size_t insize);
|
||||
int utf8_to_utf16(le16_t* output, const char* input, size_t outsize,
|
||||
size_t insize);
|
||||
size_t utf16_length(const le16_t* str);
|
||||
|
||||
struct exfat_node* exfat_get_node(struct exfat_node* node);
|
||||
void exfat_put_node(struct exfat* ef, struct exfat_node* node);
|
||||
int exfat_cleanup_node(struct exfat* ef, struct exfat_node* node);
|
||||
int exfat_cache_directory(struct exfat* ef, struct exfat_node* dir);
|
||||
void exfat_reset_cache(struct exfat* ef);
|
||||
int exfat_flush_node(struct exfat* ef, struct exfat_node* node);
|
||||
int exfat_unlink(struct exfat* ef, struct exfat_node* node);
|
||||
int exfat_rmdir(struct exfat* ef, struct exfat_node* node);
|
||||
int exfat_mknod(struct exfat* ef, const char* path);
|
||||
int exfat_mkdir(struct exfat* ef, const char* path);
|
||||
int exfat_rename(struct exfat* ef, const char* old_path, const char* new_path);
|
||||
void exfat_utimes(struct exfat_node* node, const struct timespec tv[2]);
|
||||
void exfat_update_atime(struct exfat_node* node);
|
||||
void exfat_update_mtime(struct exfat_node* node);
|
||||
const char* exfat_get_label(struct exfat* ef);
|
||||
int exfat_set_label(struct exfat* ef, const char* label);
|
||||
|
||||
int exfat_mount(struct exfat* ef, const char* spec, const char* options);
|
||||
void exfat_unmount(struct exfat* ef);
|
||||
|
||||
time_t exfat_exfat2unix(le16_t date, le16_t time, uint8_t centisec);
|
||||
void exfat_unix2exfat(time_t unix_time, le16_t* date, le16_t* time,
|
||||
uint8_t* centisec);
|
||||
void exfat_tzset(void);
|
||||
|
||||
bool exfat_ask_to_fix(const struct exfat* ef);
|
||||
bool exfat_fix_invalid_vbr_checksum(const struct exfat* ef, void* sector,
|
||||
uint32_t vbr_checksum);
|
||||
bool exfat_fix_invalid_node_checksum(const struct exfat* ef,
|
||||
struct exfat_node* node);
|
||||
bool exfat_fix_unknown_entry(struct exfat* ef, struct exfat_node* dir,
|
||||
const struct exfat_entry* entry, off_t offset);
|
||||
|
||||
#endif /* ifndef EXFAT_H_INCLUDED */
|
||||
180
LinuxGUI/Ventoy2Disk/Lib/exfat/src/libexfat/exfatfs.h
Normal file
180
LinuxGUI/Ventoy2Disk/Lib/exfat/src/libexfat/exfatfs.h
Normal file
@@ -0,0 +1,180 @@
|
||||
/*
|
||||
exfatfs.h (29.08.09)
|
||||
Definitions of structures and constants used in exFAT file system.
|
||||
|
||||
Free exFAT implementation.
|
||||
Copyright (C) 2010-2018 Andrew Nayenko
|
||||
|
||||
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.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef EXFATFS_H_INCLUDED
|
||||
#define EXFATFS_H_INCLUDED
|
||||
|
||||
#include "byteorder.h"
|
||||
#include "compiler.h"
|
||||
|
||||
typedef uint32_t cluster_t; /* cluster number */
|
||||
|
||||
#define EXFAT_FIRST_DATA_CLUSTER 2
|
||||
#define EXFAT_LAST_DATA_CLUSTER 0xfffffff6
|
||||
|
||||
#define EXFAT_CLUSTER_FREE 0 /* free cluster */
|
||||
#define EXFAT_CLUSTER_BAD 0xfffffff7 /* cluster contains bad sector */
|
||||
#define EXFAT_CLUSTER_END 0xffffffff /* final cluster of file or directory */
|
||||
|
||||
#define EXFAT_STATE_MOUNTED 2
|
||||
|
||||
struct exfat_super_block
|
||||
{
|
||||
uint8_t jump[3]; /* 0x00 jmp and nop instructions */
|
||||
uint8_t oem_name[8]; /* 0x03 "EXFAT " */
|
||||
uint8_t __unused1[53]; /* 0x0B always 0 */
|
||||
le64_t sector_start; /* 0x40 partition first sector */
|
||||
le64_t sector_count; /* 0x48 partition sectors count */
|
||||
le32_t fat_sector_start; /* 0x50 FAT first sector */
|
||||
le32_t fat_sector_count; /* 0x54 FAT sectors count */
|
||||
le32_t cluster_sector_start; /* 0x58 first cluster sector */
|
||||
le32_t cluster_count; /* 0x5C total clusters count */
|
||||
le32_t rootdir_cluster; /* 0x60 first cluster of the root dir */
|
||||
le32_t volume_serial; /* 0x64 volume serial number */
|
||||
struct /* 0x68 FS version */
|
||||
{
|
||||
uint8_t minor;
|
||||
uint8_t major;
|
||||
}
|
||||
version;
|
||||
le16_t volume_state; /* 0x6A volume state flags */
|
||||
uint8_t sector_bits; /* 0x6C sector size as (1 << n) */
|
||||
uint8_t spc_bits; /* 0x6D sectors per cluster as (1 << n) */
|
||||
uint8_t fat_count; /* 0x6E always 1 */
|
||||
uint8_t drive_no; /* 0x6F always 0x80 */
|
||||
uint8_t allocated_percent; /* 0x70 percentage of allocated space */
|
||||
uint8_t __unused2[397]; /* 0x71 always 0 */
|
||||
le16_t boot_signature; /* the value of 0xAA55 */
|
||||
}
|
||||
PACKED;
|
||||
STATIC_ASSERT(sizeof(struct exfat_super_block) == 512);
|
||||
|
||||
#define EXFAT_ENTRY_VALID 0x80
|
||||
#define EXFAT_ENTRY_CONTINUED 0x40
|
||||
#define EXFAT_ENTRY_OPTIONAL 0x20
|
||||
|
||||
#define EXFAT_ENTRY_BITMAP (0x01 | EXFAT_ENTRY_VALID)
|
||||
#define EXFAT_ENTRY_UPCASE (0x02 | EXFAT_ENTRY_VALID)
|
||||
#define EXFAT_ENTRY_LABEL (0x03 | EXFAT_ENTRY_VALID)
|
||||
#define EXFAT_ENTRY_FILE (0x05 | EXFAT_ENTRY_VALID)
|
||||
#define EXFAT_ENTRY_FILE_INFO (0x00 | EXFAT_ENTRY_VALID | EXFAT_ENTRY_CONTINUED)
|
||||
#define EXFAT_ENTRY_FILE_NAME (0x01 | EXFAT_ENTRY_VALID | EXFAT_ENTRY_CONTINUED)
|
||||
#define EXFAT_ENTRY_FILE_TAIL (0x00 | EXFAT_ENTRY_VALID \
|
||||
| EXFAT_ENTRY_CONTINUED \
|
||||
| EXFAT_ENTRY_OPTIONAL)
|
||||
|
||||
struct exfat_entry /* common container for all entries */
|
||||
{
|
||||
uint8_t type; /* any of EXFAT_ENTRY_xxx */
|
||||
uint8_t data[31];
|
||||
}
|
||||
PACKED;
|
||||
STATIC_ASSERT(sizeof(struct exfat_entry) == 32);
|
||||
|
||||
#define EXFAT_ENAME_MAX 15
|
||||
|
||||
struct exfat_entry_bitmap /* allocated clusters bitmap */
|
||||
{
|
||||
uint8_t type; /* EXFAT_ENTRY_BITMAP */
|
||||
uint8_t __unknown1[19];
|
||||
le32_t start_cluster;
|
||||
le64_t size; /* in bytes */
|
||||
}
|
||||
PACKED;
|
||||
STATIC_ASSERT(sizeof(struct exfat_entry_bitmap) == 32);
|
||||
|
||||
#define EXFAT_UPCASE_CHARS 0x10000
|
||||
|
||||
struct exfat_entry_upcase /* upper case translation table */
|
||||
{
|
||||
uint8_t type; /* EXFAT_ENTRY_UPCASE */
|
||||
uint8_t __unknown1[3];
|
||||
le32_t checksum;
|
||||
uint8_t __unknown2[12];
|
||||
le32_t start_cluster;
|
||||
le64_t size; /* in bytes */
|
||||
}
|
||||
PACKED;
|
||||
STATIC_ASSERT(sizeof(struct exfat_entry_upcase) == 32);
|
||||
|
||||
struct exfat_entry_label /* volume label */
|
||||
{
|
||||
uint8_t type; /* EXFAT_ENTRY_LABEL */
|
||||
uint8_t length; /* number of characters */
|
||||
le16_t name[EXFAT_ENAME_MAX]; /* in UTF-16LE */
|
||||
}
|
||||
PACKED;
|
||||
STATIC_ASSERT(sizeof(struct exfat_entry_label) == 32);
|
||||
|
||||
#define EXFAT_ATTRIB_RO 0x01
|
||||
#define EXFAT_ATTRIB_HIDDEN 0x02
|
||||
#define EXFAT_ATTRIB_SYSTEM 0x04
|
||||
#define EXFAT_ATTRIB_VOLUME 0x08
|
||||
#define EXFAT_ATTRIB_DIR 0x10
|
||||
#define EXFAT_ATTRIB_ARCH 0x20
|
||||
|
||||
struct exfat_entry_meta1 /* file or directory info (part 1) */
|
||||
{
|
||||
uint8_t type; /* EXFAT_ENTRY_FILE */
|
||||
uint8_t continuations;
|
||||
le16_t checksum;
|
||||
le16_t attrib; /* combination of EXFAT_ATTRIB_xxx */
|
||||
le16_t __unknown1;
|
||||
le16_t crtime, crdate; /* creation date and time */
|
||||
le16_t mtime, mdate; /* latest modification date and time */
|
||||
le16_t atime, adate; /* latest access date and time */
|
||||
uint8_t crtime_cs; /* creation time in cs (centiseconds) */
|
||||
uint8_t mtime_cs; /* latest modification time in cs */
|
||||
uint8_t __unknown2[10];
|
||||
}
|
||||
PACKED;
|
||||
STATIC_ASSERT(sizeof(struct exfat_entry_meta1) == 32);
|
||||
|
||||
#define EXFAT_FLAG_ALWAYS1 (1u << 0)
|
||||
#define EXFAT_FLAG_CONTIGUOUS (1u << 1)
|
||||
|
||||
struct exfat_entry_meta2 /* file or directory info (part 2) */
|
||||
{
|
||||
uint8_t type; /* EXFAT_ENTRY_FILE_INFO */
|
||||
uint8_t flags; /* combination of EXFAT_FLAG_xxx */
|
||||
uint8_t __unknown1;
|
||||
uint8_t name_length;
|
||||
le16_t name_hash;
|
||||
le16_t __unknown2;
|
||||
le64_t valid_size; /* in bytes, less or equal to size */
|
||||
uint8_t __unknown3[4];
|
||||
le32_t start_cluster;
|
||||
le64_t size; /* in bytes */
|
||||
}
|
||||
PACKED;
|
||||
STATIC_ASSERT(sizeof(struct exfat_entry_meta2) == 32);
|
||||
|
||||
struct exfat_entry_name /* file or directory name */
|
||||
{
|
||||
uint8_t type; /* EXFAT_ENTRY_FILE_NAME */
|
||||
uint8_t __unknown;
|
||||
le16_t name[EXFAT_ENAME_MAX]; /* in UTF-16LE */
|
||||
}
|
||||
PACKED;
|
||||
STATIC_ASSERT(sizeof(struct exfat_entry_name) == 32);
|
||||
|
||||
#endif /* ifndef EXFATFS_H_INCLUDED */
|
||||
511
LinuxGUI/Ventoy2Disk/Lib/exfat/src/libexfat/io.c
Normal file
511
LinuxGUI/Ventoy2Disk/Lib/exfat/src/libexfat/io.c
Normal file
@@ -0,0 +1,511 @@
|
||||
/*
|
||||
io.c (02.09.09)
|
||||
exFAT file system implementation library.
|
||||
|
||||
Free exFAT implementation.
|
||||
Copyright (C) 2010-2018 Andrew Nayenko
|
||||
|
||||
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.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "exfat.h"
|
||||
#include <inttypes.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#if defined(__APPLE__)
|
||||
#include <sys/disk.h>
|
||||
#elif defined(__OpenBSD__)
|
||||
#include <sys/param.h>
|
||||
#include <sys/disklabel.h>
|
||||
#include <sys/dkio.h>
|
||||
#include <sys/ioctl.h>
|
||||
#elif __linux__
|
||||
#include <sys/mount.h>
|
||||
#endif
|
||||
#ifdef USE_UBLIO
|
||||
#include <sys/uio.h>
|
||||
#include <ublio.h>
|
||||
#endif
|
||||
|
||||
struct exfat_dev
|
||||
{
|
||||
int fd;
|
||||
enum exfat_mode mode;
|
||||
off_t size; /* in bytes */
|
||||
#ifdef USE_UBLIO
|
||||
off_t pos;
|
||||
ublio_filehandle_t ufh;
|
||||
#endif
|
||||
};
|
||||
|
||||
int g_vtoy_exfat_disk_fd = -1;
|
||||
uint64_t g_vtoy_exfat_part_size = 0;
|
||||
|
||||
static bool is_open(int fd)
|
||||
{
|
||||
return fcntl(fd, F_GETFD) != -1;
|
||||
}
|
||||
|
||||
static int open_ro(const char* spec)
|
||||
{
|
||||
return open(spec, O_RDONLY);
|
||||
}
|
||||
|
||||
static int open_rw(const char* spec)
|
||||
{
|
||||
int fd = open(spec, O_RDWR);
|
||||
#ifdef __linux__
|
||||
int ro = 0;
|
||||
|
||||
/*
|
||||
This ioctl is needed because after "blockdev --setro" kernel still
|
||||
allows to open the device in read-write mode but fails writes.
|
||||
*/
|
||||
if (fd != -1 && ioctl(fd, BLKROGET, &ro) == 0 && ro)
|
||||
{
|
||||
close(fd);
|
||||
errno = EROFS;
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
return fd;
|
||||
}
|
||||
|
||||
struct exfat_dev* exfat_open(const char* spec, enum exfat_mode mode)
|
||||
{
|
||||
struct exfat_dev* dev;
|
||||
struct stat stbuf;
|
||||
#ifdef USE_UBLIO
|
||||
struct ublio_param up;
|
||||
#endif
|
||||
|
||||
/* The system allocates file descriptors sequentially. If we have been
|
||||
started with stdin (0), stdout (1) or stderr (2) closed, the system
|
||||
will give us descriptor 0, 1 or 2 later when we open block device,
|
||||
FUSE communication pipe, etc. As a result, functions using stdin,
|
||||
stdout or stderr will actually work with a different thing and can
|
||||
corrupt it. Protect descriptors 0, 1 and 2 from such misuse. */
|
||||
while (!is_open(STDIN_FILENO)
|
||||
|| !is_open(STDOUT_FILENO)
|
||||
|| !is_open(STDERR_FILENO))
|
||||
{
|
||||
/* we don't need those descriptors, let them leak */
|
||||
if (open("/dev/null", O_RDWR) == -1)
|
||||
{
|
||||
exfat_error("failed to open /dev/null");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
dev = malloc(sizeof(struct exfat_dev));
|
||||
if (dev == NULL)
|
||||
{
|
||||
exfat_error("failed to allocate memory for device structure");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
switch (mode)
|
||||
{
|
||||
case EXFAT_MODE_RO:
|
||||
dev->fd = g_vtoy_exfat_disk_fd < 0 ? open_ro(spec) : g_vtoy_exfat_disk_fd;
|
||||
if (dev->fd == -1)
|
||||
{
|
||||
free(dev);
|
||||
exfat_error("failed to open '%s' in read-only mode: %s", spec,
|
||||
strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
dev->mode = EXFAT_MODE_RO;
|
||||
break;
|
||||
case EXFAT_MODE_RW:
|
||||
dev->fd = g_vtoy_exfat_disk_fd < 0 ? open_rw(spec) : g_vtoy_exfat_disk_fd;
|
||||
if (dev->fd == -1)
|
||||
{
|
||||
free(dev);
|
||||
exfat_error("failed to open '%s' in read-write mode: %s", spec,
|
||||
strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
dev->mode = EXFAT_MODE_RW;
|
||||
break;
|
||||
case EXFAT_MODE_ANY:
|
||||
dev->fd = g_vtoy_exfat_disk_fd < 0 ? open_rw(spec) : g_vtoy_exfat_disk_fd;
|
||||
if (dev->fd != -1)
|
||||
{
|
||||
dev->mode = EXFAT_MODE_RW;
|
||||
break;
|
||||
}
|
||||
dev->fd = g_vtoy_exfat_disk_fd < 0 ? open_ro(spec) : g_vtoy_exfat_disk_fd;
|
||||
if (dev->fd != -1)
|
||||
{
|
||||
dev->mode = EXFAT_MODE_RO;
|
||||
exfat_warn("'%s' is write-protected, mounting read-only", spec);
|
||||
break;
|
||||
}
|
||||
free(dev);
|
||||
exfat_error("failed to open '%s': %s", spec, strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (fstat(dev->fd, &stbuf) != 0)
|
||||
{
|
||||
close(dev->fd);
|
||||
free(dev);
|
||||
exfat_error("failed to fstat '%s'", spec);
|
||||
return NULL;
|
||||
}
|
||||
if (!S_ISBLK(stbuf.st_mode) &&
|
||||
!S_ISCHR(stbuf.st_mode) &&
|
||||
!S_ISREG(stbuf.st_mode))
|
||||
{
|
||||
close(dev->fd);
|
||||
free(dev);
|
||||
exfat_error("'%s' is neither a device, nor a regular file", spec);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#if defined(__APPLE__)
|
||||
if (!S_ISREG(stbuf.st_mode))
|
||||
{
|
||||
uint32_t block_size = 0;
|
||||
uint64_t blocks = 0;
|
||||
|
||||
if (ioctl(dev->fd, DKIOCGETBLOCKSIZE, &block_size) != 0)
|
||||
{
|
||||
close(dev->fd);
|
||||
free(dev);
|
||||
exfat_error("failed to get block size");
|
||||
return NULL;
|
||||
}
|
||||
if (ioctl(dev->fd, DKIOCGETBLOCKCOUNT, &blocks) != 0)
|
||||
{
|
||||
close(dev->fd);
|
||||
free(dev);
|
||||
exfat_error("failed to get blocks count");
|
||||
return NULL;
|
||||
}
|
||||
dev->size = blocks * block_size;
|
||||
}
|
||||
else
|
||||
#elif defined(__OpenBSD__)
|
||||
if (!S_ISREG(stbuf.st_mode))
|
||||
{
|
||||
struct disklabel lab;
|
||||
struct partition* pp;
|
||||
char* partition;
|
||||
|
||||
if (ioctl(dev->fd, DIOCGDINFO, &lab) == -1)
|
||||
{
|
||||
close(dev->fd);
|
||||
free(dev);
|
||||
exfat_error("failed to get disklabel");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Don't need to check that partition letter is valid as we won't get
|
||||
this far otherwise. */
|
||||
partition = strchr(spec, '\0') - 1;
|
||||
pp = &(lab.d_partitions[*partition - 'a']);
|
||||
dev->size = DL_GETPSIZE(pp) * lab.d_secsize;
|
||||
|
||||
if (pp->p_fstype != FS_NTFS)
|
||||
exfat_warn("partition type is not 0x07 (NTFS/exFAT); "
|
||||
"you can fix this with fdisk(8)");
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
/* works for Linux, FreeBSD, Solaris */
|
||||
dev->size = exfat_seek(dev, 0, SEEK_END);
|
||||
if (dev->size <= 0)
|
||||
{
|
||||
close(dev->fd);
|
||||
free(dev);
|
||||
exfat_error("failed to get size of '%s'", spec);
|
||||
return NULL;
|
||||
}
|
||||
if (exfat_seek(dev, 0, SEEK_SET) == -1)
|
||||
{
|
||||
close(dev->fd);
|
||||
free(dev);
|
||||
exfat_error("failed to seek to the beginning of '%s'", spec);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef USE_UBLIO
|
||||
memset(&up, 0, sizeof(struct ublio_param));
|
||||
up.up_blocksize = 256 * 1024;
|
||||
up.up_items = 64;
|
||||
up.up_grace = 32;
|
||||
up.up_priv = &dev->fd;
|
||||
|
||||
dev->pos = 0;
|
||||
dev->ufh = ublio_open(&up);
|
||||
if (dev->ufh == NULL)
|
||||
{
|
||||
close(dev->fd);
|
||||
free(dev);
|
||||
exfat_error("failed to initialize ublio");
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
return dev;
|
||||
}
|
||||
|
||||
int exfat_close(struct exfat_dev* dev)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
#ifdef USE_UBLIO
|
||||
if (ublio_close(dev->ufh) != 0)
|
||||
{
|
||||
exfat_error("failed to close ublio");
|
||||
rc = -EIO;
|
||||
}
|
||||
#endif
|
||||
if (dev->fd != g_vtoy_exfat_disk_fd)
|
||||
{
|
||||
if (close(dev->fd) != 0)
|
||||
{
|
||||
exfat_error("failed to close device: %s", strerror(errno));
|
||||
rc = -EIO;
|
||||
}
|
||||
}
|
||||
|
||||
free(dev);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int exfat_fsync(struct exfat_dev* dev)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
#ifdef USE_UBLIO
|
||||
if (ublio_fsync(dev->ufh) != 0)
|
||||
{
|
||||
exfat_error("ublio fsync failed");
|
||||
rc = -EIO;
|
||||
}
|
||||
#endif
|
||||
if (fsync(dev->fd) != 0)
|
||||
{
|
||||
exfat_error("fsync failed: %s", strerror(errno));
|
||||
rc = -EIO;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
enum exfat_mode exfat_get_mode(const struct exfat_dev* dev)
|
||||
{
|
||||
return dev->mode;
|
||||
}
|
||||
|
||||
|
||||
off_t exfat_get_size(const struct exfat_dev* dev)
|
||||
{
|
||||
return dev->size;
|
||||
}
|
||||
|
||||
off_t exfat_seek(struct exfat_dev* dev, off_t offset, int whence)
|
||||
{
|
||||
#ifdef USE_UBLIO
|
||||
/* XXX SEEK_CUR will be handled incorrectly */
|
||||
return dev->pos = lseek(dev->fd, offset, whence);
|
||||
#else
|
||||
|
||||
if (SEEK_SET == whence)
|
||||
{
|
||||
if (offset > g_vtoy_exfat_part_size)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
lseek(dev->fd, 512 * 2048 + offset, SEEK_SET);
|
||||
return offset;
|
||||
}
|
||||
else if (SEEK_END == whence)
|
||||
{
|
||||
if (offset == 0)
|
||||
{
|
||||
offset = 512 * 2048 + g_vtoy_exfat_part_size;
|
||||
lseek(dev->fd, offset, SEEK_SET);
|
||||
return (off_t)g_vtoy_exfat_part_size;
|
||||
}
|
||||
else
|
||||
{
|
||||
exfat_error("Invalid SEEK_END offset %llu", (unsigned long long)offset);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
exfat_error("Invalid seek whence %d", whence);
|
||||
return lseek(dev->fd, offset, whence);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
ssize_t exfat_read(struct exfat_dev* dev, void* buffer, size_t size)
|
||||
{
|
||||
#ifdef USE_UBLIO
|
||||
ssize_t result = ublio_pread(dev->ufh, buffer, size, dev->pos);
|
||||
if (result >= 0)
|
||||
dev->pos += size;
|
||||
return result;
|
||||
#else
|
||||
return read(dev->fd, buffer, size);
|
||||
#endif
|
||||
}
|
||||
|
||||
ssize_t exfat_write(struct exfat_dev* dev, const void* buffer, size_t size)
|
||||
{
|
||||
#ifdef USE_UBLIO
|
||||
ssize_t result = ublio_pwrite(dev->ufh, buffer, size, dev->pos);
|
||||
if (result >= 0)
|
||||
dev->pos += size;
|
||||
return result;
|
||||
#else
|
||||
return write(dev->fd, buffer, size);
|
||||
#endif
|
||||
}
|
||||
|
||||
ssize_t exfat_pread(struct exfat_dev* dev, void* buffer, size_t size,
|
||||
off_t offset)
|
||||
{
|
||||
#ifdef USE_UBLIO
|
||||
return ublio_pread(dev->ufh, buffer, size, offset);
|
||||
#else
|
||||
return pread(dev->fd, buffer, size, offset);
|
||||
#endif
|
||||
}
|
||||
|
||||
ssize_t exfat_pwrite(struct exfat_dev* dev, const void* buffer, size_t size,
|
||||
off_t offset)
|
||||
{
|
||||
#ifdef USE_UBLIO
|
||||
return ublio_pwrite(dev->ufh, buffer, size, offset);
|
||||
#else
|
||||
return pwrite(dev->fd, buffer, size, offset);
|
||||
#endif
|
||||
}
|
||||
|
||||
ssize_t exfat_generic_pread(const struct exfat* ef, struct exfat_node* node,
|
||||
void* buffer, size_t size, off_t offset)
|
||||
{
|
||||
cluster_t cluster;
|
||||
char* bufp = buffer;
|
||||
off_t lsize, loffset, remainder;
|
||||
|
||||
if (offset >= node->size)
|
||||
return 0;
|
||||
if (size == 0)
|
||||
return 0;
|
||||
|
||||
cluster = exfat_advance_cluster(ef, node, offset / CLUSTER_SIZE(*ef->sb));
|
||||
if (CLUSTER_INVALID(*ef->sb, cluster))
|
||||
{
|
||||
exfat_error("invalid cluster 0x%x while reading", cluster);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
loffset = offset % CLUSTER_SIZE(*ef->sb);
|
||||
remainder = MIN(size, node->size - offset);
|
||||
while (remainder > 0)
|
||||
{
|
||||
if (CLUSTER_INVALID(*ef->sb, cluster))
|
||||
{
|
||||
exfat_error("invalid cluster 0x%x while reading", cluster);
|
||||
return -EIO;
|
||||
}
|
||||
lsize = MIN(CLUSTER_SIZE(*ef->sb) - loffset, remainder);
|
||||
if (exfat_pread(ef->dev, bufp, lsize,
|
||||
exfat_c2o(ef, cluster) + loffset) < 0)
|
||||
{
|
||||
exfat_error("failed to read cluster %#x", cluster);
|
||||
return -EIO;
|
||||
}
|
||||
bufp += lsize;
|
||||
loffset = 0;
|
||||
remainder -= lsize;
|
||||
cluster = exfat_next_cluster(ef, node, cluster);
|
||||
}
|
||||
if (!(node->attrib & EXFAT_ATTRIB_DIR) && !ef->ro && !ef->noatime)
|
||||
exfat_update_atime(node);
|
||||
return MIN(size, node->size - offset) - remainder;
|
||||
}
|
||||
|
||||
ssize_t exfat_generic_pwrite(struct exfat* ef, struct exfat_node* node,
|
||||
const void* buffer, size_t size, off_t offset)
|
||||
{
|
||||
int rc;
|
||||
cluster_t cluster;
|
||||
const char* bufp = buffer;
|
||||
off_t lsize, loffset, remainder;
|
||||
|
||||
if (offset > node->size)
|
||||
{
|
||||
rc = exfat_truncate(ef, node, offset, true);
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
}
|
||||
if (offset + size > node->size)
|
||||
{
|
||||
rc = exfat_truncate(ef, node, offset + size, false);
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
}
|
||||
if (size == 0)
|
||||
return 0;
|
||||
|
||||
cluster = exfat_advance_cluster(ef, node, offset / CLUSTER_SIZE(*ef->sb));
|
||||
if (CLUSTER_INVALID(*ef->sb, cluster))
|
||||
{
|
||||
exfat_error("invalid cluster 0x%x while writing", cluster);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
loffset = offset % CLUSTER_SIZE(*ef->sb);
|
||||
remainder = size;
|
||||
while (remainder > 0)
|
||||
{
|
||||
if (CLUSTER_INVALID(*ef->sb, cluster))
|
||||
{
|
||||
exfat_error("invalid cluster 0x%x while writing", cluster);
|
||||
return -EIO;
|
||||
}
|
||||
lsize = MIN(CLUSTER_SIZE(*ef->sb) - loffset, remainder);
|
||||
if (exfat_pwrite(ef->dev, bufp, lsize,
|
||||
exfat_c2o(ef, cluster) + loffset) < 0)
|
||||
{
|
||||
exfat_error("failed to write cluster %#x", cluster);
|
||||
return -EIO;
|
||||
}
|
||||
bufp += lsize;
|
||||
loffset = 0;
|
||||
remainder -= lsize;
|
||||
cluster = exfat_next_cluster(ef, node, cluster);
|
||||
}
|
||||
if (!(node->attrib & EXFAT_ATTRIB_DIR))
|
||||
/* directory's mtime should be updated by the caller only when it
|
||||
creates or removes something in this directory */
|
||||
exfat_update_mtime(node);
|
||||
return size - remainder;
|
||||
}
|
||||
224
LinuxGUI/Ventoy2Disk/Lib/exfat/src/libexfat/lookup.c
Normal file
224
LinuxGUI/Ventoy2Disk/Lib/exfat/src/libexfat/lookup.c
Normal file
@@ -0,0 +1,224 @@
|
||||
/*
|
||||
lookup.c (02.09.09)
|
||||
exFAT file system implementation library.
|
||||
|
||||
Free exFAT implementation.
|
||||
Copyright (C) 2010-2018 Andrew Nayenko
|
||||
|
||||
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.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "exfat.h"
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
int exfat_opendir(struct exfat* ef, struct exfat_node* dir,
|
||||
struct exfat_iterator* it)
|
||||
{
|
||||
int rc;
|
||||
|
||||
exfat_get_node(dir);
|
||||
it->parent = dir;
|
||||
it->current = NULL;
|
||||
rc = exfat_cache_directory(ef, dir);
|
||||
if (rc != 0)
|
||||
exfat_put_node(ef, dir);
|
||||
return rc;
|
||||
}
|
||||
|
||||
void exfat_closedir(struct exfat* ef, struct exfat_iterator* it)
|
||||
{
|
||||
exfat_put_node(ef, it->parent);
|
||||
it->parent = NULL;
|
||||
it->current = NULL;
|
||||
}
|
||||
|
||||
struct exfat_node* exfat_readdir(struct exfat_iterator* it)
|
||||
{
|
||||
if (it->current == NULL)
|
||||
it->current = it->parent->child;
|
||||
else
|
||||
it->current = it->current->next;
|
||||
|
||||
if (it->current != NULL)
|
||||
return exfat_get_node(it->current);
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int compare_char(struct exfat* ef, uint16_t a, uint16_t b)
|
||||
{
|
||||
return (int) ef->upcase[a] - (int) ef->upcase[b];
|
||||
}
|
||||
|
||||
static int compare_name(struct exfat* ef, const le16_t* a, const le16_t* b)
|
||||
{
|
||||
while (le16_to_cpu(*a) && le16_to_cpu(*b))
|
||||
{
|
||||
int rc = compare_char(ef, le16_to_cpu(*a), le16_to_cpu(*b));
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
a++;
|
||||
b++;
|
||||
}
|
||||
return compare_char(ef, le16_to_cpu(*a), le16_to_cpu(*b));
|
||||
}
|
||||
|
||||
static int lookup_name(struct exfat* ef, struct exfat_node* parent,
|
||||
struct exfat_node** node, const char* name, size_t n)
|
||||
{
|
||||
struct exfat_iterator it;
|
||||
le16_t buffer[EXFAT_NAME_MAX + 1];
|
||||
int rc;
|
||||
|
||||
*node = NULL;
|
||||
|
||||
rc = utf8_to_utf16(buffer, name, EXFAT_NAME_MAX + 1, n);
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
|
||||
rc = exfat_opendir(ef, parent, &it);
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
while ((*node = exfat_readdir(&it)))
|
||||
{
|
||||
if (compare_name(ef, buffer, (*node)->name) == 0)
|
||||
{
|
||||
exfat_closedir(ef, &it);
|
||||
return 0;
|
||||
}
|
||||
exfat_put_node(ef, *node);
|
||||
}
|
||||
exfat_closedir(ef, &it);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
static size_t get_comp(const char* path, const char** comp)
|
||||
{
|
||||
const char* end;
|
||||
|
||||
*comp = path + strspn(path, "/"); /* skip leading slashes */
|
||||
end = strchr(*comp, '/');
|
||||
if (end == NULL)
|
||||
return strlen(*comp);
|
||||
else
|
||||
return end - *comp;
|
||||
}
|
||||
|
||||
int exfat_lookup(struct exfat* ef, struct exfat_node** node,
|
||||
const char* path)
|
||||
{
|
||||
struct exfat_node* parent;
|
||||
const char* p;
|
||||
size_t n;
|
||||
int rc;
|
||||
|
||||
/* start from the root directory */
|
||||
parent = *node = exfat_get_node(ef->root);
|
||||
for (p = path; (n = get_comp(p, &p)); p += n)
|
||||
{
|
||||
if (n == 1 && *p == '.') /* skip "." component */
|
||||
continue;
|
||||
rc = lookup_name(ef, parent, node, p, n);
|
||||
if (rc != 0)
|
||||
{
|
||||
exfat_put_node(ef, parent);
|
||||
return rc;
|
||||
}
|
||||
exfat_put_node(ef, parent);
|
||||
parent = *node;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool is_last_comp(const char* comp, size_t length)
|
||||
{
|
||||
const char* p = comp + length;
|
||||
|
||||
return get_comp(p, &p) == 0;
|
||||
}
|
||||
|
||||
static bool is_allowed(const char* comp, size_t length)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < length; i++)
|
||||
switch (comp[i])
|
||||
{
|
||||
case 0x01 ... 0x1f:
|
||||
case '/':
|
||||
case '\\':
|
||||
case ':':
|
||||
case '*':
|
||||
case '?':
|
||||
case '"':
|
||||
case '<':
|
||||
case '>':
|
||||
case '|':
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int exfat_split(struct exfat* ef, struct exfat_node** parent,
|
||||
struct exfat_node** node, le16_t* name, const char* path)
|
||||
{
|
||||
const char* p;
|
||||
size_t n;
|
||||
int rc;
|
||||
|
||||
memset(name, 0, (EXFAT_NAME_MAX + 1) * sizeof(le16_t));
|
||||
*parent = *node = exfat_get_node(ef->root);
|
||||
for (p = path; (n = get_comp(p, &p)); p += n)
|
||||
{
|
||||
if (n == 1 && *p == '.')
|
||||
continue;
|
||||
if (is_last_comp(p, n))
|
||||
{
|
||||
if (!is_allowed(p, n))
|
||||
{
|
||||
/* contains characters that are not allowed */
|
||||
exfat_put_node(ef, *parent);
|
||||
return -ENOENT;
|
||||
}
|
||||
rc = utf8_to_utf16(name, p, EXFAT_NAME_MAX + 1, n);
|
||||
if (rc != 0)
|
||||
{
|
||||
exfat_put_node(ef, *parent);
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = lookup_name(ef, *parent, node, p, n);
|
||||
if (rc != 0 && rc != -ENOENT)
|
||||
{
|
||||
exfat_put_node(ef, *parent);
|
||||
return rc;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
rc = lookup_name(ef, *parent, node, p, n);
|
||||
if (rc != 0)
|
||||
{
|
||||
exfat_put_node(ef, *parent);
|
||||
return rc;
|
||||
}
|
||||
exfat_put_node(ef, *parent);
|
||||
*parent = *node;
|
||||
}
|
||||
exfat_bug("impossible");
|
||||
|
||||
return 1;
|
||||
}
|
||||
389
LinuxGUI/Ventoy2Disk/Lib/exfat/src/libexfat/mount.c
Normal file
389
LinuxGUI/Ventoy2Disk/Lib/exfat/src/libexfat/mount.c
Normal file
@@ -0,0 +1,389 @@
|
||||
/*
|
||||
mount.c (22.10.09)
|
||||
exFAT file system implementation library.
|
||||
|
||||
Free exFAT implementation.
|
||||
Copyright (C) 2010-2018 Andrew Nayenko
|
||||
|
||||
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.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "exfat.h"
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <inttypes.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
static uint64_t rootdir_size(const struct exfat* ef)
|
||||
{
|
||||
uint32_t clusters = 0;
|
||||
uint32_t clusters_max = le32_to_cpu(ef->sb->cluster_count);
|
||||
cluster_t rootdir_cluster = le32_to_cpu(ef->sb->rootdir_cluster);
|
||||
|
||||
/* Iterate all clusters of the root directory to calculate its size.
|
||||
It can't be contiguous because there is no flag to indicate this. */
|
||||
do
|
||||
{
|
||||
if (clusters == clusters_max) /* infinite loop detected */
|
||||
{
|
||||
exfat_error("root directory cannot occupy all %d clusters",
|
||||
clusters);
|
||||
return 0;
|
||||
}
|
||||
if (CLUSTER_INVALID(*ef->sb, rootdir_cluster))
|
||||
{
|
||||
exfat_error("bad cluster %#x while reading root directory",
|
||||
rootdir_cluster);
|
||||
return 0;
|
||||
}
|
||||
rootdir_cluster = exfat_next_cluster(ef, ef->root, rootdir_cluster);
|
||||
clusters++;
|
||||
}
|
||||
while (rootdir_cluster != EXFAT_CLUSTER_END);
|
||||
|
||||
return (uint64_t) clusters * CLUSTER_SIZE(*ef->sb);
|
||||
}
|
||||
|
||||
static const char* get_option(const char* options, const char* option_name)
|
||||
{
|
||||
const char* p;
|
||||
size_t length = strlen(option_name);
|
||||
|
||||
for (p = strstr(options, option_name); p; p = strstr(p + 1, option_name))
|
||||
if ((p == options || p[-1] == ',') && p[length] == '=')
|
||||
return p + length + 1;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int get_int_option(const char* options, const char* option_name,
|
||||
int base, int default_value)
|
||||
{
|
||||
const char* p = get_option(options, option_name);
|
||||
|
||||
if (p == NULL)
|
||||
return default_value;
|
||||
return strtol(p, NULL, base);
|
||||
}
|
||||
|
||||
static bool match_option(const char* options, const char* option_name)
|
||||
{
|
||||
const char* p;
|
||||
size_t length = strlen(option_name);
|
||||
|
||||
for (p = strstr(options, option_name); p; p = strstr(p + 1, option_name))
|
||||
if ((p == options || p[-1] == ',') &&
|
||||
(p[length] == ',' || p[length] == '\0'))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
static void parse_options(struct exfat* ef, const char* options)
|
||||
{
|
||||
int opt_umask;
|
||||
|
||||
opt_umask = get_int_option(options, "umask", 8, 0);
|
||||
ef->dmask = get_int_option(options, "dmask", 8, opt_umask);
|
||||
ef->fmask = get_int_option(options, "fmask", 8, opt_umask);
|
||||
|
||||
ef->uid = get_int_option(options, "uid", 10, geteuid());
|
||||
ef->gid = get_int_option(options, "gid", 10, getegid());
|
||||
|
||||
ef->noatime = match_option(options, "noatime");
|
||||
|
||||
switch (get_int_option(options, "repair", 10, 0))
|
||||
{
|
||||
case 1:
|
||||
ef->repair = EXFAT_REPAIR_ASK;
|
||||
break;
|
||||
case 2:
|
||||
ef->repair = EXFAT_REPAIR_YES;
|
||||
break;
|
||||
default:
|
||||
ef->repair = EXFAT_REPAIR_NO;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static bool verify_vbr_checksum(const struct exfat* ef, void* sector)
|
||||
{
|
||||
off_t sector_size = SECTOR_SIZE(*ef->sb);
|
||||
uint32_t vbr_checksum;
|
||||
int i;
|
||||
|
||||
if (exfat_pread(ef->dev, sector, sector_size, 0) < 0)
|
||||
{
|
||||
exfat_error("failed to read boot sector");
|
||||
return false;
|
||||
}
|
||||
vbr_checksum = exfat_vbr_start_checksum(sector, sector_size);
|
||||
for (i = 1; i < 11; i++)
|
||||
{
|
||||
if (exfat_pread(ef->dev, sector, sector_size, i * sector_size) < 0)
|
||||
{
|
||||
exfat_error("failed to read VBR sector");
|
||||
return false;
|
||||
}
|
||||
vbr_checksum = exfat_vbr_add_checksum(sector, sector_size,
|
||||
vbr_checksum);
|
||||
}
|
||||
if (exfat_pread(ef->dev, sector, sector_size, i * sector_size) < 0)
|
||||
{
|
||||
exfat_error("failed to read VBR checksum sector");
|
||||
return false;
|
||||
}
|
||||
for (i = 0; i < sector_size / sizeof(vbr_checksum); i++)
|
||||
if (le32_to_cpu(((const le32_t*) sector)[i]) != vbr_checksum)
|
||||
{
|
||||
exfat_error("invalid VBR checksum 0x%x (expected 0x%x)",
|
||||
le32_to_cpu(((const le32_t*) sector)[i]), vbr_checksum);
|
||||
if (!EXFAT_REPAIR(invalid_vbr_checksum, ef, sector, vbr_checksum))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static int commit_super_block(const struct exfat* ef)
|
||||
{
|
||||
if (exfat_pwrite(ef->dev, ef->sb, sizeof(struct exfat_super_block), 0) < 0)
|
||||
{
|
||||
exfat_error("failed to write super block");
|
||||
return 1;
|
||||
}
|
||||
return exfat_fsync(ef->dev);
|
||||
}
|
||||
|
||||
static int prepare_super_block(const struct exfat* ef)
|
||||
{
|
||||
if (le16_to_cpu(ef->sb->volume_state) & EXFAT_STATE_MOUNTED)
|
||||
exfat_warn("volume was not unmounted cleanly");
|
||||
|
||||
if (ef->ro)
|
||||
return 0;
|
||||
|
||||
ef->sb->volume_state = cpu_to_le16(
|
||||
le16_to_cpu(ef->sb->volume_state) | EXFAT_STATE_MOUNTED);
|
||||
return commit_super_block(ef);
|
||||
}
|
||||
|
||||
static void exfat_free(struct exfat* ef)
|
||||
{
|
||||
exfat_close(ef->dev); /* first of all, close the descriptor */
|
||||
ef->dev = NULL; /* struct exfat_dev is freed by exfat_close() */
|
||||
free(ef->root);
|
||||
ef->root = NULL;
|
||||
free(ef->zero_cluster);
|
||||
ef->zero_cluster = NULL;
|
||||
free(ef->cmap.chunk);
|
||||
ef->cmap.chunk = NULL;
|
||||
free(ef->upcase);
|
||||
ef->upcase = NULL;
|
||||
free(ef->sb);
|
||||
ef->sb = NULL;
|
||||
}
|
||||
|
||||
int exfat_mount(struct exfat* ef, const char* spec, const char* options)
|
||||
{
|
||||
int rc;
|
||||
enum exfat_mode mode;
|
||||
|
||||
exfat_tzset();
|
||||
memset(ef, 0, sizeof(struct exfat));
|
||||
|
||||
parse_options(ef, options);
|
||||
|
||||
if (match_option(options, "ro"))
|
||||
mode = EXFAT_MODE_RO;
|
||||
else if (match_option(options, "ro_fallback"))
|
||||
mode = EXFAT_MODE_ANY;
|
||||
else
|
||||
mode = EXFAT_MODE_RW;
|
||||
ef->dev = exfat_open(spec, mode);
|
||||
if (ef->dev == NULL)
|
||||
return -EIO;
|
||||
if (exfat_get_mode(ef->dev) == EXFAT_MODE_RO)
|
||||
{
|
||||
if (mode == EXFAT_MODE_ANY)
|
||||
ef->ro = -1;
|
||||
else
|
||||
ef->ro = 1;
|
||||
}
|
||||
|
||||
ef->sb = malloc(sizeof(struct exfat_super_block));
|
||||
if (ef->sb == NULL)
|
||||
{
|
||||
exfat_error("failed to allocate memory for the super block");
|
||||
exfat_free(ef);
|
||||
return -ENOMEM;
|
||||
}
|
||||
memset(ef->sb, 0, sizeof(struct exfat_super_block));
|
||||
|
||||
if (exfat_pread(ef->dev, ef->sb, sizeof(struct exfat_super_block), 0) < 0)
|
||||
{
|
||||
exfat_error("failed to read boot sector");
|
||||
exfat_free(ef);
|
||||
return -EIO;
|
||||
}
|
||||
if (memcmp(ef->sb->oem_name, "EXFAT ", 8) != 0)
|
||||
{
|
||||
exfat_error("exFAT file system is not found");
|
||||
exfat_free(ef);
|
||||
return -EIO;
|
||||
}
|
||||
/* sector cannot be smaller than 512 bytes */
|
||||
if (ef->sb->sector_bits < 9)
|
||||
{
|
||||
exfat_error("too small sector size: 2^%hhd", ef->sb->sector_bits);
|
||||
exfat_free(ef);
|
||||
return -EIO;
|
||||
}
|
||||
/* officially exFAT supports cluster size up to 32 MB */
|
||||
if ((int) ef->sb->sector_bits + (int) ef->sb->spc_bits > 25)
|
||||
{
|
||||
exfat_error("too big cluster size: 2^(%hhd+%hhd)",
|
||||
ef->sb->sector_bits, ef->sb->spc_bits);
|
||||
exfat_free(ef);
|
||||
return -EIO;
|
||||
}
|
||||
ef->zero_cluster = malloc(CLUSTER_SIZE(*ef->sb));
|
||||
if (ef->zero_cluster == NULL)
|
||||
{
|
||||
exfat_error("failed to allocate zero sector");
|
||||
exfat_free(ef);
|
||||
return -ENOMEM;
|
||||
}
|
||||
/* use zero_cluster as a temporary buffer for VBR checksum verification */
|
||||
if (!verify_vbr_checksum(ef, ef->zero_cluster))
|
||||
{
|
||||
exfat_free(ef);
|
||||
return -EIO;
|
||||
}
|
||||
memset(ef->zero_cluster, 0, CLUSTER_SIZE(*ef->sb));
|
||||
if (ef->sb->version.major != 1 || ef->sb->version.minor != 0)
|
||||
{
|
||||
exfat_error("unsupported exFAT version: %hhu.%hhu",
|
||||
ef->sb->version.major, ef->sb->version.minor);
|
||||
exfat_free(ef);
|
||||
return -EIO;
|
||||
}
|
||||
if (ef->sb->fat_count != 1)
|
||||
{
|
||||
exfat_error("unsupported FAT count: %hhu", ef->sb->fat_count);
|
||||
exfat_free(ef);
|
||||
return -EIO;
|
||||
}
|
||||
if (le64_to_cpu(ef->sb->sector_count) * SECTOR_SIZE(*ef->sb) >
|
||||
exfat_get_size(ef->dev))
|
||||
{
|
||||
/* this can cause I/O errors later but we don't fail mounting to let
|
||||
user rescue data */
|
||||
exfat_warn("file system in sectors is larger than device: "
|
||||
"%"PRIu64" * %d > %"PRIu64,
|
||||
le64_to_cpu(ef->sb->sector_count), SECTOR_SIZE(*ef->sb),
|
||||
exfat_get_size(ef->dev));
|
||||
}
|
||||
if ((off_t) le32_to_cpu(ef->sb->cluster_count) * CLUSTER_SIZE(*ef->sb) >
|
||||
exfat_get_size(ef->dev))
|
||||
{
|
||||
exfat_error("file system in clusters is larger than device: "
|
||||
"%u * %d > %"PRIu64,
|
||||
le32_to_cpu(ef->sb->cluster_count), CLUSTER_SIZE(*ef->sb),
|
||||
exfat_get_size(ef->dev));
|
||||
exfat_free(ef);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
ef->root = malloc(sizeof(struct exfat_node));
|
||||
if (ef->root == NULL)
|
||||
{
|
||||
exfat_error("failed to allocate root node");
|
||||
exfat_free(ef);
|
||||
return -ENOMEM;
|
||||
}
|
||||
memset(ef->root, 0, sizeof(struct exfat_node));
|
||||
ef->root->attrib = EXFAT_ATTRIB_DIR;
|
||||
ef->root->start_cluster = le32_to_cpu(ef->sb->rootdir_cluster);
|
||||
ef->root->fptr_cluster = ef->root->start_cluster;
|
||||
ef->root->name[0] = cpu_to_le16('\0');
|
||||
ef->root->size = rootdir_size(ef);
|
||||
if (ef->root->size == 0)
|
||||
{
|
||||
exfat_free(ef);
|
||||
return -EIO;
|
||||
}
|
||||
/* exFAT does not have time attributes for the root directory */
|
||||
ef->root->mtime = 0;
|
||||
ef->root->atime = 0;
|
||||
/* always keep at least 1 reference to the root node */
|
||||
exfat_get_node(ef->root);
|
||||
|
||||
rc = exfat_cache_directory(ef, ef->root);
|
||||
if (rc != 0)
|
||||
goto error;
|
||||
if (ef->upcase == NULL)
|
||||
{
|
||||
exfat_error("upcase table is not found");
|
||||
goto error;
|
||||
}
|
||||
if (ef->cmap.chunk == NULL)
|
||||
{
|
||||
exfat_error("clusters bitmap is not found");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (prepare_super_block(ef) != 0)
|
||||
goto error;
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
exfat_put_node(ef, ef->root);
|
||||
exfat_reset_cache(ef);
|
||||
exfat_free(ef);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
static void finalize_super_block(struct exfat* ef)
|
||||
{
|
||||
if (ef->ro)
|
||||
return;
|
||||
|
||||
ef->sb->volume_state = cpu_to_le16(
|
||||
le16_to_cpu(ef->sb->volume_state) & ~EXFAT_STATE_MOUNTED);
|
||||
|
||||
/* Some implementations set the percentage of allocated space to 0xff
|
||||
on FS creation and never update it. In this case leave it as is. */
|
||||
if (ef->sb->allocated_percent != 0xff)
|
||||
{
|
||||
uint32_t free, total;
|
||||
|
||||
free = exfat_count_free_clusters(ef);
|
||||
total = le32_to_cpu(ef->sb->cluster_count);
|
||||
ef->sb->allocated_percent = ((total - free) * 100 + total / 2) / total;
|
||||
}
|
||||
|
||||
commit_super_block(ef); /* ignore return code */
|
||||
}
|
||||
|
||||
void exfat_unmount(struct exfat* ef)
|
||||
{
|
||||
exfat_flush_nodes(ef); /* ignore return code */
|
||||
exfat_flush(ef); /* ignore return code */
|
||||
exfat_put_node(ef, ef->root);
|
||||
exfat_reset_cache(ef);
|
||||
finalize_super_block(ef);
|
||||
exfat_free(ef); /* will close the descriptor */
|
||||
}
|
||||
1226
LinuxGUI/Ventoy2Disk/Lib/exfat/src/libexfat/node.c
Normal file
1226
LinuxGUI/Ventoy2Disk/Lib/exfat/src/libexfat/node.c
Normal file
File diff suppressed because it is too large
Load Diff
63
LinuxGUI/Ventoy2Disk/Lib/exfat/src/libexfat/platform.h
Normal file
63
LinuxGUI/Ventoy2Disk/Lib/exfat/src/libexfat/platform.h
Normal file
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
platform.h (14.05.13)
|
||||
OS-specific code (libc-specific in fact). Note that systems with the
|
||||
same kernel can use different libc implementations.
|
||||
|
||||
Free exFAT implementation.
|
||||
Copyright (C) 2010-2018 Andrew Nayenko
|
||||
|
||||
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.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef PLATFORM_H_INCLUDED
|
||||
#define PLATFORM_H_INCLUDED
|
||||
|
||||
#if defined(__linux__) || defined(__GLIBC__) || defined(__GNU__)
|
||||
|
||||
#include <endian.h>
|
||||
#include <byteswap.h>
|
||||
#define exfat_bswap16(x) bswap_16(x)
|
||||
#define exfat_bswap32(x) bswap_32(x)
|
||||
#define exfat_bswap64(x) bswap_64(x)
|
||||
#define EXFAT_BYTE_ORDER __BYTE_ORDER
|
||||
#define EXFAT_LITTLE_ENDIAN __LITTLE_ENDIAN
|
||||
#define EXFAT_BIG_ENDIAN __BIG_ENDIAN
|
||||
|
||||
#elif defined(__APPLE__)
|
||||
|
||||
#include <machine/endian.h>
|
||||
#include <libkern/OSByteOrder.h>
|
||||
#define exfat_bswap16(x) OSSwapInt16(x)
|
||||
#define exfat_bswap32(x) OSSwapInt32(x)
|
||||
#define exfat_bswap64(x) OSSwapInt64(x)
|
||||
#define EXFAT_BYTE_ORDER BYTE_ORDER
|
||||
#define EXFAT_LITTLE_ENDIAN LITTLE_ENDIAN
|
||||
#define EXFAT_BIG_ENDIAN BIG_ENDIAN
|
||||
|
||||
#elif defined(__FreeBSD__) || defined(__DragonFly__) || defined(__NetBSD__) || defined(__OpenBSD__)
|
||||
|
||||
#include <sys/endian.h>
|
||||
#define exfat_bswap16(x) bswap16(x)
|
||||
#define exfat_bswap32(x) bswap32(x)
|
||||
#define exfat_bswap64(x) bswap64(x)
|
||||
#define EXFAT_BYTE_ORDER _BYTE_ORDER
|
||||
#define EXFAT_LITTLE_ENDIAN _LITTLE_ENDIAN
|
||||
#define EXFAT_BIG_ENDIAN _BIG_ENDIAN
|
||||
|
||||
#else
|
||||
#error Unknown platform
|
||||
#endif
|
||||
|
||||
#endif /* ifndef PLATFORM_H_INCLUDED */
|
||||
103
LinuxGUI/Ventoy2Disk/Lib/exfat/src/libexfat/repair.c
Normal file
103
LinuxGUI/Ventoy2Disk/Lib/exfat/src/libexfat/repair.c
Normal file
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
repair.c (09.03.17)
|
||||
exFAT file system implementation library.
|
||||
|
||||
Free exFAT implementation.
|
||||
Copyright (C) 2010-2018 Andrew Nayenko
|
||||
|
||||
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.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "exfat.h"
|
||||
#include <strings.h>
|
||||
|
||||
int exfat_errors_fixed;
|
||||
|
||||
bool exfat_ask_to_fix(const struct exfat* ef)
|
||||
{
|
||||
const char* question = "Fix (Y/N)?";
|
||||
char answer[8];
|
||||
bool yeah, nope;
|
||||
|
||||
switch (ef->repair)
|
||||
{
|
||||
case EXFAT_REPAIR_NO:
|
||||
return false;
|
||||
case EXFAT_REPAIR_YES:
|
||||
printf("%s %s", question, "Y\n");
|
||||
return true;
|
||||
case EXFAT_REPAIR_ASK:
|
||||
do
|
||||
{
|
||||
printf("%s ", question);
|
||||
fflush(stdout);
|
||||
if (fgets(answer, sizeof(answer), stdin))
|
||||
{
|
||||
yeah = strcasecmp(answer, "Y\n") == 0;
|
||||
nope = strcasecmp(answer, "N\n") == 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
yeah = false;
|
||||
nope = true;
|
||||
}
|
||||
}
|
||||
while (!yeah && !nope);
|
||||
return yeah;
|
||||
}
|
||||
exfat_bug("invalid repair option value: %d", ef->repair);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool exfat_fix_invalid_vbr_checksum(const struct exfat* ef, void* sector,
|
||||
uint32_t vbr_checksum)
|
||||
{
|
||||
size_t i;
|
||||
off_t sector_size = SECTOR_SIZE(*ef->sb);
|
||||
|
||||
for (i = 0; i < sector_size / sizeof(vbr_checksum); i++)
|
||||
((le32_t*) sector)[i] = cpu_to_le32(vbr_checksum);
|
||||
if (exfat_pwrite(ef->dev, sector, sector_size, 11 * sector_size) < 0)
|
||||
{
|
||||
exfat_error("failed to write correct VBR checksum");
|
||||
return false;
|
||||
}
|
||||
exfat_errors_fixed++;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool exfat_fix_invalid_node_checksum(const struct exfat* ef,
|
||||
struct exfat_node* node)
|
||||
{
|
||||
/* checksum will be rewritten by exfat_flush_node() */
|
||||
node->is_dirty = true;
|
||||
|
||||
exfat_errors_fixed++;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool exfat_fix_unknown_entry(struct exfat* ef, struct exfat_node* dir,
|
||||
const struct exfat_entry* entry, off_t offset)
|
||||
{
|
||||
struct exfat_entry deleted = *entry;
|
||||
|
||||
deleted.type &= ~EXFAT_ENTRY_VALID;
|
||||
if (exfat_generic_pwrite(ef, dir, &deleted, sizeof(struct exfat_entry),
|
||||
offset) != sizeof(struct exfat_entry))
|
||||
return false;
|
||||
|
||||
exfat_errors_fixed++;
|
||||
return true;
|
||||
}
|
||||
164
LinuxGUI/Ventoy2Disk/Lib/exfat/src/libexfat/time.c
Normal file
164
LinuxGUI/Ventoy2Disk/Lib/exfat/src/libexfat/time.c
Normal file
@@ -0,0 +1,164 @@
|
||||
/*
|
||||
time.c (03.02.12)
|
||||
exFAT file system implementation library.
|
||||
|
||||
Free exFAT implementation.
|
||||
Copyright (C) 2010-2018 Andrew Nayenko
|
||||
|
||||
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.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "exfat.h"
|
||||
|
||||
/* timezone offset from UTC in seconds; positive for western timezones,
|
||||
negative for eastern ones */
|
||||
static long exfat_timezone;
|
||||
|
||||
#define SEC_IN_MIN 60ll
|
||||
#define SEC_IN_HOUR (60 * SEC_IN_MIN)
|
||||
#define SEC_IN_DAY (24 * SEC_IN_HOUR)
|
||||
#define SEC_IN_YEAR (365 * SEC_IN_DAY) /* not leap year */
|
||||
/* Unix epoch started at 0:00:00 UTC 1 January 1970 */
|
||||
#define UNIX_EPOCH_YEAR 1970
|
||||
/* exFAT epoch started at 0:00:00 UTC 1 January 1980 */
|
||||
#define EXFAT_EPOCH_YEAR 1980
|
||||
/* number of years from Unix epoch to exFAT epoch */
|
||||
#define EPOCH_DIFF_YEAR (EXFAT_EPOCH_YEAR - UNIX_EPOCH_YEAR)
|
||||
/* number of days from Unix epoch to exFAT epoch (considering leap days) */
|
||||
#define EPOCH_DIFF_DAYS (EPOCH_DIFF_YEAR * 365 + EPOCH_DIFF_YEAR / 4)
|
||||
/* number of seconds from Unix epoch to exFAT epoch (considering leap days) */
|
||||
#define EPOCH_DIFF_SEC (EPOCH_DIFF_DAYS * SEC_IN_DAY)
|
||||
/* number of leap years passed from exFAT epoch to the specified year
|
||||
(excluding the specified year itself) */
|
||||
#define LEAP_YEARS(year) ((EXFAT_EPOCH_YEAR + (year) - 1) / 4 \
|
||||
- (EXFAT_EPOCH_YEAR - 1) / 4)
|
||||
/* checks whether the specified year is leap */
|
||||
#define IS_LEAP_YEAR(year) ((EXFAT_EPOCH_YEAR + (year)) % 4 == 0)
|
||||
|
||||
static const time_t days_in_year[] =
|
||||
{
|
||||
/* Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec */
|
||||
0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334
|
||||
};
|
||||
|
||||
time_t exfat_exfat2unix(le16_t date, le16_t time, uint8_t centisec)
|
||||
{
|
||||
time_t unix_time = EPOCH_DIFF_SEC;
|
||||
uint16_t ndate = le16_to_cpu(date);
|
||||
uint16_t ntime = le16_to_cpu(time);
|
||||
|
||||
uint16_t day = ndate & 0x1f; /* 5 bits, 1-31 */
|
||||
uint16_t month = ndate >> 5 & 0xf; /* 4 bits, 1-12 */
|
||||
uint16_t year = ndate >> 9; /* 7 bits, 1-127 (+1980) */
|
||||
|
||||
uint16_t twosec = ntime & 0x1f; /* 5 bits, 0-29 (2 sec granularity) */
|
||||
uint16_t min = ntime >> 5 & 0x3f; /* 6 bits, 0-59 */
|
||||
uint16_t hour = ntime >> 11; /* 5 bits, 0-23 */
|
||||
|
||||
if (day == 0 || month == 0 || month > 12)
|
||||
{
|
||||
exfat_error("bad date %u-%02hu-%02hu",
|
||||
year + EXFAT_EPOCH_YEAR, month, day);
|
||||
return 0;
|
||||
}
|
||||
if (hour > 23 || min > 59 || twosec > 29)
|
||||
{
|
||||
exfat_error("bad time %hu:%02hu:%02u",
|
||||
hour, min, twosec * 2);
|
||||
return 0;
|
||||
}
|
||||
if (centisec > 199)
|
||||
{
|
||||
exfat_error("bad centiseconds count %hhu", centisec);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* every 4th year between 1904 and 2096 is leap */
|
||||
unix_time += year * SEC_IN_YEAR + LEAP_YEARS(year) * SEC_IN_DAY;
|
||||
unix_time += days_in_year[month] * SEC_IN_DAY;
|
||||
/* if it's leap year and February has passed we should add 1 day */
|
||||
if ((EXFAT_EPOCH_YEAR + year) % 4 == 0 && month > 2)
|
||||
unix_time += SEC_IN_DAY;
|
||||
unix_time += (day - 1) * SEC_IN_DAY;
|
||||
|
||||
unix_time += hour * SEC_IN_HOUR;
|
||||
unix_time += min * SEC_IN_MIN;
|
||||
/* exFAT represents time with 2 sec granularity */
|
||||
unix_time += twosec * 2;
|
||||
unix_time += centisec / 100;
|
||||
|
||||
/* exFAT stores timestamps in local time, so we correct it to UTC */
|
||||
unix_time += exfat_timezone;
|
||||
|
||||
return unix_time;
|
||||
}
|
||||
|
||||
void exfat_unix2exfat(time_t unix_time, le16_t* date, le16_t* time,
|
||||
uint8_t* centisec)
|
||||
{
|
||||
time_t shift = EPOCH_DIFF_SEC + exfat_timezone;
|
||||
uint16_t day, month, year;
|
||||
uint16_t twosec, min, hour;
|
||||
int days;
|
||||
int i;
|
||||
|
||||
/* time before exFAT epoch cannot be represented */
|
||||
if (unix_time < shift)
|
||||
unix_time = shift;
|
||||
|
||||
unix_time -= shift;
|
||||
|
||||
days = unix_time / SEC_IN_DAY;
|
||||
year = (4 * days) / (4 * 365 + 1);
|
||||
days -= year * 365 + LEAP_YEARS(year);
|
||||
month = 0;
|
||||
for (i = 1; i <= 12; i++)
|
||||
{
|
||||
int leap_day = (IS_LEAP_YEAR(year) && i == 2);
|
||||
int leap_sub = (IS_LEAP_YEAR(year) && i >= 3);
|
||||
|
||||
if (i == 12 || days - leap_sub < days_in_year[i + 1] + leap_day)
|
||||
{
|
||||
month = i;
|
||||
days -= days_in_year[i] + leap_sub;
|
||||
break;
|
||||
}
|
||||
}
|
||||
day = days + 1;
|
||||
|
||||
hour = (unix_time % SEC_IN_DAY) / SEC_IN_HOUR;
|
||||
min = (unix_time % SEC_IN_HOUR) / SEC_IN_MIN;
|
||||
twosec = (unix_time % SEC_IN_MIN) / 2;
|
||||
|
||||
*date = cpu_to_le16(day | (month << 5) | (year << 9));
|
||||
*time = cpu_to_le16(twosec | (min << 5) | (hour << 11));
|
||||
if (centisec)
|
||||
*centisec = (unix_time % 2) * 100;
|
||||
}
|
||||
|
||||
void exfat_tzset(void)
|
||||
{
|
||||
time_t now;
|
||||
struct tm* utc;
|
||||
|
||||
tzset();
|
||||
now = time(NULL);
|
||||
utc = gmtime(&now);
|
||||
/* gmtime() always sets tm_isdst to 0 because daylight savings never
|
||||
affect UTC. Setting tm_isdst to -1 makes mktime() to determine whether
|
||||
summer time is in effect. */
|
||||
utc->tm_isdst = -1;
|
||||
exfat_timezone = mktime(utc) - now;
|
||||
}
|
||||
245
LinuxGUI/Ventoy2Disk/Lib/exfat/src/libexfat/utf.c
Normal file
245
LinuxGUI/Ventoy2Disk/Lib/exfat/src/libexfat/utf.c
Normal file
@@ -0,0 +1,245 @@
|
||||
/*
|
||||
utf.c (13.09.09)
|
||||
exFAT file system implementation library.
|
||||
|
||||
Free exFAT implementation.
|
||||
Copyright (C) 2010-2018 Andrew Nayenko
|
||||
|
||||
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.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "exfat.h"
|
||||
#include <errno.h>
|
||||
|
||||
static char* wchar_to_utf8(char* output, wchar_t wc, size_t outsize)
|
||||
{
|
||||
if (wc <= 0x7f)
|
||||
{
|
||||
if (outsize < 1)
|
||||
return NULL;
|
||||
*output++ = (char) wc;
|
||||
}
|
||||
else if (wc <= 0x7ff)
|
||||
{
|
||||
if (outsize < 2)
|
||||
return NULL;
|
||||
*output++ = 0xc0 | (wc >> 6);
|
||||
*output++ = 0x80 | (wc & 0x3f);
|
||||
}
|
||||
else if (wc <= 0xffff)
|
||||
{
|
||||
if (outsize < 3)
|
||||
return NULL;
|
||||
*output++ = 0xe0 | (wc >> 12);
|
||||
*output++ = 0x80 | ((wc >> 6) & 0x3f);
|
||||
*output++ = 0x80 | (wc & 0x3f);
|
||||
}
|
||||
else if (wc <= 0x1fffff)
|
||||
{
|
||||
if (outsize < 4)
|
||||
return NULL;
|
||||
*output++ = 0xf0 | (wc >> 18);
|
||||
*output++ = 0x80 | ((wc >> 12) & 0x3f);
|
||||
*output++ = 0x80 | ((wc >> 6) & 0x3f);
|
||||
*output++ = 0x80 | (wc & 0x3f);
|
||||
}
|
||||
else if (wc <= 0x3ffffff)
|
||||
{
|
||||
if (outsize < 5)
|
||||
return NULL;
|
||||
*output++ = 0xf8 | (wc >> 24);
|
||||
*output++ = 0x80 | ((wc >> 18) & 0x3f);
|
||||
*output++ = 0x80 | ((wc >> 12) & 0x3f);
|
||||
*output++ = 0x80 | ((wc >> 6) & 0x3f);
|
||||
*output++ = 0x80 | (wc & 0x3f);
|
||||
}
|
||||
else if (wc <= 0x7fffffff)
|
||||
{
|
||||
if (outsize < 6)
|
||||
return NULL;
|
||||
*output++ = 0xfc | (wc >> 30);
|
||||
*output++ = 0x80 | ((wc >> 24) & 0x3f);
|
||||
*output++ = 0x80 | ((wc >> 18) & 0x3f);
|
||||
*output++ = 0x80 | ((wc >> 12) & 0x3f);
|
||||
*output++ = 0x80 | ((wc >> 6) & 0x3f);
|
||||
*output++ = 0x80 | (wc & 0x3f);
|
||||
}
|
||||
else
|
||||
return NULL;
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
static const le16_t* utf16_to_wchar(const le16_t* input, wchar_t* wc,
|
||||
size_t insize)
|
||||
{
|
||||
if ((le16_to_cpu(input[0]) & 0xfc00) == 0xd800)
|
||||
{
|
||||
if (insize < 2 || (le16_to_cpu(input[1]) & 0xfc00) != 0xdc00)
|
||||
return NULL;
|
||||
*wc = ((wchar_t) (le16_to_cpu(input[0]) & 0x3ff) << 10);
|
||||
*wc |= (le16_to_cpu(input[1]) & 0x3ff);
|
||||
*wc += 0x10000;
|
||||
return input + 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
*wc = le16_to_cpu(*input);
|
||||
return input + 1;
|
||||
}
|
||||
}
|
||||
|
||||
int utf16_to_utf8(char* output, const le16_t* input, size_t outsize,
|
||||
size_t insize)
|
||||
{
|
||||
const le16_t* inp = input;
|
||||
char* outp = output;
|
||||
wchar_t wc;
|
||||
|
||||
while (inp - input < insize)
|
||||
{
|
||||
inp = utf16_to_wchar(inp, &wc, insize - (inp - input));
|
||||
if (inp == NULL)
|
||||
{
|
||||
exfat_error("illegal UTF-16 sequence");
|
||||
return -EILSEQ;
|
||||
}
|
||||
outp = wchar_to_utf8(outp, wc, outsize - (outp - output));
|
||||
if (outp == NULL)
|
||||
{
|
||||
exfat_error("name is too long");
|
||||
return -ENAMETOOLONG;
|
||||
}
|
||||
if (wc == 0)
|
||||
return 0;
|
||||
}
|
||||
if (outp - output >= outsize)
|
||||
{
|
||||
exfat_error("name is too long");
|
||||
return -ENAMETOOLONG;
|
||||
}
|
||||
*outp = '\0';
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char* utf8_to_wchar(const char* input, wchar_t* wc,
|
||||
size_t insize)
|
||||
{
|
||||
if ((input[0] & 0x80) == 0 && insize >= 1)
|
||||
{
|
||||
*wc = (wchar_t) input[0];
|
||||
return input + 1;
|
||||
}
|
||||
if ((input[0] & 0xe0) == 0xc0 && insize >= 2)
|
||||
{
|
||||
*wc = (((wchar_t) input[0] & 0x1f) << 6) |
|
||||
((wchar_t) input[1] & 0x3f);
|
||||
return input + 2;
|
||||
}
|
||||
if ((input[0] & 0xf0) == 0xe0 && insize >= 3)
|
||||
{
|
||||
*wc = (((wchar_t) input[0] & 0x0f) << 12) |
|
||||
(((wchar_t) input[1] & 0x3f) << 6) |
|
||||
((wchar_t) input[2] & 0x3f);
|
||||
return input + 3;
|
||||
}
|
||||
if ((input[0] & 0xf8) == 0xf0 && insize >= 4)
|
||||
{
|
||||
*wc = (((wchar_t) input[0] & 0x07) << 18) |
|
||||
(((wchar_t) input[1] & 0x3f) << 12) |
|
||||
(((wchar_t) input[2] & 0x3f) << 6) |
|
||||
((wchar_t) input[3] & 0x3f);
|
||||
return input + 4;
|
||||
}
|
||||
if ((input[0] & 0xfc) == 0xf8 && insize >= 5)
|
||||
{
|
||||
*wc = (((wchar_t) input[0] & 0x03) << 24) |
|
||||
(((wchar_t) input[1] & 0x3f) << 18) |
|
||||
(((wchar_t) input[2] & 0x3f) << 12) |
|
||||
(((wchar_t) input[3] & 0x3f) << 6) |
|
||||
((wchar_t) input[4] & 0x3f);
|
||||
return input + 5;
|
||||
}
|
||||
if ((input[0] & 0xfe) == 0xfc && insize >= 6)
|
||||
{
|
||||
*wc = (((wchar_t) input[0] & 0x01) << 30) |
|
||||
(((wchar_t) input[1] & 0x3f) << 24) |
|
||||
(((wchar_t) input[2] & 0x3f) << 18) |
|
||||
(((wchar_t) input[3] & 0x3f) << 12) |
|
||||
(((wchar_t) input[4] & 0x3f) << 6) |
|
||||
((wchar_t) input[5] & 0x3f);
|
||||
return input + 6;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static le16_t* wchar_to_utf16(le16_t* output, wchar_t wc, size_t outsize)
|
||||
{
|
||||
if (wc <= 0xffff) /* if character is from BMP */
|
||||
{
|
||||
if (outsize == 0)
|
||||
return NULL;
|
||||
output[0] = cpu_to_le16(wc);
|
||||
return output + 1;
|
||||
}
|
||||
if (outsize < 2)
|
||||
return NULL;
|
||||
wc -= 0x10000;
|
||||
output[0] = cpu_to_le16(0xd800 | ((wc >> 10) & 0x3ff));
|
||||
output[1] = cpu_to_le16(0xdc00 | (wc & 0x3ff));
|
||||
return output + 2;
|
||||
}
|
||||
|
||||
int utf8_to_utf16(le16_t* output, const char* input, size_t outsize,
|
||||
size_t insize)
|
||||
{
|
||||
const char* inp = input;
|
||||
le16_t* outp = output;
|
||||
wchar_t wc;
|
||||
|
||||
while (inp - input < insize)
|
||||
{
|
||||
inp = utf8_to_wchar(inp, &wc, insize - (inp - input));
|
||||
if (inp == NULL)
|
||||
{
|
||||
exfat_error("illegal UTF-8 sequence");
|
||||
return -EILSEQ;
|
||||
}
|
||||
outp = wchar_to_utf16(outp, wc, outsize - (outp - output));
|
||||
if (outp == NULL)
|
||||
{
|
||||
exfat_error("name is too long");
|
||||
return -ENAMETOOLONG;
|
||||
}
|
||||
if (wc == 0)
|
||||
break;
|
||||
}
|
||||
if (outp - output >= outsize)
|
||||
{
|
||||
exfat_error("name is too long");
|
||||
return -ENAMETOOLONG;
|
||||
}
|
||||
*outp = cpu_to_le16(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t utf16_length(const le16_t* str)
|
||||
{
|
||||
size_t i = 0;
|
||||
|
||||
while (le16_to_cpu(str[i]))
|
||||
i++;
|
||||
return i;
|
||||
}
|
||||
180
LinuxGUI/Ventoy2Disk/Lib/exfat/src/libexfat/utils.c
Normal file
180
LinuxGUI/Ventoy2Disk/Lib/exfat/src/libexfat/utils.c
Normal file
@@ -0,0 +1,180 @@
|
||||
/*
|
||||
utils.c (04.09.09)
|
||||
exFAT file system implementation library.
|
||||
|
||||
Free exFAT implementation.
|
||||
Copyright (C) 2010-2018 Andrew Nayenko
|
||||
|
||||
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.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "exfat.h"
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
void exfat_stat(const struct exfat* ef, const struct exfat_node* node,
|
||||
struct stat* stbuf)
|
||||
{
|
||||
memset(stbuf, 0, sizeof(struct stat));
|
||||
if (node->attrib & EXFAT_ATTRIB_DIR)
|
||||
stbuf->st_mode = S_IFDIR | (0777 & ~ef->dmask);
|
||||
else
|
||||
stbuf->st_mode = S_IFREG | (0777 & ~ef->fmask);
|
||||
stbuf->st_nlink = 1;
|
||||
stbuf->st_uid = ef->uid;
|
||||
stbuf->st_gid = ef->gid;
|
||||
stbuf->st_size = node->size;
|
||||
stbuf->st_blocks = ROUND_UP(node->size, CLUSTER_SIZE(*ef->sb)) / 512;
|
||||
stbuf->st_mtime = node->mtime;
|
||||
stbuf->st_atime = node->atime;
|
||||
/* set ctime to mtime to ensure we don't break programs that rely on ctime
|
||||
(e.g. rsync) */
|
||||
stbuf->st_ctime = node->mtime;
|
||||
}
|
||||
|
||||
void exfat_get_name(const struct exfat_node* node,
|
||||
char buffer[EXFAT_UTF8_NAME_BUFFER_MAX])
|
||||
{
|
||||
if (utf16_to_utf8(buffer, node->name, EXFAT_UTF8_NAME_BUFFER_MAX,
|
||||
EXFAT_NAME_MAX) != 0)
|
||||
exfat_bug("failed to convert name to UTF-8");
|
||||
}
|
||||
|
||||
static uint16_t add_checksum_byte(uint16_t sum, uint8_t byte)
|
||||
{
|
||||
return ((sum << 15) | (sum >> 1)) + byte;
|
||||
}
|
||||
|
||||
static uint16_t add_checksum_bytes(uint16_t sum, const void* buffer, size_t n)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < n; i++)
|
||||
sum = add_checksum_byte(sum, ((const uint8_t*) buffer)[i]);
|
||||
return sum;
|
||||
}
|
||||
|
||||
uint16_t exfat_start_checksum(const struct exfat_entry_meta1* entry)
|
||||
{
|
||||
uint16_t sum = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < sizeof(struct exfat_entry); i++)
|
||||
if (i != 2 && i != 3) /* skip checksum field itself */
|
||||
sum = add_checksum_byte(sum, ((const uint8_t*) entry)[i]);
|
||||
return sum;
|
||||
}
|
||||
|
||||
uint16_t exfat_add_checksum(const void* entry, uint16_t sum)
|
||||
{
|
||||
return add_checksum_bytes(sum, entry, sizeof(struct exfat_entry));
|
||||
}
|
||||
|
||||
le16_t exfat_calc_checksum(const struct exfat_entry* entries, int n)
|
||||
{
|
||||
uint16_t checksum;
|
||||
int i;
|
||||
|
||||
checksum = exfat_start_checksum((const struct exfat_entry_meta1*) entries);
|
||||
for (i = 1; i < n; i++)
|
||||
checksum = exfat_add_checksum(entries + i, checksum);
|
||||
return cpu_to_le16(checksum);
|
||||
}
|
||||
|
||||
uint32_t exfat_vbr_start_checksum(const void* sector, size_t size)
|
||||
{
|
||||
size_t i;
|
||||
uint32_t sum = 0;
|
||||
|
||||
for (i = 0; i < size; i++)
|
||||
/* skip volume_state and allocated_percent fields */
|
||||
if (i != 0x6a && i != 0x6b && i != 0x70)
|
||||
sum = ((sum << 31) | (sum >> 1)) + ((const uint8_t*) sector)[i];
|
||||
return sum;
|
||||
}
|
||||
|
||||
uint32_t exfat_vbr_add_checksum(const void* sector, size_t size, uint32_t sum)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < size; i++)
|
||||
sum = ((sum << 31) | (sum >> 1)) + ((const uint8_t*) sector)[i];
|
||||
return sum;
|
||||
}
|
||||
|
||||
le16_t exfat_calc_name_hash(const struct exfat* ef, const le16_t* name,
|
||||
size_t length)
|
||||
{
|
||||
size_t i;
|
||||
uint16_t hash = 0;
|
||||
|
||||
for (i = 0; i < length; i++)
|
||||
{
|
||||
uint16_t c = le16_to_cpu(name[i]);
|
||||
|
||||
/* convert to upper case */
|
||||
c = ef->upcase[c];
|
||||
|
||||
hash = ((hash << 15) | (hash >> 1)) + (c & 0xff);
|
||||
hash = ((hash << 15) | (hash >> 1)) + (c >> 8);
|
||||
}
|
||||
return cpu_to_le16(hash);
|
||||
}
|
||||
|
||||
void exfat_humanize_bytes(uint64_t value, struct exfat_human_bytes* hb)
|
||||
{
|
||||
size_t i;
|
||||
/* 16 EB (minus 1 byte) is the largest size that can be represented by
|
||||
uint64_t */
|
||||
const char* units[] = {"bytes", "KB", "MB", "GB", "TB", "PB", "EB"};
|
||||
uint64_t divisor = 1;
|
||||
uint64_t temp = 0;
|
||||
|
||||
for (i = 0; ; i++, divisor *= 1024)
|
||||
{
|
||||
temp = (value + divisor / 2) / divisor;
|
||||
|
||||
if (temp == 0)
|
||||
break;
|
||||
if (temp / 1024 * 1024 == temp)
|
||||
continue;
|
||||
if (temp < 10240)
|
||||
break;
|
||||
}
|
||||
hb->value = temp;
|
||||
hb->unit = units[i];
|
||||
}
|
||||
|
||||
void exfat_print_info(const struct exfat_super_block* sb,
|
||||
uint32_t free_clusters)
|
||||
{
|
||||
struct exfat_human_bytes hb;
|
||||
off_t total_space = le64_to_cpu(sb->sector_count) * SECTOR_SIZE(*sb);
|
||||
off_t avail_space = (off_t) free_clusters * CLUSTER_SIZE(*sb);
|
||||
|
||||
printf("File system version %hhu.%hhu\n",
|
||||
sb->version.major, sb->version.minor);
|
||||
exfat_humanize_bytes(SECTOR_SIZE(*sb), &hb);
|
||||
printf("Sector size %10"PRIu64" %s\n", hb.value, hb.unit);
|
||||
exfat_humanize_bytes(CLUSTER_SIZE(*sb), &hb);
|
||||
printf("Cluster size %10"PRIu64" %s\n", hb.value, hb.unit);
|
||||
exfat_humanize_bytes(total_space, &hb);
|
||||
printf("Volume size %10"PRIu64" %s\n", hb.value, hb.unit);
|
||||
exfat_humanize_bytes(total_space - avail_space, &hb);
|
||||
printf("Used space %10"PRIu64" %s\n", hb.value, hb.unit);
|
||||
exfat_humanize_bytes(avail_space, &hb);
|
||||
printf("Available space %10"PRIu64" %s\n", hb.value, hb.unit);
|
||||
}
|
||||
79
LinuxGUI/Ventoy2Disk/Lib/exfat/src/mkfs/cbm.c
Normal file
79
LinuxGUI/Ventoy2Disk/Lib/exfat/src/mkfs/cbm.c
Normal file
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
cbm.c (09.11.10)
|
||||
Clusters Bitmap creation code.
|
||||
|
||||
Free exFAT implementation.
|
||||
Copyright (C) 2011-2018 Andrew Nayenko
|
||||
|
||||
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.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "cbm.h"
|
||||
#include "fat.h"
|
||||
#include "uct.h"
|
||||
#include "rootdir.h"
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
|
||||
static off_t cbm_alignment(void)
|
||||
{
|
||||
return get_cluster_size();
|
||||
}
|
||||
|
||||
static off_t cbm_size(void)
|
||||
{
|
||||
return DIV_ROUND_UP(
|
||||
(get_volume_size() - get_position(&cbm)) / get_cluster_size(),
|
||||
CHAR_BIT);
|
||||
}
|
||||
|
||||
static int cbm_write(struct exfat_dev* dev)
|
||||
{
|
||||
uint32_t allocated_clusters =
|
||||
DIV_ROUND_UP(cbm.get_size(), get_cluster_size()) +
|
||||
DIV_ROUND_UP(uct.get_size(), get_cluster_size()) +
|
||||
DIV_ROUND_UP(rootdir.get_size(), get_cluster_size());
|
||||
size_t bitmap_size = ROUND_UP(allocated_clusters, CHAR_BIT);
|
||||
bitmap_t* bitmap = malloc(BMAP_SIZE(bitmap_size));
|
||||
size_t i;
|
||||
|
||||
if (bitmap == NULL)
|
||||
{
|
||||
exfat_error("failed to allocate bitmap of %zu bytes",
|
||||
BMAP_SIZE(bitmap_size));
|
||||
return 1;
|
||||
}
|
||||
memset(bitmap, 0, BMAP_SIZE(bitmap_size));
|
||||
|
||||
for (i = 0; i < bitmap_size; i++)
|
||||
if (i < allocated_clusters)
|
||||
BMAP_SET(bitmap, i);
|
||||
if (exfat_write(dev, bitmap, bitmap_size / CHAR_BIT) < 0)
|
||||
{
|
||||
free(bitmap);
|
||||
exfat_error("failed to write bitmap of %zu bytes",
|
||||
bitmap_size / CHAR_BIT);
|
||||
return 1;
|
||||
}
|
||||
free(bitmap);
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct fs_object cbm =
|
||||
{
|
||||
.get_alignment = cbm_alignment,
|
||||
.get_size = cbm_size,
|
||||
.write = cbm_write,
|
||||
};
|
||||
30
LinuxGUI/Ventoy2Disk/Lib/exfat/src/mkfs/cbm.h
Normal file
30
LinuxGUI/Ventoy2Disk/Lib/exfat/src/mkfs/cbm.h
Normal file
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
cbm.h (09.11.10)
|
||||
Clusters Bitmap creation code.
|
||||
|
||||
Free exFAT implementation.
|
||||
Copyright (C) 2011-2018 Andrew Nayenko
|
||||
|
||||
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.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef MKFS_CBM_H_INCLUDED
|
||||
#define MKFS_CBM_H_INCLUDED
|
||||
|
||||
#include "mkexfat.h"
|
||||
|
||||
extern const struct fs_object cbm;
|
||||
|
||||
#endif /* ifndef MKFS_CBM_H_INCLUDED */
|
||||
88
LinuxGUI/Ventoy2Disk/Lib/exfat/src/mkfs/fat.c
Normal file
88
LinuxGUI/Ventoy2Disk/Lib/exfat/src/mkfs/fat.c
Normal file
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
fat.c (09.11.10)
|
||||
File Allocation Table creation code.
|
||||
|
||||
Free exFAT implementation.
|
||||
Copyright (C) 2011-2018 Andrew Nayenko
|
||||
|
||||
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.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "fat.h"
|
||||
#include "cbm.h"
|
||||
#include "uct.h"
|
||||
#include "rootdir.h"
|
||||
#include <unistd.h>
|
||||
|
||||
static off_t fat_alignment(void)
|
||||
{
|
||||
return (off_t) 128 * get_sector_size();
|
||||
}
|
||||
|
||||
static off_t fat_size(void)
|
||||
{
|
||||
return get_volume_size() / get_cluster_size() * sizeof(cluster_t);
|
||||
}
|
||||
|
||||
static cluster_t fat_write_entry(struct exfat_dev* dev, cluster_t cluster,
|
||||
cluster_t value)
|
||||
{
|
||||
le32_t fat_entry = cpu_to_le32(value);
|
||||
if (exfat_write(dev, &fat_entry, sizeof(fat_entry)) < 0)
|
||||
{
|
||||
exfat_error("failed to write FAT entry 0x%x", value);
|
||||
return 0;
|
||||
}
|
||||
return cluster + 1;
|
||||
}
|
||||
|
||||
static cluster_t fat_write_entries(struct exfat_dev* dev, cluster_t cluster,
|
||||
uint64_t length)
|
||||
{
|
||||
cluster_t end = cluster + DIV_ROUND_UP(length, get_cluster_size());
|
||||
|
||||
while (cluster < end - 1)
|
||||
{
|
||||
cluster = fat_write_entry(dev, cluster, cluster + 1);
|
||||
if (cluster == 0)
|
||||
return 0;
|
||||
}
|
||||
return fat_write_entry(dev, cluster, EXFAT_CLUSTER_END);
|
||||
}
|
||||
|
||||
static int fat_write(struct exfat_dev* dev)
|
||||
{
|
||||
cluster_t c = 0;
|
||||
|
||||
if (!(c = fat_write_entry(dev, c, 0xfffffff8))) /* media type */
|
||||
return 1;
|
||||
if (!(c = fat_write_entry(dev, c, 0xffffffff))) /* some weird constant */
|
||||
return 1;
|
||||
if (!(c = fat_write_entries(dev, c, cbm.get_size())))
|
||||
return 1;
|
||||
if (!(c = fat_write_entries(dev, c, uct.get_size())))
|
||||
return 1;
|
||||
if (!(c = fat_write_entries(dev, c, rootdir.get_size())))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct fs_object fat =
|
||||
{
|
||||
.get_alignment = fat_alignment,
|
||||
.get_size = fat_size,
|
||||
.write = fat_write,
|
||||
};
|
||||
30
LinuxGUI/Ventoy2Disk/Lib/exfat/src/mkfs/fat.h
Normal file
30
LinuxGUI/Ventoy2Disk/Lib/exfat/src/mkfs/fat.h
Normal file
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
fat.h (09.11.10)
|
||||
File Allocation Table creation code.
|
||||
|
||||
Free exFAT implementation.
|
||||
Copyright (C) 2011-2018 Andrew Nayenko
|
||||
|
||||
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.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef MKFS_FAT_H_INCLUDED
|
||||
#define MKFS_FAT_H_INCLUDED
|
||||
|
||||
#include "mkexfat.h"
|
||||
|
||||
extern const struct fs_object fat;
|
||||
|
||||
#endif /* ifndef MKFS_FAT_H_INCLUDED */
|
||||
167
LinuxGUI/Ventoy2Disk/Lib/exfat/src/mkfs/mkexfat.c
Normal file
167
LinuxGUI/Ventoy2Disk/Lib/exfat/src/mkfs/mkexfat.c
Normal file
@@ -0,0 +1,167 @@
|
||||
/*
|
||||
mkexfat.c (22.04.12)
|
||||
FS creation engine.
|
||||
|
||||
Free exFAT implementation.
|
||||
Copyright (C) 2011-2018 Andrew Nayenko
|
||||
|
||||
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.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "mkexfat.h"
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
static int check_size(off_t volume_size)
|
||||
{
|
||||
const struct fs_object** pp;
|
||||
off_t position = 0;
|
||||
|
||||
for (pp = objects; *pp; pp++)
|
||||
{
|
||||
position = ROUND_UP(position, (*pp)->get_alignment());
|
||||
position += (*pp)->get_size();
|
||||
}
|
||||
|
||||
if (position > volume_size)
|
||||
{
|
||||
struct exfat_human_bytes vhb;
|
||||
|
||||
exfat_humanize_bytes(volume_size, &vhb);
|
||||
exfat_error("too small device (%"PRIu64" %s)", vhb.value, vhb.unit);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
static int erase_object(struct exfat_dev* dev, const void* block,
|
||||
size_t block_size, off_t start, off_t size)
|
||||
{
|
||||
const off_t block_count = DIV_ROUND_UP(size, block_size);
|
||||
off_t i;
|
||||
|
||||
if (exfat_seek(dev, start, SEEK_SET) == (off_t) -1)
|
||||
{
|
||||
exfat_error("seek to 0x%"PRIx64" failed", start);
|
||||
return 1;
|
||||
}
|
||||
for (i = 0; i < size; i += block_size)
|
||||
{
|
||||
if (exfat_write(dev, block, MIN(size - i, block_size)) < 0)
|
||||
{
|
||||
exfat_error("failed to erase block %"PRIu64"/%"PRIu64
|
||||
" at 0x%"PRIx64, i + 1, block_count, start);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int erase(struct exfat_dev* dev)
|
||||
{
|
||||
const struct fs_object** pp;
|
||||
off_t position = 0;
|
||||
const size_t block_size = 1024 * 1024;
|
||||
void* block = malloc(block_size);
|
||||
|
||||
if (block == NULL)
|
||||
{
|
||||
exfat_error("failed to allocate erase block of %zu bytes", block_size);
|
||||
return 1;
|
||||
}
|
||||
memset(block, 0, block_size);
|
||||
|
||||
for (pp = objects; *pp; pp++)
|
||||
{
|
||||
position = ROUND_UP(position, (*pp)->get_alignment());
|
||||
if (erase_object(dev, block, block_size, position,
|
||||
(*pp)->get_size()) != 0)
|
||||
{
|
||||
free(block);
|
||||
return 1;
|
||||
}
|
||||
position += (*pp)->get_size();
|
||||
}
|
||||
|
||||
free(block);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int create(struct exfat_dev* dev)
|
||||
{
|
||||
const struct fs_object** pp;
|
||||
off_t position = 0;
|
||||
|
||||
for (pp = objects; *pp; pp++)
|
||||
{
|
||||
position = ROUND_UP(position, (*pp)->get_alignment());
|
||||
if (exfat_seek(dev, position, SEEK_SET) == (off_t) -1)
|
||||
{
|
||||
exfat_error("seek to 0x%"PRIx64" failed", position);
|
||||
return 1;
|
||||
}
|
||||
if ((*pp)->write(dev) != 0)
|
||||
return 1;
|
||||
position += (*pp)->get_size();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mkfs(struct exfat_dev* dev, off_t volume_size)
|
||||
{
|
||||
if (check_size(volume_size) != 0)
|
||||
return 1;
|
||||
|
||||
exfat_debug("Creating... ");
|
||||
//fputs("Creating... ", stdout);
|
||||
//fflush(stdout);
|
||||
if (erase(dev) != 0)
|
||||
return 1;
|
||||
if (create(dev) != 0)
|
||||
return 1;
|
||||
//puts("done.");
|
||||
|
||||
//fputs("Flushing... ", stdout);
|
||||
//fflush(stdout);
|
||||
exfat_debug("Flushing... ");
|
||||
if (exfat_fsync(dev) != 0)
|
||||
return 1;
|
||||
//puts("done.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
off_t get_position(const struct fs_object* object)
|
||||
{
|
||||
const struct fs_object** pp;
|
||||
off_t position = 0;
|
||||
|
||||
for (pp = objects; *pp; pp++)
|
||||
{
|
||||
position = ROUND_UP(position, (*pp)->get_alignment());
|
||||
if (*pp == object)
|
||||
return position;
|
||||
position += (*pp)->get_size();
|
||||
}
|
||||
exfat_bug("unknown object");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
49
LinuxGUI/Ventoy2Disk/Lib/exfat/src/mkfs/mkexfat.h
Normal file
49
LinuxGUI/Ventoy2Disk/Lib/exfat/src/mkfs/mkexfat.h
Normal file
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
mkexfat.h (09.11.10)
|
||||
FS creation engine.
|
||||
|
||||
Free exFAT implementation.
|
||||
Copyright (C) 2011-2018 Andrew Nayenko
|
||||
|
||||
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.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef MKFS_MKEXFAT_H_INCLUDED
|
||||
#define MKFS_MKEXFAT_H_INCLUDED
|
||||
|
||||
#include "exfat.h"
|
||||
|
||||
struct fs_object
|
||||
{
|
||||
off_t (*get_alignment)(void);
|
||||
off_t (*get_size)(void);
|
||||
int (*write)(struct exfat_dev* dev);
|
||||
};
|
||||
|
||||
extern const struct fs_object* objects[];
|
||||
|
||||
int get_sector_bits(void);
|
||||
int get_spc_bits(void);
|
||||
off_t get_volume_size(void);
|
||||
const le16_t* get_volume_label(void);
|
||||
uint32_t get_volume_serial(void);
|
||||
uint64_t get_first_sector(void);
|
||||
int get_sector_size(void);
|
||||
int get_cluster_size(void);
|
||||
|
||||
int mkfs(struct exfat_dev* dev, off_t volume_size);
|
||||
off_t get_position(const struct fs_object* object);
|
||||
|
||||
#endif /* ifndef MKFS_MKEXFAT_H_INCLUDED */
|
||||
268
LinuxGUI/Ventoy2Disk/Lib/exfat/src/mkfs/mkexfat_main.c
Normal file
268
LinuxGUI/Ventoy2Disk/Lib/exfat/src/mkfs/mkexfat_main.c
Normal file
@@ -0,0 +1,268 @@
|
||||
/*
|
||||
main.c (15.08.10)
|
||||
Creates exFAT file system.
|
||||
|
||||
Free exFAT implementation.
|
||||
Copyright (C) 2011-2018 Andrew Nayenko
|
||||
|
||||
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.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "mkexfat.h"
|
||||
#include "vbr.h"
|
||||
#include "fat.h"
|
||||
#include "cbm.h"
|
||||
#include "uct.h"
|
||||
#include "rootdir.h"
|
||||
#include "exfat.h"
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
|
||||
const struct fs_object* objects[] =
|
||||
{
|
||||
&vbr,
|
||||
&vbr,
|
||||
&fat,
|
||||
/* clusters heap */
|
||||
&cbm,
|
||||
&uct,
|
||||
&rootdir,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static struct
|
||||
{
|
||||
int sector_bits;
|
||||
int spc_bits;
|
||||
off_t volume_size;
|
||||
le16_t volume_label[EXFAT_ENAME_MAX + 1];
|
||||
uint32_t volume_serial;
|
||||
uint64_t first_sector;
|
||||
}
|
||||
param;
|
||||
|
||||
extern int g_vtoy_exfat_disk_fd;
|
||||
extern uint64_t g_vtoy_exfat_part_size;
|
||||
|
||||
int get_sector_bits(void)
|
||||
{
|
||||
return param.sector_bits;
|
||||
}
|
||||
|
||||
int get_spc_bits(void)
|
||||
{
|
||||
return param.spc_bits;
|
||||
}
|
||||
|
||||
off_t get_volume_size(void)
|
||||
{
|
||||
return param.volume_size;
|
||||
}
|
||||
|
||||
const le16_t* get_volume_label(void)
|
||||
{
|
||||
return param.volume_label;
|
||||
}
|
||||
|
||||
uint32_t get_volume_serial(void)
|
||||
{
|
||||
return param.volume_serial;
|
||||
}
|
||||
|
||||
uint64_t get_first_sector(void)
|
||||
{
|
||||
return param.first_sector;
|
||||
}
|
||||
|
||||
int get_sector_size(void)
|
||||
{
|
||||
return 1 << get_sector_bits();
|
||||
}
|
||||
|
||||
int get_cluster_size(void)
|
||||
{
|
||||
return get_sector_size() << get_spc_bits();
|
||||
}
|
||||
|
||||
static int setup_spc_bits(int sector_bits, int user_defined, off_t volume_size)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (user_defined != -1)
|
||||
{
|
||||
off_t cluster_size = 1 << sector_bits << user_defined;
|
||||
if (volume_size / cluster_size > EXFAT_LAST_DATA_CLUSTER)
|
||||
{
|
||||
struct exfat_human_bytes chb, vhb;
|
||||
|
||||
exfat_humanize_bytes(cluster_size, &chb);
|
||||
exfat_humanize_bytes(volume_size, &vhb);
|
||||
exfat_error("cluster size %"PRIu64" %s is too small for "
|
||||
"%"PRIu64" %s volume, try -s %d",
|
||||
chb.value, chb.unit,
|
||||
vhb.value, vhb.unit,
|
||||
1 << setup_spc_bits(sector_bits, -1, volume_size));
|
||||
return -1;
|
||||
}
|
||||
return user_defined;
|
||||
}
|
||||
|
||||
if (volume_size < 256ull * 1024 * 1024)
|
||||
return MAX(0, 12 - sector_bits); /* 4 KB */
|
||||
if (volume_size < 32ull * 1024 * 1024 * 1024)
|
||||
return MAX(0, 15 - sector_bits); /* 32 KB */
|
||||
|
||||
for (i = 17; ; i++) /* 128 KB or more */
|
||||
if (DIV_ROUND_UP(volume_size, 1 << i) <= EXFAT_LAST_DATA_CLUSTER)
|
||||
return MAX(0, i - sector_bits);
|
||||
}
|
||||
|
||||
static int setup_volume_label(le16_t label[EXFAT_ENAME_MAX + 1], const char* s)
|
||||
{
|
||||
memset(label, 0, (EXFAT_ENAME_MAX + 1) * sizeof(le16_t));
|
||||
if (s == NULL)
|
||||
return 0;
|
||||
return utf8_to_utf16(label, s, EXFAT_ENAME_MAX + 1, strlen(s));
|
||||
}
|
||||
|
||||
static uint32_t setup_volume_serial(uint32_t user_defined)
|
||||
{
|
||||
struct timeval now;
|
||||
|
||||
if (user_defined != 0)
|
||||
return user_defined;
|
||||
|
||||
if (gettimeofday(&now, NULL) != 0)
|
||||
{
|
||||
exfat_error("failed to form volume id");
|
||||
return 0;
|
||||
}
|
||||
return (now.tv_sec << 20) | now.tv_usec;
|
||||
}
|
||||
|
||||
static int setup(struct exfat_dev* dev, int sector_bits, int spc_bits,
|
||||
const char* volume_label, uint32_t volume_serial,
|
||||
uint64_t first_sector)
|
||||
{
|
||||
param.sector_bits = sector_bits;
|
||||
param.first_sector = first_sector;
|
||||
param.volume_size = exfat_get_size(dev);
|
||||
|
||||
param.spc_bits = setup_spc_bits(sector_bits, spc_bits, param.volume_size);
|
||||
if (param.spc_bits == -1)
|
||||
return 1;
|
||||
|
||||
if (setup_volume_label(param.volume_label, volume_label) != 0)
|
||||
return 1;
|
||||
|
||||
param.volume_serial = setup_volume_serial(volume_serial);
|
||||
if (param.volume_serial == 0)
|
||||
return 1;
|
||||
|
||||
return mkfs(dev, param.volume_size);
|
||||
}
|
||||
|
||||
static int logarithm2(int n)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < sizeof(int) * CHAR_BIT - 1; i++)
|
||||
if ((1 << i) == n)
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void usage(const char* prog)
|
||||
{
|
||||
fprintf(stderr, "Usage: %s [-i volume-id] [-n label] "
|
||||
"[-p partition-first-sector] "
|
||||
"[-s sectors-per-cluster] [-V] <device>\n", prog);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int mkexfat_main(const char *devpath, int fd, uint64_t part_sector_count)
|
||||
{
|
||||
int spc_bits = -1;
|
||||
uint32_t volume_serial = 0;
|
||||
uint64_t first_sector = 0;
|
||||
struct exfat_dev* dev;
|
||||
|
||||
#if 0
|
||||
while ((opt = getopt(argc, argv, "i:n:p:s:V")) != -1)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
case 'i':
|
||||
volume_serial = strtol(optarg, NULL, 16);
|
||||
break;
|
||||
case 'n':
|
||||
volume_label = optarg;
|
||||
break;
|
||||
case 'p':
|
||||
first_sector = strtoll(optarg, NULL, 10);
|
||||
break;
|
||||
case 's':
|
||||
spc_bits = logarithm2(atoi(optarg));
|
||||
if (spc_bits < 0)
|
||||
{
|
||||
exfat_error("invalid option value: '%s'", optarg);
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
case 'V':
|
||||
puts("Copyright (C) 2011-2018 Andrew Nayenko");
|
||||
return 0;
|
||||
default:
|
||||
usage(argv[0]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif /* #if 0 */
|
||||
|
||||
/*
|
||||
* DiskSize > 32GB Cluster Size use 128KB
|
||||
* DiskSize < 32GB Cluster Size use 32KB
|
||||
*/
|
||||
if ((part_sector_count / 2097152) > 32)
|
||||
{
|
||||
spc_bits = logarithm2(256);
|
||||
}
|
||||
else
|
||||
{
|
||||
spc_bits = logarithm2(64);
|
||||
}
|
||||
|
||||
g_vtoy_exfat_disk_fd = fd;
|
||||
g_vtoy_exfat_part_size = part_sector_count * 512;
|
||||
|
||||
dev = exfat_open(devpath, EXFAT_MODE_RW);
|
||||
if (dev == NULL)
|
||||
return 1;
|
||||
if (setup(dev, 9, spc_bits, "Ventoy", volume_serial, first_sector) != 0)
|
||||
{
|
||||
exfat_close(dev);
|
||||
return 1;
|
||||
}
|
||||
if (exfat_close(dev) != 0)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
102
LinuxGUI/Ventoy2Disk/Lib/exfat/src/mkfs/rootdir.c
Normal file
102
LinuxGUI/Ventoy2Disk/Lib/exfat/src/mkfs/rootdir.c
Normal file
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
rootdir.c (09.11.10)
|
||||
Root directory creation code.
|
||||
|
||||
Free exFAT implementation.
|
||||
Copyright (C) 2011-2018 Andrew Nayenko
|
||||
|
||||
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.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "rootdir.h"
|
||||
#include "uct.h"
|
||||
#include "cbm.h"
|
||||
#include "uctc.h"
|
||||
#include <string.h>
|
||||
|
||||
static off_t rootdir_alignment(void)
|
||||
{
|
||||
return get_cluster_size();
|
||||
}
|
||||
|
||||
static off_t rootdir_size(void)
|
||||
{
|
||||
return get_cluster_size();
|
||||
}
|
||||
|
||||
static void init_label_entry(struct exfat_entry_label* label_entry)
|
||||
{
|
||||
memset(label_entry, 0, sizeof(struct exfat_entry_label));
|
||||
label_entry->type = EXFAT_ENTRY_LABEL ^ EXFAT_ENTRY_VALID;
|
||||
|
||||
if (utf16_length(get_volume_label()) == 0)
|
||||
return;
|
||||
|
||||
memcpy(label_entry->name, get_volume_label(),
|
||||
EXFAT_ENAME_MAX * sizeof(le16_t));
|
||||
label_entry->length = utf16_length(get_volume_label());
|
||||
label_entry->type |= EXFAT_ENTRY_VALID;
|
||||
}
|
||||
|
||||
static void init_bitmap_entry(struct exfat_entry_bitmap* bitmap_entry)
|
||||
{
|
||||
memset(bitmap_entry, 0, sizeof(struct exfat_entry_bitmap));
|
||||
bitmap_entry->type = EXFAT_ENTRY_BITMAP;
|
||||
bitmap_entry->start_cluster = cpu_to_le32(EXFAT_FIRST_DATA_CLUSTER);
|
||||
bitmap_entry->size = cpu_to_le64(cbm.get_size());
|
||||
}
|
||||
|
||||
static void init_upcase_entry(struct exfat_entry_upcase* upcase_entry)
|
||||
{
|
||||
size_t i;
|
||||
uint32_t sum = 0;
|
||||
|
||||
for (i = 0; i < sizeof(upcase_table); i++)
|
||||
sum = ((sum << 31) | (sum >> 1)) + upcase_table[i];
|
||||
|
||||
memset(upcase_entry, 0, sizeof(struct exfat_entry_upcase));
|
||||
upcase_entry->type = EXFAT_ENTRY_UPCASE;
|
||||
upcase_entry->checksum = cpu_to_le32(sum);
|
||||
upcase_entry->start_cluster = cpu_to_le32(
|
||||
(get_position(&uct) - get_position(&cbm)) / get_cluster_size() +
|
||||
EXFAT_FIRST_DATA_CLUSTER);
|
||||
upcase_entry->size = cpu_to_le64(sizeof(upcase_table));
|
||||
}
|
||||
|
||||
static int rootdir_write(struct exfat_dev* dev)
|
||||
{
|
||||
struct exfat_entry_label label_entry;
|
||||
struct exfat_entry_bitmap bitmap_entry;
|
||||
struct exfat_entry_upcase upcase_entry;
|
||||
|
||||
init_label_entry(&label_entry);
|
||||
init_bitmap_entry(&bitmap_entry);
|
||||
init_upcase_entry(&upcase_entry);
|
||||
|
||||
if (exfat_write(dev, &label_entry, sizeof(struct exfat_entry)) < 0)
|
||||
return 1;
|
||||
if (exfat_write(dev, &bitmap_entry, sizeof(struct exfat_entry)) < 0)
|
||||
return 1;
|
||||
if (exfat_write(dev, &upcase_entry, sizeof(struct exfat_entry)) < 0)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct fs_object rootdir =
|
||||
{
|
||||
.get_alignment = rootdir_alignment,
|
||||
.get_size = rootdir_size,
|
||||
.write = rootdir_write,
|
||||
};
|
||||
30
LinuxGUI/Ventoy2Disk/Lib/exfat/src/mkfs/rootdir.h
Normal file
30
LinuxGUI/Ventoy2Disk/Lib/exfat/src/mkfs/rootdir.h
Normal file
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
rootdir.h (09.11.10)
|
||||
Root directory creation code.
|
||||
|
||||
Free exFAT implementation.
|
||||
Copyright (C) 2011-2018 Andrew Nayenko
|
||||
|
||||
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.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef MKFS_ROOTDIR_H_INCLUDED
|
||||
#define MKFS_ROOTDIR_H_INCLUDED
|
||||
|
||||
#include "mkexfat.h"
|
||||
|
||||
extern const struct fs_object rootdir;
|
||||
|
||||
#endif /* ifndef MKFS_ROOTDIR_H_INCLUDED */
|
||||
52
LinuxGUI/Ventoy2Disk/Lib/exfat/src/mkfs/uct.c
Normal file
52
LinuxGUI/Ventoy2Disk/Lib/exfat/src/mkfs/uct.c
Normal file
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
uct.c (09.11.10)
|
||||
Upper Case Table creation code.
|
||||
|
||||
Free exFAT implementation.
|
||||
Copyright (C) 2011-2018 Andrew Nayenko
|
||||
|
||||
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.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "uct.h"
|
||||
#include "uctc.h"
|
||||
|
||||
static off_t uct_alignment(void)
|
||||
{
|
||||
return get_cluster_size();
|
||||
}
|
||||
|
||||
static off_t uct_size(void)
|
||||
{
|
||||
return sizeof(upcase_table);
|
||||
}
|
||||
|
||||
static int uct_write(struct exfat_dev* dev)
|
||||
{
|
||||
if (exfat_write(dev, upcase_table, sizeof(upcase_table)) < 0)
|
||||
{
|
||||
exfat_error("failed to write upcase table of %zu bytes",
|
||||
sizeof(upcase_table));
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct fs_object uct =
|
||||
{
|
||||
.get_alignment = uct_alignment,
|
||||
.get_size = uct_size,
|
||||
.write = uct_write,
|
||||
};
|
||||
30
LinuxGUI/Ventoy2Disk/Lib/exfat/src/mkfs/uct.h
Normal file
30
LinuxGUI/Ventoy2Disk/Lib/exfat/src/mkfs/uct.h
Normal file
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
uct.h (09.11.10)
|
||||
Upper Case Table creation code.
|
||||
|
||||
Free exFAT implementation.
|
||||
Copyright (C) 2011-2018 Andrew Nayenko
|
||||
|
||||
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.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef MKFS_UCT_H_INCLUDED
|
||||
#define MKFS_UCT_H_INCLUDED
|
||||
|
||||
#include "mkexfat.h"
|
||||
|
||||
extern const struct fs_object uct;
|
||||
|
||||
#endif /* ifndef MKFS_UCT_H_INCLUDED */
|
||||
757
LinuxGUI/Ventoy2Disk/Lib/exfat/src/mkfs/uctc.c
Normal file
757
LinuxGUI/Ventoy2Disk/Lib/exfat/src/mkfs/uctc.c
Normal file
@@ -0,0 +1,757 @@
|
||||
/*
|
||||
uctc.c (30.04.12)
|
||||
Upper Case Table contents.
|
||||
|
||||
Free exFAT implementation.
|
||||
Copyright (C) 2011-2018 Andrew Nayenko
|
||||
|
||||
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.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "uctc.h"
|
||||
|
||||
uint8_t upcase_table[5836] =
|
||||
{
|
||||
0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00,
|
||||
0x04, 0x00, 0x05, 0x00, 0x06, 0x00, 0x07, 0x00,
|
||||
0x08, 0x00, 0x09, 0x00, 0x0a, 0x00, 0x0b, 0x00,
|
||||
0x0c, 0x00, 0x0d, 0x00, 0x0e, 0x00, 0x0f, 0x00,
|
||||
0x10, 0x00, 0x11, 0x00, 0x12, 0x00, 0x13, 0x00,
|
||||
0x14, 0x00, 0x15, 0x00, 0x16, 0x00, 0x17, 0x00,
|
||||
0x18, 0x00, 0x19, 0x00, 0x1a, 0x00, 0x1b, 0x00,
|
||||
0x1c, 0x00, 0x1d, 0x00, 0x1e, 0x00, 0x1f, 0x00,
|
||||
0x20, 0x00, 0x21, 0x00, 0x22, 0x00, 0x23, 0x00,
|
||||
0x24, 0x00, 0x25, 0x00, 0x26, 0x00, 0x27, 0x00,
|
||||
0x28, 0x00, 0x29, 0x00, 0x2a, 0x00, 0x2b, 0x00,
|
||||
0x2c, 0x00, 0x2d, 0x00, 0x2e, 0x00, 0x2f, 0x00,
|
||||
0x30, 0x00, 0x31, 0x00, 0x32, 0x00, 0x33, 0x00,
|
||||
0x34, 0x00, 0x35, 0x00, 0x36, 0x00, 0x37, 0x00,
|
||||
0x38, 0x00, 0x39, 0x00, 0x3a, 0x00, 0x3b, 0x00,
|
||||
0x3c, 0x00, 0x3d, 0x00, 0x3e, 0x00, 0x3f, 0x00,
|
||||
0x40, 0x00, 0x41, 0x00, 0x42, 0x00, 0x43, 0x00,
|
||||
0x44, 0x00, 0x45, 0x00, 0x46, 0x00, 0x47, 0x00,
|
||||
0x48, 0x00, 0x49, 0x00, 0x4a, 0x00, 0x4b, 0x00,
|
||||
0x4c, 0x00, 0x4d, 0x00, 0x4e, 0x00, 0x4f, 0x00,
|
||||
0x50, 0x00, 0x51, 0x00, 0x52, 0x00, 0x53, 0x00,
|
||||
0x54, 0x00, 0x55, 0x00, 0x56, 0x00, 0x57, 0x00,
|
||||
0x58, 0x00, 0x59, 0x00, 0x5a, 0x00, 0x5b, 0x00,
|
||||
0x5c, 0x00, 0x5d, 0x00, 0x5e, 0x00, 0x5f, 0x00,
|
||||
0x60, 0x00, 0x41, 0x00, 0x42, 0x00, 0x43, 0x00,
|
||||
0x44, 0x00, 0x45, 0x00, 0x46, 0x00, 0x47, 0x00,
|
||||
0x48, 0x00, 0x49, 0x00, 0x4a, 0x00, 0x4b, 0x00,
|
||||
0x4c, 0x00, 0x4d, 0x00, 0x4e, 0x00, 0x4f, 0x00,
|
||||
0x50, 0x00, 0x51, 0x00, 0x52, 0x00, 0x53, 0x00,
|
||||
0x54, 0x00, 0x55, 0x00, 0x56, 0x00, 0x57, 0x00,
|
||||
0x58, 0x00, 0x59, 0x00, 0x5a, 0x00, 0x7b, 0x00,
|
||||
0x7c, 0x00, 0x7d, 0x00, 0x7e, 0x00, 0x7f, 0x00,
|
||||
0x80, 0x00, 0x81, 0x00, 0x82, 0x00, 0x83, 0x00,
|
||||
0x84, 0x00, 0x85, 0x00, 0x86, 0x00, 0x87, 0x00,
|
||||
0x88, 0x00, 0x89, 0x00, 0x8a, 0x00, 0x8b, 0x00,
|
||||
0x8c, 0x00, 0x8d, 0x00, 0x8e, 0x00, 0x8f, 0x00,
|
||||
0x90, 0x00, 0x91, 0x00, 0x92, 0x00, 0x93, 0x00,
|
||||
0x94, 0x00, 0x95, 0x00, 0x96, 0x00, 0x97, 0x00,
|
||||
0x98, 0x00, 0x99, 0x00, 0x9a, 0x00, 0x9b, 0x00,
|
||||
0x9c, 0x00, 0x9d, 0x00, 0x9e, 0x00, 0x9f, 0x00,
|
||||
0xa0, 0x00, 0xa1, 0x00, 0xa2, 0x00, 0xa3, 0x00,
|
||||
0xa4, 0x00, 0xa5, 0x00, 0xa6, 0x00, 0xa7, 0x00,
|
||||
0xa8, 0x00, 0xa9, 0x00, 0xaa, 0x00, 0xab, 0x00,
|
||||
0xac, 0x00, 0xad, 0x00, 0xae, 0x00, 0xaf, 0x00,
|
||||
0xb0, 0x00, 0xb1, 0x00, 0xb2, 0x00, 0xb3, 0x00,
|
||||
0xb4, 0x00, 0xb5, 0x00, 0xb6, 0x00, 0xb7, 0x00,
|
||||
0xb8, 0x00, 0xb9, 0x00, 0xba, 0x00, 0xbb, 0x00,
|
||||
0xbc, 0x00, 0xbd, 0x00, 0xbe, 0x00, 0xbf, 0x00,
|
||||
0xc0, 0x00, 0xc1, 0x00, 0xc2, 0x00, 0xc3, 0x00,
|
||||
0xc4, 0x00, 0xc5, 0x00, 0xc6, 0x00, 0xc7, 0x00,
|
||||
0xc8, 0x00, 0xc9, 0x00, 0xca, 0x00, 0xcb, 0x00,
|
||||
0xcc, 0x00, 0xcd, 0x00, 0xce, 0x00, 0xcf, 0x00,
|
||||
0xd0, 0x00, 0xd1, 0x00, 0xd2, 0x00, 0xd3, 0x00,
|
||||
0xd4, 0x00, 0xd5, 0x00, 0xd6, 0x00, 0xd7, 0x00,
|
||||
0xd8, 0x00, 0xd9, 0x00, 0xda, 0x00, 0xdb, 0x00,
|
||||
0xdc, 0x00, 0xdd, 0x00, 0xde, 0x00, 0xdf, 0x00,
|
||||
0xc0, 0x00, 0xc1, 0x00, 0xc2, 0x00, 0xc3, 0x00,
|
||||
0xc4, 0x00, 0xc5, 0x00, 0xc6, 0x00, 0xc7, 0x00,
|
||||
0xc8, 0x00, 0xc9, 0x00, 0xca, 0x00, 0xcb, 0x00,
|
||||
0xcc, 0x00, 0xcd, 0x00, 0xce, 0x00, 0xcf, 0x00,
|
||||
0xd0, 0x00, 0xd1, 0x00, 0xd2, 0x00, 0xd3, 0x00,
|
||||
0xd4, 0x00, 0xd5, 0x00, 0xd6, 0x00, 0xf7, 0x00,
|
||||
0xd8, 0x00, 0xd9, 0x00, 0xda, 0x00, 0xdb, 0x00,
|
||||
0xdc, 0x00, 0xdd, 0x00, 0xde, 0x00, 0x78, 0x01,
|
||||
0x00, 0x01, 0x00, 0x01, 0x02, 0x01, 0x02, 0x01,
|
||||
0x04, 0x01, 0x04, 0x01, 0x06, 0x01, 0x06, 0x01,
|
||||
0x08, 0x01, 0x08, 0x01, 0x0a, 0x01, 0x0a, 0x01,
|
||||
0x0c, 0x01, 0x0c, 0x01, 0x0e, 0x01, 0x0e, 0x01,
|
||||
0x10, 0x01, 0x10, 0x01, 0x12, 0x01, 0x12, 0x01,
|
||||
0x14, 0x01, 0x14, 0x01, 0x16, 0x01, 0x16, 0x01,
|
||||
0x18, 0x01, 0x18, 0x01, 0x1a, 0x01, 0x1a, 0x01,
|
||||
0x1c, 0x01, 0x1c, 0x01, 0x1e, 0x01, 0x1e, 0x01,
|
||||
0x20, 0x01, 0x20, 0x01, 0x22, 0x01, 0x22, 0x01,
|
||||
0x24, 0x01, 0x24, 0x01, 0x26, 0x01, 0x26, 0x01,
|
||||
0x28, 0x01, 0x28, 0x01, 0x2a, 0x01, 0x2a, 0x01,
|
||||
0x2c, 0x01, 0x2c, 0x01, 0x2e, 0x01, 0x2e, 0x01,
|
||||
0x30, 0x01, 0x31, 0x01, 0x32, 0x01, 0x32, 0x01,
|
||||
0x34, 0x01, 0x34, 0x01, 0x36, 0x01, 0x36, 0x01,
|
||||
0x38, 0x01, 0x39, 0x01, 0x39, 0x01, 0x3b, 0x01,
|
||||
0x3b, 0x01, 0x3d, 0x01, 0x3d, 0x01, 0x3f, 0x01,
|
||||
0x3f, 0x01, 0x41, 0x01, 0x41, 0x01, 0x43, 0x01,
|
||||
0x43, 0x01, 0x45, 0x01, 0x45, 0x01, 0x47, 0x01,
|
||||
0x47, 0x01, 0x49, 0x01, 0x4a, 0x01, 0x4a, 0x01,
|
||||
0x4c, 0x01, 0x4c, 0x01, 0x4e, 0x01, 0x4e, 0x01,
|
||||
0x50, 0x01, 0x50, 0x01, 0x52, 0x01, 0x52, 0x01,
|
||||
0x54, 0x01, 0x54, 0x01, 0x56, 0x01, 0x56, 0x01,
|
||||
0x58, 0x01, 0x58, 0x01, 0x5a, 0x01, 0x5a, 0x01,
|
||||
0x5c, 0x01, 0x5c, 0x01, 0x5e, 0x01, 0x5e, 0x01,
|
||||
0x60, 0x01, 0x60, 0x01, 0x62, 0x01, 0x62, 0x01,
|
||||
0x64, 0x01, 0x64, 0x01, 0x66, 0x01, 0x66, 0x01,
|
||||
0x68, 0x01, 0x68, 0x01, 0x6a, 0x01, 0x6a, 0x01,
|
||||
0x6c, 0x01, 0x6c, 0x01, 0x6e, 0x01, 0x6e, 0x01,
|
||||
0x70, 0x01, 0x70, 0x01, 0x72, 0x01, 0x72, 0x01,
|
||||
0x74, 0x01, 0x74, 0x01, 0x76, 0x01, 0x76, 0x01,
|
||||
0x78, 0x01, 0x79, 0x01, 0x79, 0x01, 0x7b, 0x01,
|
||||
0x7b, 0x01, 0x7d, 0x01, 0x7d, 0x01, 0x7f, 0x01,
|
||||
0x43, 0x02, 0x81, 0x01, 0x82, 0x01, 0x82, 0x01,
|
||||
0x84, 0x01, 0x84, 0x01, 0x86, 0x01, 0x87, 0x01,
|
||||
0x87, 0x01, 0x89, 0x01, 0x8a, 0x01, 0x8b, 0x01,
|
||||
0x8b, 0x01, 0x8d, 0x01, 0x8e, 0x01, 0x8f, 0x01,
|
||||
0x90, 0x01, 0x91, 0x01, 0x91, 0x01, 0x93, 0x01,
|
||||
0x94, 0x01, 0xf6, 0x01, 0x96, 0x01, 0x97, 0x01,
|
||||
0x98, 0x01, 0x98, 0x01, 0x3d, 0x02, 0x9b, 0x01,
|
||||
0x9c, 0x01, 0x9d, 0x01, 0x20, 0x02, 0x9f, 0x01,
|
||||
0xa0, 0x01, 0xa0, 0x01, 0xa2, 0x01, 0xa2, 0x01,
|
||||
0xa4, 0x01, 0xa4, 0x01, 0xa6, 0x01, 0xa7, 0x01,
|
||||
0xa7, 0x01, 0xa9, 0x01, 0xaa, 0x01, 0xab, 0x01,
|
||||
0xac, 0x01, 0xac, 0x01, 0xae, 0x01, 0xaf, 0x01,
|
||||
0xaf, 0x01, 0xb1, 0x01, 0xb2, 0x01, 0xb3, 0x01,
|
||||
0xb3, 0x01, 0xb5, 0x01, 0xb5, 0x01, 0xb7, 0x01,
|
||||
0xb8, 0x01, 0xb8, 0x01, 0xba, 0x01, 0xbb, 0x01,
|
||||
0xbc, 0x01, 0xbc, 0x01, 0xbe, 0x01, 0xf7, 0x01,
|
||||
0xc0, 0x01, 0xc1, 0x01, 0xc2, 0x01, 0xc3, 0x01,
|
||||
0xc4, 0x01, 0xc5, 0x01, 0xc4, 0x01, 0xc7, 0x01,
|
||||
0xc8, 0x01, 0xc7, 0x01, 0xca, 0x01, 0xcb, 0x01,
|
||||
0xca, 0x01, 0xcd, 0x01, 0xcd, 0x01, 0xcf, 0x01,
|
||||
0xcf, 0x01, 0xd1, 0x01, 0xd1, 0x01, 0xd3, 0x01,
|
||||
0xd3, 0x01, 0xd5, 0x01, 0xd5, 0x01, 0xd7, 0x01,
|
||||
0xd7, 0x01, 0xd9, 0x01, 0xd9, 0x01, 0xdb, 0x01,
|
||||
0xdb, 0x01, 0x8e, 0x01, 0xde, 0x01, 0xde, 0x01,
|
||||
0xe0, 0x01, 0xe0, 0x01, 0xe2, 0x01, 0xe2, 0x01,
|
||||
0xe4, 0x01, 0xe4, 0x01, 0xe6, 0x01, 0xe6, 0x01,
|
||||
0xe8, 0x01, 0xe8, 0x01, 0xea, 0x01, 0xea, 0x01,
|
||||
0xec, 0x01, 0xec, 0x01, 0xee, 0x01, 0xee, 0x01,
|
||||
0xf0, 0x01, 0xf1, 0x01, 0xf2, 0x01, 0xf1, 0x01,
|
||||
0xf4, 0x01, 0xf4, 0x01, 0xf6, 0x01, 0xf7, 0x01,
|
||||
0xf8, 0x01, 0xf8, 0x01, 0xfa, 0x01, 0xfa, 0x01,
|
||||
0xfc, 0x01, 0xfc, 0x01, 0xfe, 0x01, 0xfe, 0x01,
|
||||
0x00, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02,
|
||||
0x04, 0x02, 0x04, 0x02, 0x06, 0x02, 0x06, 0x02,
|
||||
0x08, 0x02, 0x08, 0x02, 0x0a, 0x02, 0x0a, 0x02,
|
||||
0x0c, 0x02, 0x0c, 0x02, 0x0e, 0x02, 0x0e, 0x02,
|
||||
0x10, 0x02, 0x10, 0x02, 0x12, 0x02, 0x12, 0x02,
|
||||
0x14, 0x02, 0x14, 0x02, 0x16, 0x02, 0x16, 0x02,
|
||||
0x18, 0x02, 0x18, 0x02, 0x1a, 0x02, 0x1a, 0x02,
|
||||
0x1c, 0x02, 0x1c, 0x02, 0x1e, 0x02, 0x1e, 0x02,
|
||||
0x20, 0x02, 0x21, 0x02, 0x22, 0x02, 0x22, 0x02,
|
||||
0x24, 0x02, 0x24, 0x02, 0x26, 0x02, 0x26, 0x02,
|
||||
0x28, 0x02, 0x28, 0x02, 0x2a, 0x02, 0x2a, 0x02,
|
||||
0x2c, 0x02, 0x2c, 0x02, 0x2e, 0x02, 0x2e, 0x02,
|
||||
0x30, 0x02, 0x30, 0x02, 0x32, 0x02, 0x32, 0x02,
|
||||
0x34, 0x02, 0x35, 0x02, 0x36, 0x02, 0x37, 0x02,
|
||||
0x38, 0x02, 0x39, 0x02, 0x65, 0x2c, 0x3b, 0x02,
|
||||
0x3b, 0x02, 0x3d, 0x02, 0x66, 0x2c, 0x3f, 0x02,
|
||||
0x40, 0x02, 0x41, 0x02, 0x41, 0x02, 0x43, 0x02,
|
||||
0x44, 0x02, 0x45, 0x02, 0x46, 0x02, 0x46, 0x02,
|
||||
0x48, 0x02, 0x48, 0x02, 0x4a, 0x02, 0x4a, 0x02,
|
||||
0x4c, 0x02, 0x4c, 0x02, 0x4e, 0x02, 0x4e, 0x02,
|
||||
0x50, 0x02, 0x51, 0x02, 0x52, 0x02, 0x81, 0x01,
|
||||
0x86, 0x01, 0x55, 0x02, 0x89, 0x01, 0x8a, 0x01,
|
||||
0x58, 0x02, 0x8f, 0x01, 0x5a, 0x02, 0x90, 0x01,
|
||||
0x5c, 0x02, 0x5d, 0x02, 0x5e, 0x02, 0x5f, 0x02,
|
||||
0x93, 0x01, 0x61, 0x02, 0x62, 0x02, 0x94, 0x01,
|
||||
0x64, 0x02, 0x65, 0x02, 0x66, 0x02, 0x67, 0x02,
|
||||
0x97, 0x01, 0x96, 0x01, 0x6a, 0x02, 0x62, 0x2c,
|
||||
0x6c, 0x02, 0x6d, 0x02, 0x6e, 0x02, 0x9c, 0x01,
|
||||
0x70, 0x02, 0x71, 0x02, 0x9d, 0x01, 0x73, 0x02,
|
||||
0x74, 0x02, 0x9f, 0x01, 0x76, 0x02, 0x77, 0x02,
|
||||
0x78, 0x02, 0x79, 0x02, 0x7a, 0x02, 0x7b, 0x02,
|
||||
0x7c, 0x02, 0x64, 0x2c, 0x7e, 0x02, 0x7f, 0x02,
|
||||
0xa6, 0x01, 0x81, 0x02, 0x82, 0x02, 0xa9, 0x01,
|
||||
0x84, 0x02, 0x85, 0x02, 0x86, 0x02, 0x87, 0x02,
|
||||
0xae, 0x01, 0x44, 0x02, 0xb1, 0x01, 0xb2, 0x01,
|
||||
0x45, 0x02, 0x8d, 0x02, 0x8e, 0x02, 0x8f, 0x02,
|
||||
0x90, 0x02, 0x91, 0x02, 0xb7, 0x01, 0x93, 0x02,
|
||||
0x94, 0x02, 0x95, 0x02, 0x96, 0x02, 0x97, 0x02,
|
||||
0x98, 0x02, 0x99, 0x02, 0x9a, 0x02, 0x9b, 0x02,
|
||||
0x9c, 0x02, 0x9d, 0x02, 0x9e, 0x02, 0x9f, 0x02,
|
||||
0xa0, 0x02, 0xa1, 0x02, 0xa2, 0x02, 0xa3, 0x02,
|
||||
0xa4, 0x02, 0xa5, 0x02, 0xa6, 0x02, 0xa7, 0x02,
|
||||
0xa8, 0x02, 0xa9, 0x02, 0xaa, 0x02, 0xab, 0x02,
|
||||
0xac, 0x02, 0xad, 0x02, 0xae, 0x02, 0xaf, 0x02,
|
||||
0xb0, 0x02, 0xb1, 0x02, 0xb2, 0x02, 0xb3, 0x02,
|
||||
0xb4, 0x02, 0xb5, 0x02, 0xb6, 0x02, 0xb7, 0x02,
|
||||
0xb8, 0x02, 0xb9, 0x02, 0xba, 0x02, 0xbb, 0x02,
|
||||
0xbc, 0x02, 0xbd, 0x02, 0xbe, 0x02, 0xbf, 0x02,
|
||||
0xc0, 0x02, 0xc1, 0x02, 0xc2, 0x02, 0xc3, 0x02,
|
||||
0xc4, 0x02, 0xc5, 0x02, 0xc6, 0x02, 0xc7, 0x02,
|
||||
0xc8, 0x02, 0xc9, 0x02, 0xca, 0x02, 0xcb, 0x02,
|
||||
0xcc, 0x02, 0xcd, 0x02, 0xce, 0x02, 0xcf, 0x02,
|
||||
0xd0, 0x02, 0xd1, 0x02, 0xd2, 0x02, 0xd3, 0x02,
|
||||
0xd4, 0x02, 0xd5, 0x02, 0xd6, 0x02, 0xd7, 0x02,
|
||||
0xd8, 0x02, 0xd9, 0x02, 0xda, 0x02, 0xdb, 0x02,
|
||||
0xdc, 0x02, 0xdd, 0x02, 0xde, 0x02, 0xdf, 0x02,
|
||||
0xe0, 0x02, 0xe1, 0x02, 0xe2, 0x02, 0xe3, 0x02,
|
||||
0xe4, 0x02, 0xe5, 0x02, 0xe6, 0x02, 0xe7, 0x02,
|
||||
0xe8, 0x02, 0xe9, 0x02, 0xea, 0x02, 0xeb, 0x02,
|
||||
0xec, 0x02, 0xed, 0x02, 0xee, 0x02, 0xef, 0x02,
|
||||
0xf0, 0x02, 0xf1, 0x02, 0xf2, 0x02, 0xf3, 0x02,
|
||||
0xf4, 0x02, 0xf5, 0x02, 0xf6, 0x02, 0xf7, 0x02,
|
||||
0xf8, 0x02, 0xf9, 0x02, 0xfa, 0x02, 0xfb, 0x02,
|
||||
0xfc, 0x02, 0xfd, 0x02, 0xfe, 0x02, 0xff, 0x02,
|
||||
0x00, 0x03, 0x01, 0x03, 0x02, 0x03, 0x03, 0x03,
|
||||
0x04, 0x03, 0x05, 0x03, 0x06, 0x03, 0x07, 0x03,
|
||||
0x08, 0x03, 0x09, 0x03, 0x0a, 0x03, 0x0b, 0x03,
|
||||
0x0c, 0x03, 0x0d, 0x03, 0x0e, 0x03, 0x0f, 0x03,
|
||||
0x10, 0x03, 0x11, 0x03, 0x12, 0x03, 0x13, 0x03,
|
||||
0x14, 0x03, 0x15, 0x03, 0x16, 0x03, 0x17, 0x03,
|
||||
0x18, 0x03, 0x19, 0x03, 0x1a, 0x03, 0x1b, 0x03,
|
||||
0x1c, 0x03, 0x1d, 0x03, 0x1e, 0x03, 0x1f, 0x03,
|
||||
0x20, 0x03, 0x21, 0x03, 0x22, 0x03, 0x23, 0x03,
|
||||
0x24, 0x03, 0x25, 0x03, 0x26, 0x03, 0x27, 0x03,
|
||||
0x28, 0x03, 0x29, 0x03, 0x2a, 0x03, 0x2b, 0x03,
|
||||
0x2c, 0x03, 0x2d, 0x03, 0x2e, 0x03, 0x2f, 0x03,
|
||||
0x30, 0x03, 0x31, 0x03, 0x32, 0x03, 0x33, 0x03,
|
||||
0x34, 0x03, 0x35, 0x03, 0x36, 0x03, 0x37, 0x03,
|
||||
0x38, 0x03, 0x39, 0x03, 0x3a, 0x03, 0x3b, 0x03,
|
||||
0x3c, 0x03, 0x3d, 0x03, 0x3e, 0x03, 0x3f, 0x03,
|
||||
0x40, 0x03, 0x41, 0x03, 0x42, 0x03, 0x43, 0x03,
|
||||
0x44, 0x03, 0x45, 0x03, 0x46, 0x03, 0x47, 0x03,
|
||||
0x48, 0x03, 0x49, 0x03, 0x4a, 0x03, 0x4b, 0x03,
|
||||
0x4c, 0x03, 0x4d, 0x03, 0x4e, 0x03, 0x4f, 0x03,
|
||||
0x50, 0x03, 0x51, 0x03, 0x52, 0x03, 0x53, 0x03,
|
||||
0x54, 0x03, 0x55, 0x03, 0x56, 0x03, 0x57, 0x03,
|
||||
0x58, 0x03, 0x59, 0x03, 0x5a, 0x03, 0x5b, 0x03,
|
||||
0x5c, 0x03, 0x5d, 0x03, 0x5e, 0x03, 0x5f, 0x03,
|
||||
0x60, 0x03, 0x61, 0x03, 0x62, 0x03, 0x63, 0x03,
|
||||
0x64, 0x03, 0x65, 0x03, 0x66, 0x03, 0x67, 0x03,
|
||||
0x68, 0x03, 0x69, 0x03, 0x6a, 0x03, 0x6b, 0x03,
|
||||
0x6c, 0x03, 0x6d, 0x03, 0x6e, 0x03, 0x6f, 0x03,
|
||||
0x70, 0x03, 0x71, 0x03, 0x72, 0x03, 0x73, 0x03,
|
||||
0x74, 0x03, 0x75, 0x03, 0x76, 0x03, 0x77, 0x03,
|
||||
0x78, 0x03, 0x79, 0x03, 0x7a, 0x03, 0xfd, 0x03,
|
||||
0xfe, 0x03, 0xff, 0x03, 0x7e, 0x03, 0x7f, 0x03,
|
||||
0x80, 0x03, 0x81, 0x03, 0x82, 0x03, 0x83, 0x03,
|
||||
0x84, 0x03, 0x85, 0x03, 0x86, 0x03, 0x87, 0x03,
|
||||
0x88, 0x03, 0x89, 0x03, 0x8a, 0x03, 0x8b, 0x03,
|
||||
0x8c, 0x03, 0x8d, 0x03, 0x8e, 0x03, 0x8f, 0x03,
|
||||
0x90, 0x03, 0x91, 0x03, 0x92, 0x03, 0x93, 0x03,
|
||||
0x94, 0x03, 0x95, 0x03, 0x96, 0x03, 0x97, 0x03,
|
||||
0x98, 0x03, 0x99, 0x03, 0x9a, 0x03, 0x9b, 0x03,
|
||||
0x9c, 0x03, 0x9d, 0x03, 0x9e, 0x03, 0x9f, 0x03,
|
||||
0xa0, 0x03, 0xa1, 0x03, 0xa2, 0x03, 0xa3, 0x03,
|
||||
0xa4, 0x03, 0xa5, 0x03, 0xa6, 0x03, 0xa7, 0x03,
|
||||
0xa8, 0x03, 0xa9, 0x03, 0xaa, 0x03, 0xab, 0x03,
|
||||
0x86, 0x03, 0x88, 0x03, 0x89, 0x03, 0x8a, 0x03,
|
||||
0xb0, 0x03, 0x91, 0x03, 0x92, 0x03, 0x93, 0x03,
|
||||
0x94, 0x03, 0x95, 0x03, 0x96, 0x03, 0x97, 0x03,
|
||||
0x98, 0x03, 0x99, 0x03, 0x9a, 0x03, 0x9b, 0x03,
|
||||
0x9c, 0x03, 0x9d, 0x03, 0x9e, 0x03, 0x9f, 0x03,
|
||||
0xa0, 0x03, 0xa1, 0x03, 0xa3, 0x03, 0xa3, 0x03,
|
||||
0xa4, 0x03, 0xa5, 0x03, 0xa6, 0x03, 0xa7, 0x03,
|
||||
0xa8, 0x03, 0xa9, 0x03, 0xaa, 0x03, 0xab, 0x03,
|
||||
0x8c, 0x03, 0x8e, 0x03, 0x8f, 0x03, 0xcf, 0x03,
|
||||
0xd0, 0x03, 0xd1, 0x03, 0xd2, 0x03, 0xd3, 0x03,
|
||||
0xd4, 0x03, 0xd5, 0x03, 0xd6, 0x03, 0xd7, 0x03,
|
||||
0xd8, 0x03, 0xd8, 0x03, 0xda, 0x03, 0xda, 0x03,
|
||||
0xdc, 0x03, 0xdc, 0x03, 0xde, 0x03, 0xde, 0x03,
|
||||
0xe0, 0x03, 0xe0, 0x03, 0xe2, 0x03, 0xe2, 0x03,
|
||||
0xe4, 0x03, 0xe4, 0x03, 0xe6, 0x03, 0xe6, 0x03,
|
||||
0xe8, 0x03, 0xe8, 0x03, 0xea, 0x03, 0xea, 0x03,
|
||||
0xec, 0x03, 0xec, 0x03, 0xee, 0x03, 0xee, 0x03,
|
||||
0xf0, 0x03, 0xf1, 0x03, 0xf9, 0x03, 0xf3, 0x03,
|
||||
0xf4, 0x03, 0xf5, 0x03, 0xf6, 0x03, 0xf7, 0x03,
|
||||
0xf7, 0x03, 0xf9, 0x03, 0xfa, 0x03, 0xfa, 0x03,
|
||||
0xfc, 0x03, 0xfd, 0x03, 0xfe, 0x03, 0xff, 0x03,
|
||||
0x00, 0x04, 0x01, 0x04, 0x02, 0x04, 0x03, 0x04,
|
||||
0x04, 0x04, 0x05, 0x04, 0x06, 0x04, 0x07, 0x04,
|
||||
0x08, 0x04, 0x09, 0x04, 0x0a, 0x04, 0x0b, 0x04,
|
||||
0x0c, 0x04, 0x0d, 0x04, 0x0e, 0x04, 0x0f, 0x04,
|
||||
0x10, 0x04, 0x11, 0x04, 0x12, 0x04, 0x13, 0x04,
|
||||
0x14, 0x04, 0x15, 0x04, 0x16, 0x04, 0x17, 0x04,
|
||||
0x18, 0x04, 0x19, 0x04, 0x1a, 0x04, 0x1b, 0x04,
|
||||
0x1c, 0x04, 0x1d, 0x04, 0x1e, 0x04, 0x1f, 0x04,
|
||||
0x20, 0x04, 0x21, 0x04, 0x22, 0x04, 0x23, 0x04,
|
||||
0x24, 0x04, 0x25, 0x04, 0x26, 0x04, 0x27, 0x04,
|
||||
0x28, 0x04, 0x29, 0x04, 0x2a, 0x04, 0x2b, 0x04,
|
||||
0x2c, 0x04, 0x2d, 0x04, 0x2e, 0x04, 0x2f, 0x04,
|
||||
0x10, 0x04, 0x11, 0x04, 0x12, 0x04, 0x13, 0x04,
|
||||
0x14, 0x04, 0x15, 0x04, 0x16, 0x04, 0x17, 0x04,
|
||||
0x18, 0x04, 0x19, 0x04, 0x1a, 0x04, 0x1b, 0x04,
|
||||
0x1c, 0x04, 0x1d, 0x04, 0x1e, 0x04, 0x1f, 0x04,
|
||||
0x20, 0x04, 0x21, 0x04, 0x22, 0x04, 0x23, 0x04,
|
||||
0x24, 0x04, 0x25, 0x04, 0x26, 0x04, 0x27, 0x04,
|
||||
0x28, 0x04, 0x29, 0x04, 0x2a, 0x04, 0x2b, 0x04,
|
||||
0x2c, 0x04, 0x2d, 0x04, 0x2e, 0x04, 0x2f, 0x04,
|
||||
0x00, 0x04, 0x01, 0x04, 0x02, 0x04, 0x03, 0x04,
|
||||
0x04, 0x04, 0x05, 0x04, 0x06, 0x04, 0x07, 0x04,
|
||||
0x08, 0x04, 0x09, 0x04, 0x0a, 0x04, 0x0b, 0x04,
|
||||
0x0c, 0x04, 0x0d, 0x04, 0x0e, 0x04, 0x0f, 0x04,
|
||||
0x60, 0x04, 0x60, 0x04, 0x62, 0x04, 0x62, 0x04,
|
||||
0x64, 0x04, 0x64, 0x04, 0x66, 0x04, 0x66, 0x04,
|
||||
0x68, 0x04, 0x68, 0x04, 0x6a, 0x04, 0x6a, 0x04,
|
||||
0x6c, 0x04, 0x6c, 0x04, 0x6e, 0x04, 0x6e, 0x04,
|
||||
0x70, 0x04, 0x70, 0x04, 0x72, 0x04, 0x72, 0x04,
|
||||
0x74, 0x04, 0x74, 0x04, 0x76, 0x04, 0x76, 0x04,
|
||||
0x78, 0x04, 0x78, 0x04, 0x7a, 0x04, 0x7a, 0x04,
|
||||
0x7c, 0x04, 0x7c, 0x04, 0x7e, 0x04, 0x7e, 0x04,
|
||||
0x80, 0x04, 0x80, 0x04, 0x82, 0x04, 0x83, 0x04,
|
||||
0x84, 0x04, 0x85, 0x04, 0x86, 0x04, 0x87, 0x04,
|
||||
0x88, 0x04, 0x89, 0x04, 0x8a, 0x04, 0x8a, 0x04,
|
||||
0x8c, 0x04, 0x8c, 0x04, 0x8e, 0x04, 0x8e, 0x04,
|
||||
0x90, 0x04, 0x90, 0x04, 0x92, 0x04, 0x92, 0x04,
|
||||
0x94, 0x04, 0x94, 0x04, 0x96, 0x04, 0x96, 0x04,
|
||||
0x98, 0x04, 0x98, 0x04, 0x9a, 0x04, 0x9a, 0x04,
|
||||
0x9c, 0x04, 0x9c, 0x04, 0x9e, 0x04, 0x9e, 0x04,
|
||||
0xa0, 0x04, 0xa0, 0x04, 0xa2, 0x04, 0xa2, 0x04,
|
||||
0xa4, 0x04, 0xa4, 0x04, 0xa6, 0x04, 0xa6, 0x04,
|
||||
0xa8, 0x04, 0xa8, 0x04, 0xaa, 0x04, 0xaa, 0x04,
|
||||
0xac, 0x04, 0xac, 0x04, 0xae, 0x04, 0xae, 0x04,
|
||||
0xb0, 0x04, 0xb0, 0x04, 0xb2, 0x04, 0xb2, 0x04,
|
||||
0xb4, 0x04, 0xb4, 0x04, 0xb6, 0x04, 0xb6, 0x04,
|
||||
0xb8, 0x04, 0xb8, 0x04, 0xba, 0x04, 0xba, 0x04,
|
||||
0xbc, 0x04, 0xbc, 0x04, 0xbe, 0x04, 0xbe, 0x04,
|
||||
0xc0, 0x04, 0xc1, 0x04, 0xc1, 0x04, 0xc3, 0x04,
|
||||
0xc3, 0x04, 0xc5, 0x04, 0xc5, 0x04, 0xc7, 0x04,
|
||||
0xc7, 0x04, 0xc9, 0x04, 0xc9, 0x04, 0xcb, 0x04,
|
||||
0xcb, 0x04, 0xcd, 0x04, 0xcd, 0x04, 0xc0, 0x04,
|
||||
0xd0, 0x04, 0xd0, 0x04, 0xd2, 0x04, 0xd2, 0x04,
|
||||
0xd4, 0x04, 0xd4, 0x04, 0xd6, 0x04, 0xd6, 0x04,
|
||||
0xd8, 0x04, 0xd8, 0x04, 0xda, 0x04, 0xda, 0x04,
|
||||
0xdc, 0x04, 0xdc, 0x04, 0xde, 0x04, 0xde, 0x04,
|
||||
0xe0, 0x04, 0xe0, 0x04, 0xe2, 0x04, 0xe2, 0x04,
|
||||
0xe4, 0x04, 0xe4, 0x04, 0xe6, 0x04, 0xe6, 0x04,
|
||||
0xe8, 0x04, 0xe8, 0x04, 0xea, 0x04, 0xea, 0x04,
|
||||
0xec, 0x04, 0xec, 0x04, 0xee, 0x04, 0xee, 0x04,
|
||||
0xf0, 0x04, 0xf0, 0x04, 0xf2, 0x04, 0xf2, 0x04,
|
||||
0xf4, 0x04, 0xf4, 0x04, 0xf6, 0x04, 0xf6, 0x04,
|
||||
0xf8, 0x04, 0xf8, 0x04, 0xfa, 0x04, 0xfa, 0x04,
|
||||
0xfc, 0x04, 0xfc, 0x04, 0xfe, 0x04, 0xfe, 0x04,
|
||||
0x00, 0x05, 0x00, 0x05, 0x02, 0x05, 0x02, 0x05,
|
||||
0x04, 0x05, 0x04, 0x05, 0x06, 0x05, 0x06, 0x05,
|
||||
0x08, 0x05, 0x08, 0x05, 0x0a, 0x05, 0x0a, 0x05,
|
||||
0x0c, 0x05, 0x0c, 0x05, 0x0e, 0x05, 0x0e, 0x05,
|
||||
0x10, 0x05, 0x10, 0x05, 0x12, 0x05, 0x12, 0x05,
|
||||
0x14, 0x05, 0x15, 0x05, 0x16, 0x05, 0x17, 0x05,
|
||||
0x18, 0x05, 0x19, 0x05, 0x1a, 0x05, 0x1b, 0x05,
|
||||
0x1c, 0x05, 0x1d, 0x05, 0x1e, 0x05, 0x1f, 0x05,
|
||||
0x20, 0x05, 0x21, 0x05, 0x22, 0x05, 0x23, 0x05,
|
||||
0x24, 0x05, 0x25, 0x05, 0x26, 0x05, 0x27, 0x05,
|
||||
0x28, 0x05, 0x29, 0x05, 0x2a, 0x05, 0x2b, 0x05,
|
||||
0x2c, 0x05, 0x2d, 0x05, 0x2e, 0x05, 0x2f, 0x05,
|
||||
0x30, 0x05, 0x31, 0x05, 0x32, 0x05, 0x33, 0x05,
|
||||
0x34, 0x05, 0x35, 0x05, 0x36, 0x05, 0x37, 0x05,
|
||||
0x38, 0x05, 0x39, 0x05, 0x3a, 0x05, 0x3b, 0x05,
|
||||
0x3c, 0x05, 0x3d, 0x05, 0x3e, 0x05, 0x3f, 0x05,
|
||||
0x40, 0x05, 0x41, 0x05, 0x42, 0x05, 0x43, 0x05,
|
||||
0x44, 0x05, 0x45, 0x05, 0x46, 0x05, 0x47, 0x05,
|
||||
0x48, 0x05, 0x49, 0x05, 0x4a, 0x05, 0x4b, 0x05,
|
||||
0x4c, 0x05, 0x4d, 0x05, 0x4e, 0x05, 0x4f, 0x05,
|
||||
0x50, 0x05, 0x51, 0x05, 0x52, 0x05, 0x53, 0x05,
|
||||
0x54, 0x05, 0x55, 0x05, 0x56, 0x05, 0x57, 0x05,
|
||||
0x58, 0x05, 0x59, 0x05, 0x5a, 0x05, 0x5b, 0x05,
|
||||
0x5c, 0x05, 0x5d, 0x05, 0x5e, 0x05, 0x5f, 0x05,
|
||||
0x60, 0x05, 0x31, 0x05, 0x32, 0x05, 0x33, 0x05,
|
||||
0x34, 0x05, 0x35, 0x05, 0x36, 0x05, 0x37, 0x05,
|
||||
0x38, 0x05, 0x39, 0x05, 0x3a, 0x05, 0x3b, 0x05,
|
||||
0x3c, 0x05, 0x3d, 0x05, 0x3e, 0x05, 0x3f, 0x05,
|
||||
0x40, 0x05, 0x41, 0x05, 0x42, 0x05, 0x43, 0x05,
|
||||
0x44, 0x05, 0x45, 0x05, 0x46, 0x05, 0x47, 0x05,
|
||||
0x48, 0x05, 0x49, 0x05, 0x4a, 0x05, 0x4b, 0x05,
|
||||
0x4c, 0x05, 0x4d, 0x05, 0x4e, 0x05, 0x4f, 0x05,
|
||||
0x50, 0x05, 0x51, 0x05, 0x52, 0x05, 0x53, 0x05,
|
||||
0x54, 0x05, 0x55, 0x05, 0x56, 0x05, 0xff, 0xff,
|
||||
0xf6, 0x17, 0x63, 0x2c, 0x7e, 0x1d, 0x7f, 0x1d,
|
||||
0x80, 0x1d, 0x81, 0x1d, 0x82, 0x1d, 0x83, 0x1d,
|
||||
0x84, 0x1d, 0x85, 0x1d, 0x86, 0x1d, 0x87, 0x1d,
|
||||
0x88, 0x1d, 0x89, 0x1d, 0x8a, 0x1d, 0x8b, 0x1d,
|
||||
0x8c, 0x1d, 0x8d, 0x1d, 0x8e, 0x1d, 0x8f, 0x1d,
|
||||
0x90, 0x1d, 0x91, 0x1d, 0x92, 0x1d, 0x93, 0x1d,
|
||||
0x94, 0x1d, 0x95, 0x1d, 0x96, 0x1d, 0x97, 0x1d,
|
||||
0x98, 0x1d, 0x99, 0x1d, 0x9a, 0x1d, 0x9b, 0x1d,
|
||||
0x9c, 0x1d, 0x9d, 0x1d, 0x9e, 0x1d, 0x9f, 0x1d,
|
||||
0xa0, 0x1d, 0xa1, 0x1d, 0xa2, 0x1d, 0xa3, 0x1d,
|
||||
0xa4, 0x1d, 0xa5, 0x1d, 0xa6, 0x1d, 0xa7, 0x1d,
|
||||
0xa8, 0x1d, 0xa9, 0x1d, 0xaa, 0x1d, 0xab, 0x1d,
|
||||
0xac, 0x1d, 0xad, 0x1d, 0xae, 0x1d, 0xaf, 0x1d,
|
||||
0xb0, 0x1d, 0xb1, 0x1d, 0xb2, 0x1d, 0xb3, 0x1d,
|
||||
0xb4, 0x1d, 0xb5, 0x1d, 0xb6, 0x1d, 0xb7, 0x1d,
|
||||
0xb8, 0x1d, 0xb9, 0x1d, 0xba, 0x1d, 0xbb, 0x1d,
|
||||
0xbc, 0x1d, 0xbd, 0x1d, 0xbe, 0x1d, 0xbf, 0x1d,
|
||||
0xc0, 0x1d, 0xc1, 0x1d, 0xc2, 0x1d, 0xc3, 0x1d,
|
||||
0xc4, 0x1d, 0xc5, 0x1d, 0xc6, 0x1d, 0xc7, 0x1d,
|
||||
0xc8, 0x1d, 0xc9, 0x1d, 0xca, 0x1d, 0xcb, 0x1d,
|
||||
0xcc, 0x1d, 0xcd, 0x1d, 0xce, 0x1d, 0xcf, 0x1d,
|
||||
0xd0, 0x1d, 0xd1, 0x1d, 0xd2, 0x1d, 0xd3, 0x1d,
|
||||
0xd4, 0x1d, 0xd5, 0x1d, 0xd6, 0x1d, 0xd7, 0x1d,
|
||||
0xd8, 0x1d, 0xd9, 0x1d, 0xda, 0x1d, 0xdb, 0x1d,
|
||||
0xdc, 0x1d, 0xdd, 0x1d, 0xde, 0x1d, 0xdf, 0x1d,
|
||||
0xe0, 0x1d, 0xe1, 0x1d, 0xe2, 0x1d, 0xe3, 0x1d,
|
||||
0xe4, 0x1d, 0xe5, 0x1d, 0xe6, 0x1d, 0xe7, 0x1d,
|
||||
0xe8, 0x1d, 0xe9, 0x1d, 0xea, 0x1d, 0xeb, 0x1d,
|
||||
0xec, 0x1d, 0xed, 0x1d, 0xee, 0x1d, 0xef, 0x1d,
|
||||
0xf0, 0x1d, 0xf1, 0x1d, 0xf2, 0x1d, 0xf3, 0x1d,
|
||||
0xf4, 0x1d, 0xf5, 0x1d, 0xf6, 0x1d, 0xf7, 0x1d,
|
||||
0xf8, 0x1d, 0xf9, 0x1d, 0xfa, 0x1d, 0xfb, 0x1d,
|
||||
0xfc, 0x1d, 0xfd, 0x1d, 0xfe, 0x1d, 0xff, 0x1d,
|
||||
0x00, 0x1e, 0x00, 0x1e, 0x02, 0x1e, 0x02, 0x1e,
|
||||
0x04, 0x1e, 0x04, 0x1e, 0x06, 0x1e, 0x06, 0x1e,
|
||||
0x08, 0x1e, 0x08, 0x1e, 0x0a, 0x1e, 0x0a, 0x1e,
|
||||
0x0c, 0x1e, 0x0c, 0x1e, 0x0e, 0x1e, 0x0e, 0x1e,
|
||||
0x10, 0x1e, 0x10, 0x1e, 0x12, 0x1e, 0x12, 0x1e,
|
||||
0x14, 0x1e, 0x14, 0x1e, 0x16, 0x1e, 0x16, 0x1e,
|
||||
0x18, 0x1e, 0x18, 0x1e, 0x1a, 0x1e, 0x1a, 0x1e,
|
||||
0x1c, 0x1e, 0x1c, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
|
||||
0x20, 0x1e, 0x20, 0x1e, 0x22, 0x1e, 0x22, 0x1e,
|
||||
0x24, 0x1e, 0x24, 0x1e, 0x26, 0x1e, 0x26, 0x1e,
|
||||
0x28, 0x1e, 0x28, 0x1e, 0x2a, 0x1e, 0x2a, 0x1e,
|
||||
0x2c, 0x1e, 0x2c, 0x1e, 0x2e, 0x1e, 0x2e, 0x1e,
|
||||
0x30, 0x1e, 0x30, 0x1e, 0x32, 0x1e, 0x32, 0x1e,
|
||||
0x34, 0x1e, 0x34, 0x1e, 0x36, 0x1e, 0x36, 0x1e,
|
||||
0x38, 0x1e, 0x38, 0x1e, 0x3a, 0x1e, 0x3a, 0x1e,
|
||||
0x3c, 0x1e, 0x3c, 0x1e, 0x3e, 0x1e, 0x3e, 0x1e,
|
||||
0x40, 0x1e, 0x40, 0x1e, 0x42, 0x1e, 0x42, 0x1e,
|
||||
0x44, 0x1e, 0x44, 0x1e, 0x46, 0x1e, 0x46, 0x1e,
|
||||
0x48, 0x1e, 0x48, 0x1e, 0x4a, 0x1e, 0x4a, 0x1e,
|
||||
0x4c, 0x1e, 0x4c, 0x1e, 0x4e, 0x1e, 0x4e, 0x1e,
|
||||
0x50, 0x1e, 0x50, 0x1e, 0x52, 0x1e, 0x52, 0x1e,
|
||||
0x54, 0x1e, 0x54, 0x1e, 0x56, 0x1e, 0x56, 0x1e,
|
||||
0x58, 0x1e, 0x58, 0x1e, 0x5a, 0x1e, 0x5a, 0x1e,
|
||||
0x5c, 0x1e, 0x5c, 0x1e, 0x5e, 0x1e, 0x5e, 0x1e,
|
||||
0x60, 0x1e, 0x60, 0x1e, 0x62, 0x1e, 0x62, 0x1e,
|
||||
0x64, 0x1e, 0x64, 0x1e, 0x66, 0x1e, 0x66, 0x1e,
|
||||
0x68, 0x1e, 0x68, 0x1e, 0x6a, 0x1e, 0x6a, 0x1e,
|
||||
0x6c, 0x1e, 0x6c, 0x1e, 0x6e, 0x1e, 0x6e, 0x1e,
|
||||
0x70, 0x1e, 0x70, 0x1e, 0x72, 0x1e, 0x72, 0x1e,
|
||||
0x74, 0x1e, 0x74, 0x1e, 0x76, 0x1e, 0x76, 0x1e,
|
||||
0x78, 0x1e, 0x78, 0x1e, 0x7a, 0x1e, 0x7a, 0x1e,
|
||||
0x7c, 0x1e, 0x7c, 0x1e, 0x7e, 0x1e, 0x7e, 0x1e,
|
||||
0x80, 0x1e, 0x80, 0x1e, 0x82, 0x1e, 0x82, 0x1e,
|
||||
0x84, 0x1e, 0x84, 0x1e, 0x86, 0x1e, 0x86, 0x1e,
|
||||
0x88, 0x1e, 0x88, 0x1e, 0x8a, 0x1e, 0x8a, 0x1e,
|
||||
0x8c, 0x1e, 0x8c, 0x1e, 0x8e, 0x1e, 0x8e, 0x1e,
|
||||
0x90, 0x1e, 0x90, 0x1e, 0x92, 0x1e, 0x92, 0x1e,
|
||||
0x94, 0x1e, 0x94, 0x1e, 0x96, 0x1e, 0x97, 0x1e,
|
||||
0x98, 0x1e, 0x99, 0x1e, 0x9a, 0x1e, 0x9b, 0x1e,
|
||||
0x9c, 0x1e, 0x9d, 0x1e, 0x9e, 0x1e, 0x9f, 0x1e,
|
||||
0xa0, 0x1e, 0xa0, 0x1e, 0xa2, 0x1e, 0xa2, 0x1e,
|
||||
0xa4, 0x1e, 0xa4, 0x1e, 0xa6, 0x1e, 0xa6, 0x1e,
|
||||
0xa8, 0x1e, 0xa8, 0x1e, 0xaa, 0x1e, 0xaa, 0x1e,
|
||||
0xac, 0x1e, 0xac, 0x1e, 0xae, 0x1e, 0xae, 0x1e,
|
||||
0xb0, 0x1e, 0xb0, 0x1e, 0xb2, 0x1e, 0xb2, 0x1e,
|
||||
0xb4, 0x1e, 0xb4, 0x1e, 0xb6, 0x1e, 0xb6, 0x1e,
|
||||
0xb8, 0x1e, 0xb8, 0x1e, 0xba, 0x1e, 0xba, 0x1e,
|
||||
0xbc, 0x1e, 0xbc, 0x1e, 0xbe, 0x1e, 0xbe, 0x1e,
|
||||
0xc0, 0x1e, 0xc0, 0x1e, 0xc2, 0x1e, 0xc2, 0x1e,
|
||||
0xc4, 0x1e, 0xc4, 0x1e, 0xc6, 0x1e, 0xc6, 0x1e,
|
||||
0xc8, 0x1e, 0xc8, 0x1e, 0xca, 0x1e, 0xca, 0x1e,
|
||||
0xcc, 0x1e, 0xcc, 0x1e, 0xce, 0x1e, 0xce, 0x1e,
|
||||
0xd0, 0x1e, 0xd0, 0x1e, 0xd2, 0x1e, 0xd2, 0x1e,
|
||||
0xd4, 0x1e, 0xd4, 0x1e, 0xd6, 0x1e, 0xd6, 0x1e,
|
||||
0xd8, 0x1e, 0xd8, 0x1e, 0xda, 0x1e, 0xda, 0x1e,
|
||||
0xdc, 0x1e, 0xdc, 0x1e, 0xde, 0x1e, 0xde, 0x1e,
|
||||
0xe0, 0x1e, 0xe0, 0x1e, 0xe2, 0x1e, 0xe2, 0x1e,
|
||||
0xe4, 0x1e, 0xe4, 0x1e, 0xe6, 0x1e, 0xe6, 0x1e,
|
||||
0xe8, 0x1e, 0xe8, 0x1e, 0xea, 0x1e, 0xea, 0x1e,
|
||||
0xec, 0x1e, 0xec, 0x1e, 0xee, 0x1e, 0xee, 0x1e,
|
||||
0xf0, 0x1e, 0xf0, 0x1e, 0xf2, 0x1e, 0xf2, 0x1e,
|
||||
0xf4, 0x1e, 0xf4, 0x1e, 0xf6, 0x1e, 0xf6, 0x1e,
|
||||
0xf8, 0x1e, 0xf8, 0x1e, 0xfa, 0x1e, 0xfb, 0x1e,
|
||||
0xfc, 0x1e, 0xfd, 0x1e, 0xfe, 0x1e, 0xff, 0x1e,
|
||||
0x08, 0x1f, 0x09, 0x1f, 0x0a, 0x1f, 0x0b, 0x1f,
|
||||
0x0c, 0x1f, 0x0d, 0x1f, 0x0e, 0x1f, 0x0f, 0x1f,
|
||||
0x08, 0x1f, 0x09, 0x1f, 0x0a, 0x1f, 0x0b, 0x1f,
|
||||
0x0c, 0x1f, 0x0d, 0x1f, 0x0e, 0x1f, 0x0f, 0x1f,
|
||||
0x18, 0x1f, 0x19, 0x1f, 0x1a, 0x1f, 0x1b, 0x1f,
|
||||
0x1c, 0x1f, 0x1d, 0x1f, 0x16, 0x1f, 0x17, 0x1f,
|
||||
0x18, 0x1f, 0x19, 0x1f, 0x1a, 0x1f, 0x1b, 0x1f,
|
||||
0x1c, 0x1f, 0x1d, 0x1f, 0x1e, 0x1f, 0x1f, 0x1f,
|
||||
0x28, 0x1f, 0x29, 0x1f, 0x2a, 0x1f, 0x2b, 0x1f,
|
||||
0x2c, 0x1f, 0x2d, 0x1f, 0x2e, 0x1f, 0x2f, 0x1f,
|
||||
0x28, 0x1f, 0x29, 0x1f, 0x2a, 0x1f, 0x2b, 0x1f,
|
||||
0x2c, 0x1f, 0x2d, 0x1f, 0x2e, 0x1f, 0x2f, 0x1f,
|
||||
0x38, 0x1f, 0x39, 0x1f, 0x3a, 0x1f, 0x3b, 0x1f,
|
||||
0x3c, 0x1f, 0x3d, 0x1f, 0x3e, 0x1f, 0x3f, 0x1f,
|
||||
0x38, 0x1f, 0x39, 0x1f, 0x3a, 0x1f, 0x3b, 0x1f,
|
||||
0x3c, 0x1f, 0x3d, 0x1f, 0x3e, 0x1f, 0x3f, 0x1f,
|
||||
0x48, 0x1f, 0x49, 0x1f, 0x4a, 0x1f, 0x4b, 0x1f,
|
||||
0x4c, 0x1f, 0x4d, 0x1f, 0x46, 0x1f, 0x47, 0x1f,
|
||||
0x48, 0x1f, 0x49, 0x1f, 0x4a, 0x1f, 0x4b, 0x1f,
|
||||
0x4c, 0x1f, 0x4d, 0x1f, 0x4e, 0x1f, 0x4f, 0x1f,
|
||||
0x50, 0x1f, 0x59, 0x1f, 0x52, 0x1f, 0x5b, 0x1f,
|
||||
0x54, 0x1f, 0x5d, 0x1f, 0x56, 0x1f, 0x5f, 0x1f,
|
||||
0x58, 0x1f, 0x59, 0x1f, 0x5a, 0x1f, 0x5b, 0x1f,
|
||||
0x5c, 0x1f, 0x5d, 0x1f, 0x5e, 0x1f, 0x5f, 0x1f,
|
||||
0x68, 0x1f, 0x69, 0x1f, 0x6a, 0x1f, 0x6b, 0x1f,
|
||||
0x6c, 0x1f, 0x6d, 0x1f, 0x6e, 0x1f, 0x6f, 0x1f,
|
||||
0x68, 0x1f, 0x69, 0x1f, 0x6a, 0x1f, 0x6b, 0x1f,
|
||||
0x6c, 0x1f, 0x6d, 0x1f, 0x6e, 0x1f, 0x6f, 0x1f,
|
||||
0xba, 0x1f, 0xbb, 0x1f, 0xc8, 0x1f, 0xc9, 0x1f,
|
||||
0xca, 0x1f, 0xcb, 0x1f, 0xda, 0x1f, 0xdb, 0x1f,
|
||||
0xf8, 0x1f, 0xf9, 0x1f, 0xea, 0x1f, 0xeb, 0x1f,
|
||||
0xfa, 0x1f, 0xfb, 0x1f, 0x7e, 0x1f, 0x7f, 0x1f,
|
||||
0x88, 0x1f, 0x89, 0x1f, 0x8a, 0x1f, 0x8b, 0x1f,
|
||||
0x8c, 0x1f, 0x8d, 0x1f, 0x8e, 0x1f, 0x8f, 0x1f,
|
||||
0x88, 0x1f, 0x89, 0x1f, 0x8a, 0x1f, 0x8b, 0x1f,
|
||||
0x8c, 0x1f, 0x8d, 0x1f, 0x8e, 0x1f, 0x8f, 0x1f,
|
||||
0x98, 0x1f, 0x99, 0x1f, 0x9a, 0x1f, 0x9b, 0x1f,
|
||||
0x9c, 0x1f, 0x9d, 0x1f, 0x9e, 0x1f, 0x9f, 0x1f,
|
||||
0x98, 0x1f, 0x99, 0x1f, 0x9a, 0x1f, 0x9b, 0x1f,
|
||||
0x9c, 0x1f, 0x9d, 0x1f, 0x9e, 0x1f, 0x9f, 0x1f,
|
||||
0xa8, 0x1f, 0xa9, 0x1f, 0xaa, 0x1f, 0xab, 0x1f,
|
||||
0xac, 0x1f, 0xad, 0x1f, 0xae, 0x1f, 0xaf, 0x1f,
|
||||
0xa8, 0x1f, 0xa9, 0x1f, 0xaa, 0x1f, 0xab, 0x1f,
|
||||
0xac, 0x1f, 0xad, 0x1f, 0xae, 0x1f, 0xaf, 0x1f,
|
||||
0xb8, 0x1f, 0xb9, 0x1f, 0xb2, 0x1f, 0xbc, 0x1f,
|
||||
0xb4, 0x1f, 0xb5, 0x1f, 0xb6, 0x1f, 0xb7, 0x1f,
|
||||
0xb8, 0x1f, 0xb9, 0x1f, 0xba, 0x1f, 0xbb, 0x1f,
|
||||
0xbc, 0x1f, 0xbd, 0x1f, 0xbe, 0x1f, 0xbf, 0x1f,
|
||||
0xc0, 0x1f, 0xc1, 0x1f, 0xc2, 0x1f, 0xc3, 0x1f,
|
||||
0xc4, 0x1f, 0xc5, 0x1f, 0xc6, 0x1f, 0xc7, 0x1f,
|
||||
0xc8, 0x1f, 0xc9, 0x1f, 0xca, 0x1f, 0xcb, 0x1f,
|
||||
0xc3, 0x1f, 0xcd, 0x1f, 0xce, 0x1f, 0xcf, 0x1f,
|
||||
0xd8, 0x1f, 0xd9, 0x1f, 0xd2, 0x1f, 0xd3, 0x1f,
|
||||
0xd4, 0x1f, 0xd5, 0x1f, 0xd6, 0x1f, 0xd7, 0x1f,
|
||||
0xd8, 0x1f, 0xd9, 0x1f, 0xda, 0x1f, 0xdb, 0x1f,
|
||||
0xdc, 0x1f, 0xdd, 0x1f, 0xde, 0x1f, 0xdf, 0x1f,
|
||||
0xe8, 0x1f, 0xe9, 0x1f, 0xe2, 0x1f, 0xe3, 0x1f,
|
||||
0xe4, 0x1f, 0xec, 0x1f, 0xe6, 0x1f, 0xe7, 0x1f,
|
||||
0xe8, 0x1f, 0xe9, 0x1f, 0xea, 0x1f, 0xeb, 0x1f,
|
||||
0xec, 0x1f, 0xed, 0x1f, 0xee, 0x1f, 0xef, 0x1f,
|
||||
0xf0, 0x1f, 0xf1, 0x1f, 0xf2, 0x1f, 0xf3, 0x1f,
|
||||
0xf4, 0x1f, 0xf5, 0x1f, 0xf6, 0x1f, 0xf7, 0x1f,
|
||||
0xf8, 0x1f, 0xf9, 0x1f, 0xfa, 0x1f, 0xfb, 0x1f,
|
||||
0xf3, 0x1f, 0xfd, 0x1f, 0xfe, 0x1f, 0xff, 0x1f,
|
||||
0x00, 0x20, 0x01, 0x20, 0x02, 0x20, 0x03, 0x20,
|
||||
0x04, 0x20, 0x05, 0x20, 0x06, 0x20, 0x07, 0x20,
|
||||
0x08, 0x20, 0x09, 0x20, 0x0a, 0x20, 0x0b, 0x20,
|
||||
0x0c, 0x20, 0x0d, 0x20, 0x0e, 0x20, 0x0f, 0x20,
|
||||
0x10, 0x20, 0x11, 0x20, 0x12, 0x20, 0x13, 0x20,
|
||||
0x14, 0x20, 0x15, 0x20, 0x16, 0x20, 0x17, 0x20,
|
||||
0x18, 0x20, 0x19, 0x20, 0x1a, 0x20, 0x1b, 0x20,
|
||||
0x1c, 0x20, 0x1d, 0x20, 0x1e, 0x20, 0x1f, 0x20,
|
||||
0x20, 0x20, 0x21, 0x20, 0x22, 0x20, 0x23, 0x20,
|
||||
0x24, 0x20, 0x25, 0x20, 0x26, 0x20, 0x27, 0x20,
|
||||
0x28, 0x20, 0x29, 0x20, 0x2a, 0x20, 0x2b, 0x20,
|
||||
0x2c, 0x20, 0x2d, 0x20, 0x2e, 0x20, 0x2f, 0x20,
|
||||
0x30, 0x20, 0x31, 0x20, 0x32, 0x20, 0x33, 0x20,
|
||||
0x34, 0x20, 0x35, 0x20, 0x36, 0x20, 0x37, 0x20,
|
||||
0x38, 0x20, 0x39, 0x20, 0x3a, 0x20, 0x3b, 0x20,
|
||||
0x3c, 0x20, 0x3d, 0x20, 0x3e, 0x20, 0x3f, 0x20,
|
||||
0x40, 0x20, 0x41, 0x20, 0x42, 0x20, 0x43, 0x20,
|
||||
0x44, 0x20, 0x45, 0x20, 0x46, 0x20, 0x47, 0x20,
|
||||
0x48, 0x20, 0x49, 0x20, 0x4a, 0x20, 0x4b, 0x20,
|
||||
0x4c, 0x20, 0x4d, 0x20, 0x4e, 0x20, 0x4f, 0x20,
|
||||
0x50, 0x20, 0x51, 0x20, 0x52, 0x20, 0x53, 0x20,
|
||||
0x54, 0x20, 0x55, 0x20, 0x56, 0x20, 0x57, 0x20,
|
||||
0x58, 0x20, 0x59, 0x20, 0x5a, 0x20, 0x5b, 0x20,
|
||||
0x5c, 0x20, 0x5d, 0x20, 0x5e, 0x20, 0x5f, 0x20,
|
||||
0x60, 0x20, 0x61, 0x20, 0x62, 0x20, 0x63, 0x20,
|
||||
0x64, 0x20, 0x65, 0x20, 0x66, 0x20, 0x67, 0x20,
|
||||
0x68, 0x20, 0x69, 0x20, 0x6a, 0x20, 0x6b, 0x20,
|
||||
0x6c, 0x20, 0x6d, 0x20, 0x6e, 0x20, 0x6f, 0x20,
|
||||
0x70, 0x20, 0x71, 0x20, 0x72, 0x20, 0x73, 0x20,
|
||||
0x74, 0x20, 0x75, 0x20, 0x76, 0x20, 0x77, 0x20,
|
||||
0x78, 0x20, 0x79, 0x20, 0x7a, 0x20, 0x7b, 0x20,
|
||||
0x7c, 0x20, 0x7d, 0x20, 0x7e, 0x20, 0x7f, 0x20,
|
||||
0x80, 0x20, 0x81, 0x20, 0x82, 0x20, 0x83, 0x20,
|
||||
0x84, 0x20, 0x85, 0x20, 0x86, 0x20, 0x87, 0x20,
|
||||
0x88, 0x20, 0x89, 0x20, 0x8a, 0x20, 0x8b, 0x20,
|
||||
0x8c, 0x20, 0x8d, 0x20, 0x8e, 0x20, 0x8f, 0x20,
|
||||
0x90, 0x20, 0x91, 0x20, 0x92, 0x20, 0x93, 0x20,
|
||||
0x94, 0x20, 0x95, 0x20, 0x96, 0x20, 0x97, 0x20,
|
||||
0x98, 0x20, 0x99, 0x20, 0x9a, 0x20, 0x9b, 0x20,
|
||||
0x9c, 0x20, 0x9d, 0x20, 0x9e, 0x20, 0x9f, 0x20,
|
||||
0xa0, 0x20, 0xa1, 0x20, 0xa2, 0x20, 0xa3, 0x20,
|
||||
0xa4, 0x20, 0xa5, 0x20, 0xa6, 0x20, 0xa7, 0x20,
|
||||
0xa8, 0x20, 0xa9, 0x20, 0xaa, 0x20, 0xab, 0x20,
|
||||
0xac, 0x20, 0xad, 0x20, 0xae, 0x20, 0xaf, 0x20,
|
||||
0xb0, 0x20, 0xb1, 0x20, 0xb2, 0x20, 0xb3, 0x20,
|
||||
0xb4, 0x20, 0xb5, 0x20, 0xb6, 0x20, 0xb7, 0x20,
|
||||
0xb8, 0x20, 0xb9, 0x20, 0xba, 0x20, 0xbb, 0x20,
|
||||
0xbc, 0x20, 0xbd, 0x20, 0xbe, 0x20, 0xbf, 0x20,
|
||||
0xc0, 0x20, 0xc1, 0x20, 0xc2, 0x20, 0xc3, 0x20,
|
||||
0xc4, 0x20, 0xc5, 0x20, 0xc6, 0x20, 0xc7, 0x20,
|
||||
0xc8, 0x20, 0xc9, 0x20, 0xca, 0x20, 0xcb, 0x20,
|
||||
0xcc, 0x20, 0xcd, 0x20, 0xce, 0x20, 0xcf, 0x20,
|
||||
0xd0, 0x20, 0xd1, 0x20, 0xd2, 0x20, 0xd3, 0x20,
|
||||
0xd4, 0x20, 0xd5, 0x20, 0xd6, 0x20, 0xd7, 0x20,
|
||||
0xd8, 0x20, 0xd9, 0x20, 0xda, 0x20, 0xdb, 0x20,
|
||||
0xdc, 0x20, 0xdd, 0x20, 0xde, 0x20, 0xdf, 0x20,
|
||||
0xe0, 0x20, 0xe1, 0x20, 0xe2, 0x20, 0xe3, 0x20,
|
||||
0xe4, 0x20, 0xe5, 0x20, 0xe6, 0x20, 0xe7, 0x20,
|
||||
0xe8, 0x20, 0xe9, 0x20, 0xea, 0x20, 0xeb, 0x20,
|
||||
0xec, 0x20, 0xed, 0x20, 0xee, 0x20, 0xef, 0x20,
|
||||
0xf0, 0x20, 0xf1, 0x20, 0xf2, 0x20, 0xf3, 0x20,
|
||||
0xf4, 0x20, 0xf5, 0x20, 0xf6, 0x20, 0xf7, 0x20,
|
||||
0xf8, 0x20, 0xf9, 0x20, 0xfa, 0x20, 0xfb, 0x20,
|
||||
0xfc, 0x20, 0xfd, 0x20, 0xfe, 0x20, 0xff, 0x20,
|
||||
0x00, 0x21, 0x01, 0x21, 0x02, 0x21, 0x03, 0x21,
|
||||
0x04, 0x21, 0x05, 0x21, 0x06, 0x21, 0x07, 0x21,
|
||||
0x08, 0x21, 0x09, 0x21, 0x0a, 0x21, 0x0b, 0x21,
|
||||
0x0c, 0x21, 0x0d, 0x21, 0x0e, 0x21, 0x0f, 0x21,
|
||||
0x10, 0x21, 0x11, 0x21, 0x12, 0x21, 0x13, 0x21,
|
||||
0x14, 0x21, 0x15, 0x21, 0x16, 0x21, 0x17, 0x21,
|
||||
0x18, 0x21, 0x19, 0x21, 0x1a, 0x21, 0x1b, 0x21,
|
||||
0x1c, 0x21, 0x1d, 0x21, 0x1e, 0x21, 0x1f, 0x21,
|
||||
0x20, 0x21, 0x21, 0x21, 0x22, 0x21, 0x23, 0x21,
|
||||
0x24, 0x21, 0x25, 0x21, 0x26, 0x21, 0x27, 0x21,
|
||||
0x28, 0x21, 0x29, 0x21, 0x2a, 0x21, 0x2b, 0x21,
|
||||
0x2c, 0x21, 0x2d, 0x21, 0x2e, 0x21, 0x2f, 0x21,
|
||||
0x30, 0x21, 0x31, 0x21, 0x32, 0x21, 0x33, 0x21,
|
||||
0x34, 0x21, 0x35, 0x21, 0x36, 0x21, 0x37, 0x21,
|
||||
0x38, 0x21, 0x39, 0x21, 0x3a, 0x21, 0x3b, 0x21,
|
||||
0x3c, 0x21, 0x3d, 0x21, 0x3e, 0x21, 0x3f, 0x21,
|
||||
0x40, 0x21, 0x41, 0x21, 0x42, 0x21, 0x43, 0x21,
|
||||
0x44, 0x21, 0x45, 0x21, 0x46, 0x21, 0x47, 0x21,
|
||||
0x48, 0x21, 0x49, 0x21, 0x4a, 0x21, 0x4b, 0x21,
|
||||
0x4c, 0x21, 0x4d, 0x21, 0x32, 0x21, 0x4f, 0x21,
|
||||
0x50, 0x21, 0x51, 0x21, 0x52, 0x21, 0x53, 0x21,
|
||||
0x54, 0x21, 0x55, 0x21, 0x56, 0x21, 0x57, 0x21,
|
||||
0x58, 0x21, 0x59, 0x21, 0x5a, 0x21, 0x5b, 0x21,
|
||||
0x5c, 0x21, 0x5d, 0x21, 0x5e, 0x21, 0x5f, 0x21,
|
||||
0x60, 0x21, 0x61, 0x21, 0x62, 0x21, 0x63, 0x21,
|
||||
0x64, 0x21, 0x65, 0x21, 0x66, 0x21, 0x67, 0x21,
|
||||
0x68, 0x21, 0x69, 0x21, 0x6a, 0x21, 0x6b, 0x21,
|
||||
0x6c, 0x21, 0x6d, 0x21, 0x6e, 0x21, 0x6f, 0x21,
|
||||
0x60, 0x21, 0x61, 0x21, 0x62, 0x21, 0x63, 0x21,
|
||||
0x64, 0x21, 0x65, 0x21, 0x66, 0x21, 0x67, 0x21,
|
||||
0x68, 0x21, 0x69, 0x21, 0x6a, 0x21, 0x6b, 0x21,
|
||||
0x6c, 0x21, 0x6d, 0x21, 0x6e, 0x21, 0x6f, 0x21,
|
||||
0x80, 0x21, 0x81, 0x21, 0x82, 0x21, 0x83, 0x21,
|
||||
0x83, 0x21, 0xff, 0xff, 0x4b, 0x03, 0xb6, 0x24,
|
||||
0xb7, 0x24, 0xb8, 0x24, 0xb9, 0x24, 0xba, 0x24,
|
||||
0xbb, 0x24, 0xbc, 0x24, 0xbd, 0x24, 0xbe, 0x24,
|
||||
0xbf, 0x24, 0xc0, 0x24, 0xc1, 0x24, 0xc2, 0x24,
|
||||
0xc3, 0x24, 0xc4, 0x24, 0xc5, 0x24, 0xc6, 0x24,
|
||||
0xc7, 0x24, 0xc8, 0x24, 0xc9, 0x24, 0xca, 0x24,
|
||||
0xcb, 0x24, 0xcc, 0x24, 0xcd, 0x24, 0xce, 0x24,
|
||||
0xcf, 0x24, 0xff, 0xff, 0x46, 0x07, 0x00, 0x2c,
|
||||
0x01, 0x2c, 0x02, 0x2c, 0x03, 0x2c, 0x04, 0x2c,
|
||||
0x05, 0x2c, 0x06, 0x2c, 0x07, 0x2c, 0x08, 0x2c,
|
||||
0x09, 0x2c, 0x0a, 0x2c, 0x0b, 0x2c, 0x0c, 0x2c,
|
||||
0x0d, 0x2c, 0x0e, 0x2c, 0x0f, 0x2c, 0x10, 0x2c,
|
||||
0x11, 0x2c, 0x12, 0x2c, 0x13, 0x2c, 0x14, 0x2c,
|
||||
0x15, 0x2c, 0x16, 0x2c, 0x17, 0x2c, 0x18, 0x2c,
|
||||
0x19, 0x2c, 0x1a, 0x2c, 0x1b, 0x2c, 0x1c, 0x2c,
|
||||
0x1d, 0x2c, 0x1e, 0x2c, 0x1f, 0x2c, 0x20, 0x2c,
|
||||
0x21, 0x2c, 0x22, 0x2c, 0x23, 0x2c, 0x24, 0x2c,
|
||||
0x25, 0x2c, 0x26, 0x2c, 0x27, 0x2c, 0x28, 0x2c,
|
||||
0x29, 0x2c, 0x2a, 0x2c, 0x2b, 0x2c, 0x2c, 0x2c,
|
||||
0x2d, 0x2c, 0x2e, 0x2c, 0x5f, 0x2c, 0x60, 0x2c,
|
||||
0x60, 0x2c, 0x62, 0x2c, 0x63, 0x2c, 0x64, 0x2c,
|
||||
0x65, 0x2c, 0x66, 0x2c, 0x67, 0x2c, 0x67, 0x2c,
|
||||
0x69, 0x2c, 0x69, 0x2c, 0x6b, 0x2c, 0x6b, 0x2c,
|
||||
0x6d, 0x2c, 0x6e, 0x2c, 0x6f, 0x2c, 0x70, 0x2c,
|
||||
0x71, 0x2c, 0x72, 0x2c, 0x73, 0x2c, 0x74, 0x2c,
|
||||
0x75, 0x2c, 0x75, 0x2c, 0x77, 0x2c, 0x78, 0x2c,
|
||||
0x79, 0x2c, 0x7a, 0x2c, 0x7b, 0x2c, 0x7c, 0x2c,
|
||||
0x7d, 0x2c, 0x7e, 0x2c, 0x7f, 0x2c, 0x80, 0x2c,
|
||||
0x80, 0x2c, 0x82, 0x2c, 0x82, 0x2c, 0x84, 0x2c,
|
||||
0x84, 0x2c, 0x86, 0x2c, 0x86, 0x2c, 0x88, 0x2c,
|
||||
0x88, 0x2c, 0x8a, 0x2c, 0x8a, 0x2c, 0x8c, 0x2c,
|
||||
0x8c, 0x2c, 0x8e, 0x2c, 0x8e, 0x2c, 0x90, 0x2c,
|
||||
0x90, 0x2c, 0x92, 0x2c, 0x92, 0x2c, 0x94, 0x2c,
|
||||
0x94, 0x2c, 0x96, 0x2c, 0x96, 0x2c, 0x98, 0x2c,
|
||||
0x98, 0x2c, 0x9a, 0x2c, 0x9a, 0x2c, 0x9c, 0x2c,
|
||||
0x9c, 0x2c, 0x9e, 0x2c, 0x9e, 0x2c, 0xa0, 0x2c,
|
||||
0xa0, 0x2c, 0xa2, 0x2c, 0xa2, 0x2c, 0xa4, 0x2c,
|
||||
0xa4, 0x2c, 0xa6, 0x2c, 0xa6, 0x2c, 0xa8, 0x2c,
|
||||
0xa8, 0x2c, 0xaa, 0x2c, 0xaa, 0x2c, 0xac, 0x2c,
|
||||
0xac, 0x2c, 0xae, 0x2c, 0xae, 0x2c, 0xb0, 0x2c,
|
||||
0xb0, 0x2c, 0xb2, 0x2c, 0xb2, 0x2c, 0xb4, 0x2c,
|
||||
0xb4, 0x2c, 0xb6, 0x2c, 0xb6, 0x2c, 0xb8, 0x2c,
|
||||
0xb8, 0x2c, 0xba, 0x2c, 0xba, 0x2c, 0xbc, 0x2c,
|
||||
0xbc, 0x2c, 0xbe, 0x2c, 0xbe, 0x2c, 0xc0, 0x2c,
|
||||
0xc0, 0x2c, 0xc2, 0x2c, 0xc2, 0x2c, 0xc4, 0x2c,
|
||||
0xc4, 0x2c, 0xc6, 0x2c, 0xc6, 0x2c, 0xc8, 0x2c,
|
||||
0xc8, 0x2c, 0xca, 0x2c, 0xca, 0x2c, 0xcc, 0x2c,
|
||||
0xcc, 0x2c, 0xce, 0x2c, 0xce, 0x2c, 0xd0, 0x2c,
|
||||
0xd0, 0x2c, 0xd2, 0x2c, 0xd2, 0x2c, 0xd4, 0x2c,
|
||||
0xd4, 0x2c, 0xd6, 0x2c, 0xd6, 0x2c, 0xd8, 0x2c,
|
||||
0xd8, 0x2c, 0xda, 0x2c, 0xda, 0x2c, 0xdc, 0x2c,
|
||||
0xdc, 0x2c, 0xde, 0x2c, 0xde, 0x2c, 0xe0, 0x2c,
|
||||
0xe0, 0x2c, 0xe2, 0x2c, 0xe2, 0x2c, 0xe4, 0x2c,
|
||||
0xe5, 0x2c, 0xe6, 0x2c, 0xe7, 0x2c, 0xe8, 0x2c,
|
||||
0xe9, 0x2c, 0xea, 0x2c, 0xeb, 0x2c, 0xec, 0x2c,
|
||||
0xed, 0x2c, 0xee, 0x2c, 0xef, 0x2c, 0xf0, 0x2c,
|
||||
0xf1, 0x2c, 0xf2, 0x2c, 0xf3, 0x2c, 0xf4, 0x2c,
|
||||
0xf5, 0x2c, 0xf6, 0x2c, 0xf7, 0x2c, 0xf8, 0x2c,
|
||||
0xf9, 0x2c, 0xfa, 0x2c, 0xfb, 0x2c, 0xfc, 0x2c,
|
||||
0xfd, 0x2c, 0xfe, 0x2c, 0xff, 0x2c, 0xa0, 0x10,
|
||||
0xa1, 0x10, 0xa2, 0x10, 0xa3, 0x10, 0xa4, 0x10,
|
||||
0xa5, 0x10, 0xa6, 0x10, 0xa7, 0x10, 0xa8, 0x10,
|
||||
0xa9, 0x10, 0xaa, 0x10, 0xab, 0x10, 0xac, 0x10,
|
||||
0xad, 0x10, 0xae, 0x10, 0xaf, 0x10, 0xb0, 0x10,
|
||||
0xb1, 0x10, 0xb2, 0x10, 0xb3, 0x10, 0xb4, 0x10,
|
||||
0xb5, 0x10, 0xb6, 0x10, 0xb7, 0x10, 0xb8, 0x10,
|
||||
0xb9, 0x10, 0xba, 0x10, 0xbb, 0x10, 0xbc, 0x10,
|
||||
0xbd, 0x10, 0xbe, 0x10, 0xbf, 0x10, 0xc0, 0x10,
|
||||
0xc1, 0x10, 0xc2, 0x10, 0xc3, 0x10, 0xc4, 0x10,
|
||||
0xc5, 0x10, 0xff, 0xff, 0x1b, 0xd2, 0x21, 0xff,
|
||||
0x22, 0xff, 0x23, 0xff, 0x24, 0xff, 0x25, 0xff,
|
||||
0x26, 0xff, 0x27, 0xff, 0x28, 0xff, 0x29, 0xff,
|
||||
0x2a, 0xff, 0x2b, 0xff, 0x2c, 0xff, 0x2d, 0xff,
|
||||
0x2e, 0xff, 0x2f, 0xff, 0x30, 0xff, 0x31, 0xff,
|
||||
0x32, 0xff, 0x33, 0xff, 0x34, 0xff, 0x35, 0xff,
|
||||
0x36, 0xff, 0x37, 0xff, 0x38, 0xff, 0x39, 0xff,
|
||||
0x3a, 0xff, 0x5b, 0xff, 0x5c, 0xff, 0x5d, 0xff,
|
||||
0x5e, 0xff, 0x5f, 0xff, 0x60, 0xff, 0x61, 0xff,
|
||||
0x62, 0xff, 0x63, 0xff, 0x64, 0xff, 0x65, 0xff,
|
||||
0x66, 0xff, 0x67, 0xff, 0x68, 0xff, 0x69, 0xff,
|
||||
0x6a, 0xff, 0x6b, 0xff, 0x6c, 0xff, 0x6d, 0xff,
|
||||
0x6e, 0xff, 0x6f, 0xff, 0x70, 0xff, 0x71, 0xff,
|
||||
0x72, 0xff, 0x73, 0xff, 0x74, 0xff, 0x75, 0xff,
|
||||
0x76, 0xff, 0x77, 0xff, 0x78, 0xff, 0x79, 0xff,
|
||||
0x7a, 0xff, 0x7b, 0xff, 0x7c, 0xff, 0x7d, 0xff,
|
||||
0x7e, 0xff, 0x7f, 0xff, 0x80, 0xff, 0x81, 0xff,
|
||||
0x82, 0xff, 0x83, 0xff, 0x84, 0xff, 0x85, 0xff,
|
||||
0x86, 0xff, 0x87, 0xff, 0x88, 0xff, 0x89, 0xff,
|
||||
0x8a, 0xff, 0x8b, 0xff, 0x8c, 0xff, 0x8d, 0xff,
|
||||
0x8e, 0xff, 0x8f, 0xff, 0x90, 0xff, 0x91, 0xff,
|
||||
0x92, 0xff, 0x93, 0xff, 0x94, 0xff, 0x95, 0xff,
|
||||
0x96, 0xff, 0x97, 0xff, 0x98, 0xff, 0x99, 0xff,
|
||||
0x9a, 0xff, 0x9b, 0xff, 0x9c, 0xff, 0x9d, 0xff,
|
||||
0x9e, 0xff, 0x9f, 0xff, 0xa0, 0xff, 0xa1, 0xff,
|
||||
0xa2, 0xff, 0xa3, 0xff, 0xa4, 0xff, 0xa5, 0xff,
|
||||
0xa6, 0xff, 0xa7, 0xff, 0xa8, 0xff, 0xa9, 0xff,
|
||||
0xaa, 0xff, 0xab, 0xff, 0xac, 0xff, 0xad, 0xff,
|
||||
0xae, 0xff, 0xaf, 0xff, 0xb0, 0xff, 0xb1, 0xff,
|
||||
0xb2, 0xff, 0xb3, 0xff, 0xb4, 0xff, 0xb5, 0xff,
|
||||
0xb6, 0xff, 0xb7, 0xff, 0xb8, 0xff, 0xb9, 0xff,
|
||||
0xba, 0xff, 0xbb, 0xff, 0xbc, 0xff, 0xbd, 0xff,
|
||||
0xbe, 0xff, 0xbf, 0xff, 0xc0, 0xff, 0xc1, 0xff,
|
||||
0xc2, 0xff, 0xc3, 0xff, 0xc4, 0xff, 0xc5, 0xff,
|
||||
0xc6, 0xff, 0xc7, 0xff, 0xc8, 0xff, 0xc9, 0xff,
|
||||
0xca, 0xff, 0xcb, 0xff, 0xcc, 0xff, 0xcd, 0xff,
|
||||
0xce, 0xff, 0xcf, 0xff, 0xd0, 0xff, 0xd1, 0xff,
|
||||
0xd2, 0xff, 0xd3, 0xff, 0xd4, 0xff, 0xd5, 0xff,
|
||||
0xd6, 0xff, 0xd7, 0xff, 0xd8, 0xff, 0xd9, 0xff,
|
||||
0xda, 0xff, 0xdb, 0xff, 0xdc, 0xff, 0xdd, 0xff,
|
||||
0xde, 0xff, 0xdf, 0xff, 0xe0, 0xff, 0xe1, 0xff,
|
||||
0xe2, 0xff, 0xe3, 0xff, 0xe4, 0xff, 0xe5, 0xff,
|
||||
0xe6, 0xff, 0xe7, 0xff, 0xe8, 0xff, 0xe9, 0xff,
|
||||
0xea, 0xff, 0xeb, 0xff, 0xec, 0xff, 0xed, 0xff,
|
||||
0xee, 0xff, 0xef, 0xff, 0xf0, 0xff, 0xf1, 0xff,
|
||||
0xf2, 0xff, 0xf3, 0xff, 0xf4, 0xff, 0xf5, 0xff,
|
||||
0xf6, 0xff, 0xf7, 0xff, 0xf8, 0xff, 0xf9, 0xff,
|
||||
0xfa, 0xff, 0xfb, 0xff, 0xfc, 0xff, 0xfd, 0xff,
|
||||
0xfe, 0xff, 0xff, 0xff
|
||||
};
|
||||
30
LinuxGUI/Ventoy2Disk/Lib/exfat/src/mkfs/uctc.h
Normal file
30
LinuxGUI/Ventoy2Disk/Lib/exfat/src/mkfs/uctc.h
Normal file
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
uctc.h (30.10.10)
|
||||
Upper Case Table declaration.
|
||||
|
||||
Free exFAT implementation.
|
||||
Copyright (C) 2011-2018 Andrew Nayenko
|
||||
|
||||
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.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef MKFS_UCTC_H_INCLUDED
|
||||
#define MKFS_UCTC_H_INCLUDED
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
extern uint8_t upcase_table[5836];
|
||||
|
||||
#endif /* ifndef MKFS_UCTC_H_INCLUDED */
|
||||
148
LinuxGUI/Ventoy2Disk/Lib/exfat/src/mkfs/vbr.c
Normal file
148
LinuxGUI/Ventoy2Disk/Lib/exfat/src/mkfs/vbr.c
Normal file
@@ -0,0 +1,148 @@
|
||||
/*
|
||||
vbr.c (09.11.10)
|
||||
Volume Boot Record creation code.
|
||||
|
||||
Free exFAT implementation.
|
||||
Copyright (C) 2011-2018 Andrew Nayenko
|
||||
|
||||
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.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "vbr.h"
|
||||
#include "fat.h"
|
||||
#include "cbm.h"
|
||||
#include "uct.h"
|
||||
#include "rootdir.h"
|
||||
#include <string.h>
|
||||
|
||||
static off_t vbr_alignment(void)
|
||||
{
|
||||
return get_sector_size();
|
||||
}
|
||||
|
||||
static off_t vbr_size(void)
|
||||
{
|
||||
return 12 * get_sector_size();
|
||||
}
|
||||
|
||||
static void init_sb(struct exfat_super_block* sb)
|
||||
{
|
||||
uint32_t clusters_max;
|
||||
uint32_t fat_sectors;
|
||||
|
||||
clusters_max = get_volume_size() / get_cluster_size();
|
||||
fat_sectors = DIV_ROUND_UP((off_t) clusters_max * sizeof(cluster_t),
|
||||
get_sector_size());
|
||||
|
||||
memset(sb, 0, sizeof(struct exfat_super_block));
|
||||
sb->jump[0] = 0xeb;
|
||||
sb->jump[1] = 0x76;
|
||||
sb->jump[2] = 0x90;
|
||||
memcpy(sb->oem_name, "EXFAT ", sizeof(sb->oem_name));
|
||||
sb->sector_start = cpu_to_le64(get_first_sector());
|
||||
sb->sector_count = cpu_to_le64(get_volume_size() / get_sector_size());
|
||||
sb->fat_sector_start = cpu_to_le32(
|
||||
fat.get_alignment() / get_sector_size());
|
||||
sb->fat_sector_count = cpu_to_le32(ROUND_UP(
|
||||
le32_to_cpu(sb->fat_sector_start) + fat_sectors,
|
||||
1 << get_spc_bits()) -
|
||||
le32_to_cpu(sb->fat_sector_start));
|
||||
sb->cluster_sector_start = cpu_to_le32(
|
||||
get_position(&cbm) / get_sector_size());
|
||||
sb->cluster_count = cpu_to_le32(clusters_max -
|
||||
((le32_to_cpu(sb->fat_sector_start) +
|
||||
le32_to_cpu(sb->fat_sector_count)) >> get_spc_bits()));
|
||||
sb->rootdir_cluster = cpu_to_le32(
|
||||
(get_position(&rootdir) - get_position(&cbm)) / get_cluster_size()
|
||||
+ EXFAT_FIRST_DATA_CLUSTER);
|
||||
sb->volume_serial = cpu_to_le32(get_volume_serial());
|
||||
sb->version.major = 1;
|
||||
sb->version.minor = 0;
|
||||
sb->volume_state = cpu_to_le16(0);
|
||||
sb->sector_bits = get_sector_bits();
|
||||
sb->spc_bits = get_spc_bits();
|
||||
sb->fat_count = 1;
|
||||
sb->drive_no = 0x80;
|
||||
sb->allocated_percent = 0;
|
||||
sb->boot_signature = cpu_to_le16(0xaa55);
|
||||
}
|
||||
|
||||
static int vbr_write(struct exfat_dev* dev)
|
||||
{
|
||||
struct exfat_super_block sb;
|
||||
uint32_t checksum;
|
||||
le32_t* sector = malloc(get_sector_size());
|
||||
size_t i;
|
||||
|
||||
if (sector == NULL)
|
||||
{
|
||||
exfat_error("failed to allocate sector-sized block of memory");
|
||||
return 1;
|
||||
}
|
||||
|
||||
init_sb(&sb);
|
||||
if (exfat_write(dev, &sb, sizeof(struct exfat_super_block)) < 0)
|
||||
{
|
||||
free(sector);
|
||||
exfat_error("failed to write super block sector");
|
||||
return 1;
|
||||
}
|
||||
checksum = exfat_vbr_start_checksum(&sb, sizeof(struct exfat_super_block));
|
||||
|
||||
memset(sector, 0, get_sector_size());
|
||||
sector[get_sector_size() / sizeof(sector[0]) - 1] =
|
||||
cpu_to_le32(0xaa550000);
|
||||
for (i = 0; i < 8; i++)
|
||||
{
|
||||
if (exfat_write(dev, sector, get_sector_size()) < 0)
|
||||
{
|
||||
free(sector);
|
||||
exfat_error("failed to write a sector with boot signature");
|
||||
return 1;
|
||||
}
|
||||
checksum = exfat_vbr_add_checksum(sector, get_sector_size(), checksum);
|
||||
}
|
||||
|
||||
memset(sector, 0, get_sector_size());
|
||||
for (i = 0; i < 2; i++)
|
||||
{
|
||||
if (exfat_write(dev, sector, get_sector_size()) < 0)
|
||||
{
|
||||
free(sector);
|
||||
exfat_error("failed to write an empty sector");
|
||||
return 1;
|
||||
}
|
||||
checksum = exfat_vbr_add_checksum(sector, get_sector_size(), checksum);
|
||||
}
|
||||
|
||||
for (i = 0; i < get_sector_size() / sizeof(sector[0]); i++)
|
||||
sector[i] = cpu_to_le32(checksum);
|
||||
if (exfat_write(dev, sector, get_sector_size()) < 0)
|
||||
{
|
||||
free(sector);
|
||||
exfat_error("failed to write checksum sector");
|
||||
return 1;
|
||||
}
|
||||
|
||||
free(sector);
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct fs_object vbr =
|
||||
{
|
||||
.get_alignment = vbr_alignment,
|
||||
.get_size = vbr_size,
|
||||
.write = vbr_write,
|
||||
};
|
||||
30
LinuxGUI/Ventoy2Disk/Lib/exfat/src/mkfs/vbr.h
Normal file
30
LinuxGUI/Ventoy2Disk/Lib/exfat/src/mkfs/vbr.h
Normal file
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
vbr.h (09.11.10)
|
||||
Volume Boot Record creation code.
|
||||
|
||||
Free exFAT implementation.
|
||||
Copyright (C) 2011-2018 Andrew Nayenko
|
||||
|
||||
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.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef MKFS_VBR_H_INCLUDED
|
||||
#define MKFS_VBR_H_INCLUDED
|
||||
|
||||
#include "mkexfat.h"
|
||||
|
||||
extern const struct fs_object vbr;
|
||||
|
||||
#endif /* ifndef MKFS_VBR_H_INCLUDED */
|
||||
30
LinuxGUI/Ventoy2Disk/Lib/fat_io_lib/buildlib.sh
Normal file
30
LinuxGUI/Ventoy2Disk/Lib/fat_io_lib/buildlib.sh
Normal file
@@ -0,0 +1,30 @@
|
||||
#!/bin/sh
|
||||
|
||||
rm -rf include
|
||||
rm -rf lib
|
||||
|
||||
cd release
|
||||
gcc -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
|
||||
|
||||
|
||||
cd -
|
||||
|
||||
|
||||
mkdir lib
|
||||
mkdir include
|
||||
|
||||
mv release/*.a lib/
|
||||
cp -a release/*.h include/
|
||||
|
||||
133
LinuxGUI/Ventoy2Disk/Lib/fat_io_lib/include/fat_access.h
Normal file
133
LinuxGUI/Ventoy2Disk/Lib/fat_io_lib/include/fat_access.h
Normal file
@@ -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
|
||||
13
LinuxGUI/Ventoy2Disk/Lib/fat_io_lib/include/fat_cache.h
Normal file
13
LinuxGUI/Ventoy2Disk/Lib/fat_io_lib/include/fat_cache.h
Normal file
@@ -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
|
||||
128
LinuxGUI/Ventoy2Disk/Lib/fat_io_lib/include/fat_defs.h
Normal file
128
LinuxGUI/Ventoy2Disk/Lib/fat_io_lib/include/fat_defs.h
Normal file
@@ -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
|
||||
146
LinuxGUI/Ventoy2Disk/Lib/fat_io_lib/include/fat_filelib.h
Normal file
146
LinuxGUI/Ventoy2Disk/Lib/fat_io_lib/include/fat_filelib.h
Normal file
@@ -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
|
||||
15
LinuxGUI/Ventoy2Disk/Lib/fat_io_lib/include/fat_format.h
Normal file
15
LinuxGUI/Ventoy2Disk/Lib/fat_io_lib/include/fat_format.h
Normal file
@@ -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
|
||||
161
LinuxGUI/Ventoy2Disk/Lib/fat_io_lib/include/fat_list.h
Normal file
161
LinuxGUI/Ventoy2Disk/Lib/fat_io_lib/include/fat_list.h
Normal file
@@ -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
|
||||
|
||||
63
LinuxGUI/Ventoy2Disk/Lib/fat_io_lib/include/fat_misc.h
Normal file
63
LinuxGUI/Ventoy2Disk/Lib/fat_io_lib/include/fat_misc.h
Normal file
@@ -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
|
||||
90
LinuxGUI/Ventoy2Disk/Lib/fat_io_lib/include/fat_opts.h
Normal file
90
LinuxGUI/Ventoy2Disk/Lib/fat_io_lib/include/fat_opts.h
Normal file
@@ -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
|
||||
20
LinuxGUI/Ventoy2Disk/Lib/fat_io_lib/include/fat_string.h
Normal file
20
LinuxGUI/Ventoy2Disk/Lib/fat_io_lib/include/fat_string.h
Normal file
@@ -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
|
||||
20
LinuxGUI/Ventoy2Disk/Lib/fat_io_lib/include/fat_table.h
Normal file
20
LinuxGUI/Ventoy2Disk/Lib/fat_io_lib/include/fat_table.h
Normal file
@@ -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
|
||||
69
LinuxGUI/Ventoy2Disk/Lib/fat_io_lib/include/fat_types.h
Normal file
69
LinuxGUI/Ventoy2Disk/Lib/fat_io_lib/include/fat_types.h
Normal file
@@ -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
|
||||
14
LinuxGUI/Ventoy2Disk/Lib/fat_io_lib/include/fat_write.h
Normal file
14
LinuxGUI/Ventoy2Disk/Lib/fat_io_lib/include/fat_write.h
Normal file
@@ -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
|
||||
BIN
LinuxGUI/Ventoy2Disk/Lib/fat_io_lib/lib/libfat_io_32.a
Normal file
BIN
LinuxGUI/Ventoy2Disk/Lib/fat_io_lib/lib/libfat_io_32.a
Normal file
Binary file not shown.
BIN
LinuxGUI/Ventoy2Disk/Lib/fat_io_lib/lib/libfat_io_64.a
Normal file
BIN
LinuxGUI/Ventoy2Disk/Lib/fat_io_lib/lib/libfat_io_64.a
Normal file
Binary file not shown.
BIN
LinuxGUI/Ventoy2Disk/Lib/fat_io_lib/lib/libfat_io_aa64.a
Normal file
BIN
LinuxGUI/Ventoy2Disk/Lib/fat_io_lib/lib/libfat_io_aa64.a
Normal file
Binary file not shown.
22
LinuxGUI/Ventoy2Disk/Lib/fat_io_lib/release/API.txt
Normal file
22
LinuxGUI/Ventoy2Disk/Lib/fat_io_lib/release/API.txt
Normal file
@@ -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 <20>locked<65> 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.
|
||||
345
LinuxGUI/Ventoy2Disk/Lib/fat_io_lib/release/COPYRIGHT.txt
Normal file
345
LinuxGUI/Ventoy2Disk/Lib/fat_io_lib/release/COPYRIGHT.txt
Normal file
@@ -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
|
||||
24
LinuxGUI/Ventoy2Disk/Lib/fat_io_lib/release/History.txt
Normal file
24
LinuxGUI/Ventoy2Disk/Lib/fat_io_lib/release/History.txt
Normal file
@@ -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 <20> Massive read + write performance improvements.
|
||||
V2.6.5 <20> Bug fixes for big endian systems.
|
||||
V2.6.4 <20> Further bug fixes and performance improvements for write operations.
|
||||
V2.6.3 <20> 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.
|
||||
10
LinuxGUI/Ventoy2Disk/Lib/fat_io_lib/release/License.txt
Normal file
10
LinuxGUI/Ventoy2Disk/Lib/fat_io_lib/release/License.txt
Normal file
@@ -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)
|
||||
|
||||
|
||||
|
||||
87
LinuxGUI/Ventoy2Disk/Lib/fat_io_lib/release/example.c
Normal file
87
LinuxGUI/Ventoy2Disk/Lib/fat_io_lib/release/example.c
Normal file
@@ -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();
|
||||
}
|
||||
904
LinuxGUI/Ventoy2Disk/Lib/fat_io_lib/release/fat_access.c
Normal file
904
LinuxGUI/Ventoy2Disk/Lib/fat_io_lib/release/fat_access.c
Normal file
@@ -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
|
||||
133
LinuxGUI/Ventoy2Disk/Lib/fat_io_lib/release/fat_access.h
Normal file
133
LinuxGUI/Ventoy2Disk/Lib/fat_io_lib/release/fat_access.h
Normal file
@@ -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
|
||||
91
LinuxGUI/Ventoy2Disk/Lib/fat_io_lib/release/fat_cache.c
Normal file
91
LinuxGUI/Ventoy2Disk/Lib/fat_io_lib/release/fat_cache.c
Normal file
@@ -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;
|
||||
}
|
||||
13
LinuxGUI/Ventoy2Disk/Lib/fat_io_lib/release/fat_cache.h
Normal file
13
LinuxGUI/Ventoy2Disk/Lib/fat_io_lib/release/fat_cache.h
Normal file
@@ -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
|
||||
128
LinuxGUI/Ventoy2Disk/Lib/fat_io_lib/release/fat_defs.h
Normal file
128
LinuxGUI/Ventoy2Disk/Lib/fat_io_lib/release/fat_defs.h
Normal file
@@ -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
|
||||
1603
LinuxGUI/Ventoy2Disk/Lib/fat_io_lib/release/fat_filelib.c
Normal file
1603
LinuxGUI/Ventoy2Disk/Lib/fat_io_lib/release/fat_filelib.c
Normal file
File diff suppressed because it is too large
Load Diff
146
LinuxGUI/Ventoy2Disk/Lib/fat_io_lib/release/fat_filelib.h
Normal file
146
LinuxGUI/Ventoy2Disk/Lib/fat_io_lib/release/fat_filelib.h
Normal file
@@ -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
|
||||
532
LinuxGUI/Ventoy2Disk/Lib/fat_io_lib/release/fat_format.c
Normal file
532
LinuxGUI/Ventoy2Disk/Lib/fat_io_lib/release/fat_format.c
Normal file
@@ -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*/
|
||||
15
LinuxGUI/Ventoy2Disk/Lib/fat_io_lib/release/fat_format.h
Normal file
15
LinuxGUI/Ventoy2Disk/Lib/fat_io_lib/release/fat_format.h
Normal file
@@ -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
|
||||
161
LinuxGUI/Ventoy2Disk/Lib/fat_io_lib/release/fat_list.h
Normal file
161
LinuxGUI/Ventoy2Disk/Lib/fat_io_lib/release/fat_list.h
Normal file
@@ -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
|
||||
|
||||
505
LinuxGUI/Ventoy2Disk/Lib/fat_io_lib/release/fat_misc.c
Normal file
505
LinuxGUI/Ventoy2Disk/Lib/fat_io_lib/release/fat_misc.c
Normal file
@@ -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
|
||||
63
LinuxGUI/Ventoy2Disk/Lib/fat_io_lib/release/fat_misc.h
Normal file
63
LinuxGUI/Ventoy2Disk/Lib/fat_io_lib/release/fat_misc.h
Normal file
@@ -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
|
||||
90
LinuxGUI/Ventoy2Disk/Lib/fat_io_lib/release/fat_opts.h
Normal file
90
LinuxGUI/Ventoy2Disk/Lib/fat_io_lib/release/fat_opts.h
Normal file
@@ -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
|
||||
514
LinuxGUI/Ventoy2Disk/Lib/fat_io_lib/release/fat_string.c
Normal file
514
LinuxGUI/Ventoy2Disk/Lib/fat_io_lib/release/fat_string.c
Normal file
@@ -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
|
||||
20
LinuxGUI/Ventoy2Disk/Lib/fat_io_lib/release/fat_string.h
Normal file
20
LinuxGUI/Ventoy2Disk/Lib/fat_io_lib/release/fat_string.h
Normal file
@@ -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
|
||||
478
LinuxGUI/Ventoy2Disk/Lib/fat_io_lib/release/fat_table.c
Normal file
478
LinuxGUI/Ventoy2Disk/Lib/fat_io_lib/release/fat_table.c
Normal file
@@ -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;
|
||||
}
|
||||
20
LinuxGUI/Ventoy2Disk/Lib/fat_io_lib/release/fat_table.h
Normal file
20
LinuxGUI/Ventoy2Disk/Lib/fat_io_lib/release/fat_table.h
Normal file
@@ -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
|
||||
69
LinuxGUI/Ventoy2Disk/Lib/fat_io_lib/release/fat_types.h
Normal file
69
LinuxGUI/Ventoy2Disk/Lib/fat_io_lib/release/fat_types.h
Normal file
@@ -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
|
||||
373
LinuxGUI/Ventoy2Disk/Lib/fat_io_lib/release/fat_write.c
Normal file
373
LinuxGUI/Ventoy2Disk/Lib/fat_io_lib/release/fat_write.c
Normal file
@@ -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
|
||||
14
LinuxGUI/Ventoy2Disk/Lib/fat_io_lib/release/fat_write.h
Normal file
14
LinuxGUI/Ventoy2Disk/Lib/fat_io_lib/release/fat_write.h
Normal file
@@ -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
|
||||
1
LinuxGUI/Ventoy2Disk/Lib/fat_io_lib/release/version.txt
Normal file
1
LinuxGUI/Ventoy2Disk/Lib/fat_io_lib/release/version.txt
Normal file
@@ -0,0 +1 @@
|
||||
2.6.11
|
||||
46
LinuxGUI/Ventoy2Disk/Lib/libhttp/buildlib.sh
Normal file
46
LinuxGUI/Ventoy2Disk/Lib/libhttp/buildlib.sh
Normal file
@@ -0,0 +1,46 @@
|
||||
#!/bin/sh
|
||||
|
||||
# https://github.com/lammertb/libhttp/archive/v1.8.tar.gz
|
||||
|
||||
|
||||
# rm -rf include
|
||||
# rm -rf lib
|
||||
# mkdir include
|
||||
# mkdir lib
|
||||
|
||||
# rm -rf libhttp-1.8
|
||||
# tar xf libhttp-1.8.tar.gz
|
||||
# cd libhttp-1.8
|
||||
# cp -a include/civetweb.h ../include/
|
||||
|
||||
|
||||
# cd ..
|
||||
# rm -rf libhttp-1.8
|
||||
# tar xf libhttp-1.8.tar.gz
|
||||
# cd libhttp-1.8
|
||||
# make lib COPT="-DNDEBUG -DNO_CGI -DNO_CACHING -DNO_SSL -DSQLITE_DISABLE_LFS -DSSL_ALREADY_INITIALIZED"
|
||||
# cp -a libcivetweb.a ../lib/libcivetweb_64.a
|
||||
|
||||
|
||||
|
||||
# cd ..
|
||||
# rm -rf libhttp-1.8
|
||||
# tar xf libhttp-1.8.tar.gz
|
||||
# cd libhttp-1.8
|
||||
# make lib COPT="-m32 -DNDEBUG -DNO_CGI -DNO_CACHING -DNO_SSL -DSQLITE_DISABLE_LFS -DSSL_ALREADY_INITIALIZED"
|
||||
# cp -a libcivetweb.a ../lib/libcivetweb_32.a
|
||||
|
||||
|
||||
|
||||
# cd ..
|
||||
# rm -rf libhttp-1.8
|
||||
# tar xf libhttp-1.8.tar.gz
|
||||
# cd libhttp-1.8
|
||||
# make lib CC=aarch64-linux-gnu-gcc COPT="-DNDEBUG -DNO_CGI -DNO_CACHING -DNO_SSL -DSQLITE_DISABLE_LFS -DSSL_ALREADY_INITIALIZED"
|
||||
# cp -a libcivetweb.a ../lib/libcivetweb_aa64.a
|
||||
|
||||
|
||||
# cd ..
|
||||
# rm -rf libhttp-1.8
|
||||
|
||||
|
||||
13145
LinuxGUI/Ventoy2Disk/Lib/libhttp/include/civetweb.c
Normal file
13145
LinuxGUI/Ventoy2Disk/Lib/libhttp/include/civetweb.c
Normal file
File diff suppressed because it is too large
Load Diff
1024
LinuxGUI/Ventoy2Disk/Lib/libhttp/include/civetweb.h
Normal file
1024
LinuxGUI/Ventoy2Disk/Lib/libhttp/include/civetweb.h
Normal file
File diff suppressed because it is too large
Load Diff
793
LinuxGUI/Ventoy2Disk/Lib/libhttp/include/handle_form.inl
Normal file
793
LinuxGUI/Ventoy2Disk/Lib/libhttp/include/handle_form.inl
Normal file
@@ -0,0 +1,793 @@
|
||||
/* Copyright (c) 2016 the Civetweb developers
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
|
||||
static int
|
||||
url_encoded_field_found(const struct mg_connection *conn,
|
||||
const char *key,
|
||||
size_t key_len,
|
||||
const char *filename,
|
||||
size_t filename_len,
|
||||
char *path,
|
||||
size_t path_len,
|
||||
struct mg_form_data_handler *fdh)
|
||||
{
|
||||
char key_dec[1024];
|
||||
char filename_dec[1024];
|
||||
int key_dec_len;
|
||||
int filename_dec_len;
|
||||
int ret;
|
||||
|
||||
key_dec_len =
|
||||
mg_url_decode(key, (int)key_len, key_dec, (int)sizeof(key_dec), 1);
|
||||
|
||||
if (((size_t)key_dec_len >= (size_t)sizeof(key_dec)) || (key_dec_len < 0)) {
|
||||
return FORM_FIELD_STORAGE_SKIP;
|
||||
}
|
||||
|
||||
if (filename) {
|
||||
filename_dec_len = mg_url_decode(filename,
|
||||
(int)filename_len,
|
||||
filename_dec,
|
||||
(int)sizeof(filename_dec),
|
||||
1);
|
||||
|
||||
if (((size_t)filename_dec_len >= (size_t)sizeof(filename_dec))
|
||||
|| (filename_dec_len < 0)) {
|
||||
/* Log error message and skip this field. */
|
||||
mg_cry(conn, "%s: Cannot decode filename", __func__);
|
||||
return FORM_FIELD_STORAGE_SKIP;
|
||||
}
|
||||
} else {
|
||||
filename_dec[0] = 0;
|
||||
}
|
||||
|
||||
ret =
|
||||
fdh->field_found(key_dec, filename_dec, path, path_len, fdh->user_data);
|
||||
|
||||
if ((ret & 0xF) == FORM_FIELD_STORAGE_GET) {
|
||||
if (fdh->field_get == NULL) {
|
||||
mg_cry(conn, "%s: Function \"Get\" not available", __func__);
|
||||
return FORM_FIELD_STORAGE_SKIP;
|
||||
}
|
||||
}
|
||||
if ((ret & 0xF) == FORM_FIELD_STORAGE_STORE) {
|
||||
if (fdh->field_store == NULL) {
|
||||
mg_cry(conn, "%s: Function \"Store\" not available", __func__);
|
||||
return FORM_FIELD_STORAGE_SKIP;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
url_encoded_field_get(const struct mg_connection *conn,
|
||||
const char *key,
|
||||
size_t key_len,
|
||||
const char *value,
|
||||
size_t value_len,
|
||||
struct mg_form_data_handler *fdh)
|
||||
{
|
||||
char key_dec[1024];
|
||||
|
||||
char *value_dec = mg_malloc(value_len + 1);
|
||||
int value_dec_len;
|
||||
|
||||
if (!value_dec) {
|
||||
/* Log error message and stop parsing the form data. */
|
||||
mg_cry(conn,
|
||||
"%s: Not enough memory (required: %lu)",
|
||||
__func__,
|
||||
(unsigned long)(value_len + 1));
|
||||
return FORM_FIELD_STORAGE_ABORT;
|
||||
}
|
||||
|
||||
mg_url_decode(key, (int)key_len, key_dec, (int)sizeof(key_dec), 1);
|
||||
|
||||
value_dec_len =
|
||||
mg_url_decode(value, (int)value_len, value_dec, (int)value_len + 1, 1);
|
||||
|
||||
return fdh->field_get(key_dec,
|
||||
value_dec,
|
||||
(size_t)value_dec_len,
|
||||
fdh->user_data);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
field_stored(const struct mg_connection *conn,
|
||||
const char *path,
|
||||
long long file_size,
|
||||
struct mg_form_data_handler *fdh)
|
||||
{
|
||||
/* Equivalent to "upload" callback of "mg_upload". */
|
||||
|
||||
(void)conn; /* we do not need mg_cry here, so conn is currently unused */
|
||||
|
||||
return fdh->field_store(path, file_size, fdh->user_data);
|
||||
}
|
||||
|
||||
|
||||
static const char *
|
||||
search_boundary(const char *buf,
|
||||
size_t buf_len,
|
||||
const char *boundary,
|
||||
size_t boundary_len)
|
||||
{
|
||||
/* We must do a binary search here, not a string search, since the buffer
|
||||
* may contain '\x00' bytes, if binary data is transferred. */
|
||||
int clen = (int)buf_len - (int)boundary_len - 4;
|
||||
int i;
|
||||
|
||||
for (i = 0; i <= clen; i++) {
|
||||
if (!memcmp(buf + i, "\r\n--", 4)) {
|
||||
if (!memcmp(buf + i + 4, boundary, boundary_len)) {
|
||||
return buf + i;
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
mg_handle_form_request(struct mg_connection *conn,
|
||||
struct mg_form_data_handler *fdh)
|
||||
{
|
||||
const char *content_type;
|
||||
char path[512];
|
||||
char buf[1024];
|
||||
int field_storage;
|
||||
int buf_fill = 0;
|
||||
int r;
|
||||
int field_count = 0;
|
||||
struct file fstore = STRUCT_FILE_INITIALIZER;
|
||||
int64_t file_size = 0; /* init here, to a avoid a false positive
|
||||
"uninitialized variable used" warning */
|
||||
|
||||
int has_body_data =
|
||||
(conn->request_info.content_length > 0) || (conn->is_chunked);
|
||||
|
||||
/* There are three ways to encode data from a HTML form:
|
||||
* 1) method: GET (default)
|
||||
* The form data is in the HTTP query string.
|
||||
* 2) method: POST, enctype: "application/x-www-form-urlencoded"
|
||||
* The form data is in the request body.
|
||||
* The body is url encoded (the default encoding for POST).
|
||||
* 3) method: POST, enctype: "multipart/form-data".
|
||||
* The form data is in the request body of a multipart message.
|
||||
* This is the typical way to handle file upload from a form.
|
||||
*/
|
||||
|
||||
if (!has_body_data) {
|
||||
const char *data;
|
||||
|
||||
if (strcmp(conn->request_info.request_method, "GET")) {
|
||||
/* No body data, but not a GET request.
|
||||
* This is not a valid form request. */
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* GET request: form data is in the query string. */
|
||||
/* The entire data has already been loaded, so there is no nead to
|
||||
* call mg_read. We just need to split the query string into key-value
|
||||
* pairs. */
|
||||
data = conn->request_info.query_string;
|
||||
if (!data) {
|
||||
/* No query string. */
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Split data in a=1&b=xy&c=3&c=4 ... */
|
||||
while (*data) {
|
||||
const char *val = strchr(data, '=');
|
||||
const char *next;
|
||||
ptrdiff_t keylen, vallen;
|
||||
|
||||
if (!val) {
|
||||
break;
|
||||
}
|
||||
keylen = val - data;
|
||||
|
||||
/* In every "field_found" callback we ask what to do with the
|
||||
* data ("field_storage"). This could be:
|
||||
* FORM_FIELD_STORAGE_SKIP (0) ... ignore the value of this field
|
||||
* FORM_FIELD_STORAGE_GET (1) ... read the data and call the get
|
||||
* callback function
|
||||
* FORM_FIELD_STORAGE_STORE (2) ... store the data in a file
|
||||
* FORM_FIELD_STORAGE_READ (3) ... let the user read the data
|
||||
* (for parsing long data on the fly)
|
||||
* (currently not implemented)
|
||||
* FORM_FIELD_STORAGE_ABORT (flag) ... stop parsing
|
||||
*/
|
||||
memset(path, 0, sizeof(path));
|
||||
field_count++;
|
||||
field_storage = url_encoded_field_found(conn,
|
||||
data,
|
||||
(size_t)keylen,
|
||||
NULL,
|
||||
0,
|
||||
path,
|
||||
sizeof(path) - 1,
|
||||
fdh);
|
||||
|
||||
val++;
|
||||
next = strchr(val, '&');
|
||||
if (next) {
|
||||
vallen = next - val;
|
||||
next++;
|
||||
} else {
|
||||
vallen = (ptrdiff_t)strlen(val);
|
||||
next = val + vallen;
|
||||
}
|
||||
|
||||
if (field_storage == FORM_FIELD_STORAGE_GET) {
|
||||
/* Call callback */
|
||||
url_encoded_field_get(
|
||||
conn, data, (size_t)keylen, val, (size_t)vallen, fdh);
|
||||
}
|
||||
if (field_storage == FORM_FIELD_STORAGE_STORE) {
|
||||
/* Store the content to a file */
|
||||
if (mg_fopen(conn, path, "wb", &fstore) == 0) {
|
||||
fstore.fp = NULL;
|
||||
}
|
||||
file_size = 0;
|
||||
if (fstore.fp != NULL) {
|
||||
size_t n =
|
||||
(size_t)fwrite(val, 1, (size_t)vallen, fstore.fp);
|
||||
if ((n != (size_t)vallen) || (ferror(fstore.fp))) {
|
||||
mg_cry(conn,
|
||||
"%s: Cannot write file %s",
|
||||
__func__,
|
||||
path);
|
||||
fclose(fstore.fp);
|
||||
fstore.fp = NULL;
|
||||
remove_bad_file(conn, path);
|
||||
}
|
||||
file_size += (int64_t)n;
|
||||
|
||||
if (fstore.fp) {
|
||||
r = fclose(fstore.fp);
|
||||
if (r == 0) {
|
||||
/* stored successfully */
|
||||
field_stored(conn, path, file_size, fdh);
|
||||
} else {
|
||||
mg_cry(conn,
|
||||
"%s: Error saving file %s",
|
||||
__func__,
|
||||
path);
|
||||
remove_bad_file(conn, path);
|
||||
}
|
||||
fstore.fp = NULL;
|
||||
}
|
||||
|
||||
} else {
|
||||
mg_cry(conn, "%s: Cannot create file %s", __func__, path);
|
||||
}
|
||||
}
|
||||
|
||||
/* if (field_storage == FORM_FIELD_STORAGE_READ) { */
|
||||
/* The idea of "field_storage=read" is to let the API user read
|
||||
* data chunk by chunk and to some data processing on the fly.
|
||||
* This should avoid the need to store data in the server:
|
||||
* It should neither be stored in memory, like
|
||||
* "field_storage=get" does, nor in a file like
|
||||
* "field_storage=store".
|
||||
* However, for a "GET" request this does not make any much
|
||||
* sense, since the data is already stored in memory, as it is
|
||||
* part of the query string.
|
||||
*/
|
||||
/* } */
|
||||
|
||||
if ((field_storage & FORM_FIELD_STORAGE_ABORT)
|
||||
== FORM_FIELD_STORAGE_ABORT) {
|
||||
/* Stop parsing the request */
|
||||
break;
|
||||
}
|
||||
|
||||
/* Proceed to next entry */
|
||||
data = next;
|
||||
}
|
||||
|
||||
return field_count;
|
||||
}
|
||||
|
||||
content_type = mg_get_header(conn, "Content-Type");
|
||||
|
||||
if (!content_type
|
||||
|| !mg_strcasecmp(content_type, "APPLICATION/X-WWW-FORM-URLENCODED")
|
||||
|| !mg_strcasecmp(content_type, "APPLICATION/WWW-FORM-URLENCODED")) {
|
||||
/* The form data is in the request body data, encoded in key/value
|
||||
* pairs. */
|
||||
int all_data_read = 0;
|
||||
|
||||
/* Read body data and split it in keys and values.
|
||||
* The encoding is like in the "GET" case above: a=1&b&c=3&c=4.
|
||||
* Here we use "POST", and read the data from the request body.
|
||||
* The data read on the fly, so it is not required to buffer the
|
||||
* entire request in memory before processing it. */
|
||||
for (;;) {
|
||||
const char *val;
|
||||
const char *next;
|
||||
ptrdiff_t keylen, vallen;
|
||||
ptrdiff_t used;
|
||||
int end_of_key_value_pair_found = 0;
|
||||
int get_block;
|
||||
|
||||
if ((size_t)buf_fill < (sizeof(buf) - 1)) {
|
||||
|
||||
size_t to_read = sizeof(buf) - 1 - (size_t)buf_fill;
|
||||
r = mg_read(conn, buf + (size_t)buf_fill, to_read);
|
||||
if (r < 0) {
|
||||
/* read error */
|
||||
return -1;
|
||||
}
|
||||
if (r != (int)to_read) {
|
||||
/* TODO: Create a function to get "all_data_read" from
|
||||
* the conn object. All data is read if the Content-Length
|
||||
* has been reached, or if chunked encoding is used and
|
||||
* the end marker has been read, or if the connection has
|
||||
* been closed. */
|
||||
all_data_read = 1;
|
||||
}
|
||||
buf_fill += r;
|
||||
buf[buf_fill] = 0;
|
||||
if (buf_fill < 1) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
val = strchr(buf, '=');
|
||||
|
||||
if (!val) {
|
||||
break;
|
||||
}
|
||||
keylen = val - buf;
|
||||
val++;
|
||||
|
||||
/* Call callback */
|
||||
memset(path, 0, sizeof(path));
|
||||
field_count++;
|
||||
field_storage = url_encoded_field_found(conn,
|
||||
buf,
|
||||
(size_t)keylen,
|
||||
NULL,
|
||||
0,
|
||||
path,
|
||||
sizeof(path) - 1,
|
||||
fdh);
|
||||
|
||||
if ((field_storage & FORM_FIELD_STORAGE_ABORT)
|
||||
== FORM_FIELD_STORAGE_ABORT) {
|
||||
/* Stop parsing the request */
|
||||
break;
|
||||
}
|
||||
|
||||
if (field_storage == FORM_FIELD_STORAGE_STORE) {
|
||||
if (mg_fopen(conn, path, "wb", &fstore) == 0) {
|
||||
fstore.fp = NULL;
|
||||
}
|
||||
file_size = 0;
|
||||
if (!fstore.fp) {
|
||||
mg_cry(conn, "%s: Cannot create file %s", __func__, path);
|
||||
}
|
||||
}
|
||||
|
||||
get_block = 0;
|
||||
/* Loop to read values larger than sizeof(buf)-keylen-2 */
|
||||
do {
|
||||
next = strchr(val, '&');
|
||||
if (next) {
|
||||
vallen = next - val;
|
||||
next++;
|
||||
end_of_key_value_pair_found = 1;
|
||||
} else {
|
||||
vallen = (ptrdiff_t)strlen(val);
|
||||
next = val + vallen;
|
||||
}
|
||||
|
||||
if (field_storage == FORM_FIELD_STORAGE_GET) {
|
||||
#if 0
|
||||
if (!end_of_key_value_pair_found && !all_data_read) {
|
||||
/* This callback will deliver partial contents */
|
||||
}
|
||||
#else
|
||||
(void)all_data_read; /* avoid warning */
|
||||
#endif
|
||||
|
||||
/* Call callback */
|
||||
url_encoded_field_get(conn,
|
||||
((get_block > 0) ? NULL : buf),
|
||||
((get_block > 0) ? 0
|
||||
: (size_t)keylen),
|
||||
val,
|
||||
(size_t)vallen,
|
||||
fdh);
|
||||
get_block++;
|
||||
}
|
||||
if (fstore.fp) {
|
||||
size_t n =
|
||||
(size_t)fwrite(val, 1, (size_t)vallen, fstore.fp);
|
||||
if ((n != (size_t)vallen) || (ferror(fstore.fp))) {
|
||||
mg_cry(conn,
|
||||
"%s: Cannot write file %s",
|
||||
__func__,
|
||||
path);
|
||||
fclose(fstore.fp);
|
||||
fstore.fp = NULL;
|
||||
remove_bad_file(conn, path);
|
||||
}
|
||||
file_size += (int64_t)n;
|
||||
}
|
||||
|
||||
if (!end_of_key_value_pair_found) {
|
||||
used = next - buf;
|
||||
memmove(buf,
|
||||
buf + (size_t)used,
|
||||
sizeof(buf) - (size_t)used);
|
||||
buf_fill -= (int)used;
|
||||
if ((size_t)buf_fill < (sizeof(buf) - 1)) {
|
||||
|
||||
size_t to_read = sizeof(buf) - 1 - (size_t)buf_fill;
|
||||
r = mg_read(conn, buf + (size_t)buf_fill, to_read);
|
||||
if (r < 0) {
|
||||
/* read error */
|
||||
return -1;
|
||||
}
|
||||
if (r != (int)to_read) {
|
||||
/* TODO: Create a function to get "all_data_read"
|
||||
* from the conn object. All data is read if the
|
||||
* Content-Length has been reached, or if chunked
|
||||
* encoding is used and the end marker has been
|
||||
* read, or if the connection has been closed. */
|
||||
all_data_read = 1;
|
||||
}
|
||||
buf_fill += r;
|
||||
buf[buf_fill] = 0;
|
||||
if (buf_fill < 1) {
|
||||
break;
|
||||
}
|
||||
val = buf;
|
||||
}
|
||||
}
|
||||
|
||||
} while (!end_of_key_value_pair_found);
|
||||
|
||||
if (fstore.fp) {
|
||||
r = fclose(fstore.fp);
|
||||
if (r == 0) {
|
||||
/* stored successfully */
|
||||
field_stored(conn, path, file_size, fdh);
|
||||
} else {
|
||||
mg_cry(conn, "%s: Error saving file %s", __func__, path);
|
||||
remove_bad_file(conn, path);
|
||||
}
|
||||
fstore.fp = NULL;
|
||||
}
|
||||
|
||||
/* Proceed to next entry */
|
||||
used = next - buf;
|
||||
memmove(buf, buf + (size_t)used, sizeof(buf) - (size_t)used);
|
||||
buf_fill -= (int)used;
|
||||
}
|
||||
|
||||
return field_count;
|
||||
}
|
||||
|
||||
if (!mg_strncasecmp(content_type, "MULTIPART/FORM-DATA;", 20)) {
|
||||
/* The form data is in the request body data, encoded as multipart
|
||||
* content (see https://www.ietf.org/rfc/rfc1867.txt,
|
||||
* https://www.ietf.org/rfc/rfc2388.txt). */
|
||||
const char *boundary;
|
||||
size_t bl;
|
||||
ptrdiff_t used;
|
||||
struct mg_request_info part_header;
|
||||
char *hbuf, *hend, *fbeg, *fend, *nbeg, *nend;
|
||||
const char *content_disp;
|
||||
const char *next;
|
||||
|
||||
memset(&part_header, 0, sizeof(part_header));
|
||||
|
||||
/* Skip all spaces between MULTIPART/FORM-DATA; and BOUNDARY= */
|
||||
bl = 20;
|
||||
while (content_type[bl] == ' ') {
|
||||
bl++;
|
||||
}
|
||||
|
||||
/* There has to be a BOUNDARY definition in the Content-Type header */
|
||||
if (mg_strncasecmp(content_type + bl, "BOUNDARY=", 9)) {
|
||||
/* Malformed request */
|
||||
return -1;
|
||||
}
|
||||
|
||||
boundary = content_type + bl + 9;
|
||||
bl = strlen(boundary);
|
||||
|
||||
if (bl + 800 > sizeof(buf)) {
|
||||
/* Sanity check: The algorithm can not work if bl >= sizeof(buf),
|
||||
* and it will not work effectively, if the buf is only a few byte
|
||||
* larger than bl, or it buf can not hold the multipart header
|
||||
* plus the boundary.
|
||||
* Check some reasonable number here, that should be fulfilled by
|
||||
* any reasonable request from every browser. If it is not
|
||||
* fulfilled, it might be a hand-made request, intended to
|
||||
* interfere with the algorithm. */
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
size_t towrite, n;
|
||||
int get_block;
|
||||
|
||||
r = mg_read(conn,
|
||||
buf + (size_t)buf_fill,
|
||||
sizeof(buf) - 1 - (size_t)buf_fill);
|
||||
if (r < 0) {
|
||||
/* read error */
|
||||
return -1;
|
||||
}
|
||||
buf_fill += r;
|
||||
buf[buf_fill] = 0;
|
||||
if (buf_fill < 1) {
|
||||
/* No data */
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (buf[0] != '-' || buf[1] != '-') {
|
||||
/* Malformed request */
|
||||
return -1;
|
||||
}
|
||||
if (strncmp(buf + 2, boundary, bl)) {
|
||||
/* Malformed request */
|
||||
return -1;
|
||||
}
|
||||
if (buf[bl + 2] != '\r' || buf[bl + 3] != '\n') {
|
||||
/* Every part must end with \r\n, if there is another part.
|
||||
* The end of the request has an extra -- */
|
||||
if (((size_t)buf_fill != (size_t)(bl + 6))
|
||||
|| (strncmp(buf + bl + 2, "--\r\n", 4))) {
|
||||
/* Malformed request */
|
||||
return -1;
|
||||
}
|
||||
/* End of the request */
|
||||
break;
|
||||
}
|
||||
|
||||
/* Next, we need to get the part header: Read until \r\n\r\n */
|
||||
hbuf = buf + bl + 4;
|
||||
hend = strstr(hbuf, "\r\n\r\n");
|
||||
if (!hend) {
|
||||
/* Malformed request */
|
||||
return -1;
|
||||
}
|
||||
|
||||
parse_http_headers(&hbuf, &part_header);
|
||||
if ((hend + 2) != hbuf) {
|
||||
/* Malformed request */
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Skip \r\n\r\n */
|
||||
hend += 4;
|
||||
|
||||
/* According to the RFC, every part has to have a header field like:
|
||||
* Content-Disposition: form-data; name="..." */
|
||||
content_disp = get_header(&part_header, "Content-Disposition");
|
||||
if (!content_disp) {
|
||||
/* Malformed request */
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Get the mandatory name="..." part of the Content-Disposition
|
||||
* header. */
|
||||
nbeg = strstr(content_disp, "name=\"");
|
||||
if (!nbeg) {
|
||||
/* Malformed request */
|
||||
return -1;
|
||||
}
|
||||
nbeg += 6;
|
||||
nend = strchr(nbeg, '\"');
|
||||
if (!nend) {
|
||||
/* Malformed request */
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Get the optional filename="..." part of the Content-Disposition
|
||||
* header. */
|
||||
fbeg = strstr(content_disp, "filename=\"");
|
||||
if (fbeg) {
|
||||
fbeg += 10;
|
||||
fend = strchr(fbeg, '\"');
|
||||
if (!fend) {
|
||||
/* Malformed request (the filename field is optional, but if
|
||||
* it exists, it needs to be terminated correctly). */
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* TODO: check Content-Type */
|
||||
/* Content-Type: application/octet-stream */
|
||||
|
||||
} else {
|
||||
fend = fbeg;
|
||||
}
|
||||
|
||||
memset(path, 0, sizeof(path));
|
||||
field_count++;
|
||||
field_storage = url_encoded_field_found(conn,
|
||||
nbeg,
|
||||
(size_t)(nend - nbeg),
|
||||
fbeg,
|
||||
(size_t)(fend - fbeg),
|
||||
path,
|
||||
sizeof(path) - 1,
|
||||
fdh);
|
||||
|
||||
/* If the boundary is already in the buffer, get the address,
|
||||
* otherwise next will be NULL. */
|
||||
next = search_boundary(hbuf,
|
||||
(size_t)((buf - hbuf) + buf_fill),
|
||||
boundary,
|
||||
bl);
|
||||
|
||||
if (field_storage == FORM_FIELD_STORAGE_STORE) {
|
||||
/* Store the content to a file */
|
||||
if (mg_fopen(conn, path, "wb", &fstore) == 0) {
|
||||
fstore.fp = NULL;
|
||||
}
|
||||
file_size = 0;
|
||||
|
||||
if (!fstore.fp) {
|
||||
mg_cry(conn, "%s: Cannot create file %s", __func__, path);
|
||||
}
|
||||
}
|
||||
|
||||
get_block = 0;
|
||||
while (!next) {
|
||||
/* Set "towrite" to the number of bytes available
|
||||
* in the buffer */
|
||||
towrite = (size_t)(buf - hend + buf_fill);
|
||||
/* Subtract the boundary length, to deal with
|
||||
* cases the boundary is only partially stored
|
||||
* in the buffer. */
|
||||
towrite -= bl + 4;
|
||||
|
||||
if (field_storage == FORM_FIELD_STORAGE_GET) {
|
||||
url_encoded_field_get(conn,
|
||||
((get_block > 0) ? NULL : nbeg),
|
||||
((get_block > 0)
|
||||
? 0
|
||||
: (size_t)(nend - nbeg)),
|
||||
hend,
|
||||
towrite,
|
||||
fdh);
|
||||
get_block++;
|
||||
}
|
||||
|
||||
if (field_storage == FORM_FIELD_STORAGE_STORE) {
|
||||
if (fstore.fp) {
|
||||
|
||||
/* Store the content of the buffer. */
|
||||
n = (size_t)fwrite(hend, 1, towrite, fstore.fp);
|
||||
if ((n != towrite) || (ferror(fstore.fp))) {
|
||||
mg_cry(conn,
|
||||
"%s: Cannot write file %s",
|
||||
__func__,
|
||||
path);
|
||||
fclose(fstore.fp);
|
||||
fstore.fp = NULL;
|
||||
remove_bad_file(conn, path);
|
||||
}
|
||||
file_size += (int64_t)n;
|
||||
}
|
||||
}
|
||||
|
||||
memmove(buf, hend + towrite, bl + 4);
|
||||
buf_fill = (int)(bl + 4);
|
||||
hend = buf;
|
||||
|
||||
/* Read new data */
|
||||
r = mg_read(conn,
|
||||
buf + (size_t)buf_fill,
|
||||
sizeof(buf) - 1 - (size_t)buf_fill);
|
||||
if (r < 0) {
|
||||
/* read error */
|
||||
return -1;
|
||||
}
|
||||
buf_fill += r;
|
||||
buf[buf_fill] = 0;
|
||||
if (buf_fill < 1) {
|
||||
/* No data */
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Find boundary */
|
||||
next = search_boundary(buf, (size_t)buf_fill, boundary, bl);
|
||||
}
|
||||
|
||||
towrite = (size_t)(next - hend);
|
||||
|
||||
if (field_storage == FORM_FIELD_STORAGE_GET) {
|
||||
/* Call callback */
|
||||
url_encoded_field_get(conn,
|
||||
((get_block > 0) ? NULL : nbeg),
|
||||
((get_block > 0) ? 0
|
||||
: (size_t)(nend - nbeg)),
|
||||
hend,
|
||||
towrite,
|
||||
fdh);
|
||||
}
|
||||
|
||||
if (field_storage == FORM_FIELD_STORAGE_STORE) {
|
||||
|
||||
if (fstore.fp) {
|
||||
n = (size_t)fwrite(hend, 1, towrite, fstore.fp);
|
||||
if ((n != towrite) || (ferror(fstore.fp))) {
|
||||
mg_cry(conn,
|
||||
"%s: Cannot write file %s",
|
||||
__func__,
|
||||
path);
|
||||
fclose(fstore.fp);
|
||||
fstore.fp = NULL;
|
||||
remove_bad_file(conn, path);
|
||||
}
|
||||
file_size += (int64_t)n;
|
||||
}
|
||||
}
|
||||
|
||||
if (field_storage == FORM_FIELD_STORAGE_STORE) {
|
||||
|
||||
if (fstore.fp) {
|
||||
r = fclose(fstore.fp);
|
||||
if (r == 0) {
|
||||
/* stored successfully */
|
||||
field_stored(conn, path, file_size, fdh);
|
||||
} else {
|
||||
mg_cry(conn,
|
||||
"%s: Error saving file %s",
|
||||
__func__,
|
||||
path);
|
||||
remove_bad_file(conn, path);
|
||||
}
|
||||
fstore.fp = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if ((field_storage & FORM_FIELD_STORAGE_ABORT)
|
||||
== FORM_FIELD_STORAGE_ABORT) {
|
||||
/* Stop parsing the request */
|
||||
break;
|
||||
}
|
||||
|
||||
/* Remove from the buffer */
|
||||
used = next - buf + 2;
|
||||
memmove(buf, buf + (size_t)used, sizeof(buf) - (size_t)used);
|
||||
buf_fill -= (int)used;
|
||||
}
|
||||
|
||||
/* All parts handled */
|
||||
return field_count;
|
||||
}
|
||||
|
||||
/* Unknown Content-Type */
|
||||
return -1;
|
||||
}
|
||||
468
LinuxGUI/Ventoy2Disk/Lib/libhttp/include/md5.inl
Normal file
468
LinuxGUI/Ventoy2Disk/Lib/libhttp/include/md5.inl
Normal file
@@ -0,0 +1,468 @@
|
||||
/*
|
||||
* This an amalgamation of md5.c and md5.h into a single file
|
||||
* with all static declaration to reduce linker conflicts
|
||||
* in Civetweb.
|
||||
*
|
||||
* The MD5_STATIC declaration was added to facilitate static
|
||||
* inclusion.
|
||||
* No Face Press, LLC
|
||||
*/
|
||||
|
||||
/* $Id: md5.h,v 1.4 2002/04/13 19:20:28 lpd Exp $ */
|
||||
/*
|
||||
Independent implementation of MD5 (RFC 1321).
|
||||
|
||||
This code implements the MD5 Algorithm defined in RFC 1321, whose
|
||||
text is available at
|
||||
http://www.ietf.org/rfc/rfc1321.txt
|
||||
The code is derived from the text of the RFC, including the test suite
|
||||
(section A.5) but excluding the rest of Appendix A. It does not include
|
||||
any code or documentation that is identified in the RFC as being
|
||||
copyrighted.
|
||||
|
||||
The original and principal author of md5.h is L. Peter Deutsch
|
||||
<ghost@aladdin.com>. Other authors are noted in the change history
|
||||
that follows (in reverse chronological order):
|
||||
|
||||
2002-04-13 lpd Removed support for non-ANSI compilers; removed
|
||||
references to Ghostscript; clarified derivation from RFC 1321;
|
||||
now handles byte order either statically or dynamically.
|
||||
1999-11-04 lpd Edited comments slightly for automatic TOC extraction.
|
||||
1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5);
|
||||
added conditionalization for C++ compilation from Martin
|
||||
Purschke <purschke@bnl.gov>.
|
||||
1999-05-03 lpd Original version.
|
||||
*/
|
||||
|
||||
#ifndef md5_INCLUDED
|
||||
#define md5_INCLUDED
|
||||
|
||||
/*
|
||||
* This package supports both compile-time and run-time determination of CPU
|
||||
* byte order. If ARCH_IS_BIG_ENDIAN is defined as 0, the code will be
|
||||
* compiled to run only on little-endian CPUs; if ARCH_IS_BIG_ENDIAN is
|
||||
* defined as non-zero, the code will be compiled to run only on big-endian
|
||||
* CPUs; if ARCH_IS_BIG_ENDIAN is not defined, the code will be compiled to
|
||||
* run on either big- or little-endian CPUs, but will run slightly less
|
||||
* efficiently on either one than if ARCH_IS_BIG_ENDIAN is defined.
|
||||
*/
|
||||
|
||||
typedef unsigned char md5_byte_t; /* 8-bit byte */
|
||||
typedef unsigned int md5_word_t; /* 32-bit word */
|
||||
|
||||
/* Define the state of the MD5 Algorithm. */
|
||||
typedef struct md5_state_s {
|
||||
md5_word_t count[2]; /* message length in bits, lsw first */
|
||||
md5_word_t abcd[4]; /* digest buffer */
|
||||
md5_byte_t buf[64]; /* accumulate block */
|
||||
} md5_state_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Initialize the algorithm. */
|
||||
MD5_STATIC void md5_init(md5_state_t *pms);
|
||||
|
||||
/* Append a string to the message. */
|
||||
MD5_STATIC void
|
||||
md5_append(md5_state_t *pms, const md5_byte_t *data, size_t nbytes);
|
||||
|
||||
/* Finish the message and return the digest. */
|
||||
MD5_STATIC void md5_finish(md5_state_t *pms, md5_byte_t digest[16]);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* end extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* md5_INCLUDED */
|
||||
|
||||
/*
|
||||
Copyright (C) 1999, 2000, 2002 Aladdin Enterprises. All rights reserved.
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
L. Peter Deutsch
|
||||
ghost@aladdin.com
|
||||
|
||||
*/
|
||||
/* $Id: md5.c,v 1.6 2002/04/13 19:20:28 lpd Exp $ */
|
||||
/*
|
||||
Independent implementation of MD5 (RFC 1321).
|
||||
|
||||
This code implements the MD5 Algorithm defined in RFC 1321, whose
|
||||
text is available at
|
||||
http://www.ietf.org/rfc/rfc1321.txt
|
||||
The code is derived from the text of the RFC, including the test suite
|
||||
(section A.5) but excluding the rest of Appendix A. It does not include
|
||||
any code or documentation that is identified in the RFC as being
|
||||
copyrighted.
|
||||
|
||||
The original and principal author of md5.c is L. Peter Deutsch
|
||||
<ghost@aladdin.com>. Other authors are noted in the change history
|
||||
that follows (in reverse chronological order):
|
||||
|
||||
2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order
|
||||
either statically or dynamically; added missing #include <string.h>
|
||||
in library.
|
||||
2002-03-11 lpd Corrected argument list for main(), and added int return
|
||||
type, in test program and T value program.
|
||||
2002-02-21 lpd Added missing #include <stdio.h> in test program.
|
||||
2000-07-03 lpd Patched to eliminate warnings about "constant is
|
||||
unsigned in ANSI C, signed in traditional"; made test program
|
||||
self-checking.
|
||||
1999-11-04 lpd Edited comments slightly for automatic TOC extraction.
|
||||
1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5).
|
||||
1999-05-03 lpd Original version.
|
||||
*/
|
||||
|
||||
#ifndef MD5_STATIC
|
||||
#include <string.h>
|
||||
#endif
|
||||
|
||||
#undef BYTE_ORDER /* 1 = big-endian, -1 = little-endian, 0 = unknown */
|
||||
#ifdef ARCH_IS_BIG_ENDIAN
|
||||
#define BYTE_ORDER (ARCH_IS_BIG_ENDIAN ? 1 : -1)
|
||||
#else
|
||||
#define BYTE_ORDER (0)
|
||||
#endif
|
||||
|
||||
#define T_MASK ((md5_word_t)~0)
|
||||
#define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87)
|
||||
#define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9)
|
||||
#define T3 (0x242070db)
|
||||
#define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111)
|
||||
#define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050)
|
||||
#define T6 (0x4787c62a)
|
||||
#define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec)
|
||||
#define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe)
|
||||
#define T9 (0x698098d8)
|
||||
#define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850)
|
||||
#define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e)
|
||||
#define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841)
|
||||
#define T13 (0x6b901122)
|
||||
#define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c)
|
||||
#define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71)
|
||||
#define T16 (0x49b40821)
|
||||
#define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d)
|
||||
#define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf)
|
||||
#define T19 (0x265e5a51)
|
||||
#define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855)
|
||||
#define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2)
|
||||
#define T22 (0x02441453)
|
||||
#define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e)
|
||||
#define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437)
|
||||
#define T25 (0x21e1cde6)
|
||||
#define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829)
|
||||
#define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278)
|
||||
#define T28 (0x455a14ed)
|
||||
#define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa)
|
||||
#define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07)
|
||||
#define T31 (0x676f02d9)
|
||||
#define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375)
|
||||
#define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd)
|
||||
#define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e)
|
||||
#define T35 (0x6d9d6122)
|
||||
#define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3)
|
||||
#define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb)
|
||||
#define T38 (0x4bdecfa9)
|
||||
#define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f)
|
||||
#define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f)
|
||||
#define T41 (0x289b7ec6)
|
||||
#define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805)
|
||||
#define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a)
|
||||
#define T44 (0x04881d05)
|
||||
#define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6)
|
||||
#define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a)
|
||||
#define T47 (0x1fa27cf8)
|
||||
#define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a)
|
||||
#define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb)
|
||||
#define T50 (0x432aff97)
|
||||
#define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58)
|
||||
#define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6)
|
||||
#define T53 (0x655b59c3)
|
||||
#define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d)
|
||||
#define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82)
|
||||
#define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e)
|
||||
#define T57 (0x6fa87e4f)
|
||||
#define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f)
|
||||
#define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb)
|
||||
#define T60 (0x4e0811a1)
|
||||
#define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d)
|
||||
#define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca)
|
||||
#define T63 (0x2ad7d2bb)
|
||||
#define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e)
|
||||
|
||||
static void
|
||||
md5_process(md5_state_t *pms, const md5_byte_t *data /*[64]*/)
|
||||
{
|
||||
md5_word_t a = pms->abcd[0], b = pms->abcd[1], c = pms->abcd[2],
|
||||
d = pms->abcd[3];
|
||||
md5_word_t t;
|
||||
#if BYTE_ORDER > 0
|
||||
/* Define storage only for big-endian CPUs. */
|
||||
md5_word_t X[16];
|
||||
#else
|
||||
/* Define storage for little-endian or both types of CPUs. */
|
||||
md5_word_t xbuf[16];
|
||||
const md5_word_t *X;
|
||||
#endif
|
||||
|
||||
{
|
||||
#if BYTE_ORDER == 0
|
||||
/*
|
||||
* Determine dynamically whether this is a big-endian or
|
||||
* little-endian machine, since we can use a more efficient
|
||||
* algorithm on the latter.
|
||||
*/
|
||||
static const int w = 1;
|
||||
|
||||
if (*((const md5_byte_t *)&w)) /* dynamic little-endian */
|
||||
#endif
|
||||
#if BYTE_ORDER <= 0 /* little-endian */
|
||||
{
|
||||
/*
|
||||
* On little-endian machines, we can process properly aligned
|
||||
* data without copying it.
|
||||
*/
|
||||
if (!((data - (const md5_byte_t *)0) & 3)) {
|
||||
/* data are properly aligned, a direct assignment is possible */
|
||||
/* cast through a (void *) should avoid a compiler warning,
|
||||
see
|
||||
https://github.com/bel2125/civetweb/issues/94#issuecomment-98112861
|
||||
*/
|
||||
X = (const md5_word_t *)(const void *)data;
|
||||
} else {
|
||||
/* not aligned */
|
||||
memcpy(xbuf, data, 64);
|
||||
X = xbuf;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#if BYTE_ORDER == 0
|
||||
else /* dynamic big-endian */
|
||||
#endif
|
||||
#if BYTE_ORDER >= 0 /* big-endian */
|
||||
{
|
||||
/*
|
||||
* On big-endian machines, we must arrange the bytes in the
|
||||
* right order.
|
||||
*/
|
||||
const md5_byte_t *xp = data;
|
||||
int i;
|
||||
|
||||
#if BYTE_ORDER == 0
|
||||
X = xbuf; /* (dynamic only) */
|
||||
#else
|
||||
#define xbuf X /* (static only) */
|
||||
#endif
|
||||
for (i = 0; i < 16; ++i, xp += 4)
|
||||
xbuf[i] = (md5_word_t)(xp[0]) + (md5_word_t)(xp[1] << 8)
|
||||
+ (md5_word_t)(xp[2] << 16)
|
||||
+ (md5_word_t)(xp[3] << 24);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
|
||||
|
||||
/* Round 1. */
|
||||
/* Let [abcd k s i] denote the operation
|
||||
a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */
|
||||
#define F(x, y, z) (((x) & (y)) | (~(x) & (z)))
|
||||
#define SET(a, b, c, d, k, s, Ti) \
|
||||
t = a + F(b, c, d) + X[k] + Ti; \
|
||||
a = ROTATE_LEFT(t, s) + b
|
||||
|
||||
/* Do the following 16 operations. */
|
||||
SET(a, b, c, d, 0, 7, T1);
|
||||
SET(d, a, b, c, 1, 12, T2);
|
||||
SET(c, d, a, b, 2, 17, T3);
|
||||
SET(b, c, d, a, 3, 22, T4);
|
||||
SET(a, b, c, d, 4, 7, T5);
|
||||
SET(d, a, b, c, 5, 12, T6);
|
||||
SET(c, d, a, b, 6, 17, T7);
|
||||
SET(b, c, d, a, 7, 22, T8);
|
||||
SET(a, b, c, d, 8, 7, T9);
|
||||
SET(d, a, b, c, 9, 12, T10);
|
||||
SET(c, d, a, b, 10, 17, T11);
|
||||
SET(b, c, d, a, 11, 22, T12);
|
||||
SET(a, b, c, d, 12, 7, T13);
|
||||
SET(d, a, b, c, 13, 12, T14);
|
||||
SET(c, d, a, b, 14, 17, T15);
|
||||
SET(b, c, d, a, 15, 22, T16);
|
||||
#undef SET
|
||||
|
||||
/* Round 2. */
|
||||
/* Let [abcd k s i] denote the operation
|
||||
a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */
|
||||
#define G(x, y, z) (((x) & (z)) | ((y) & ~(z)))
|
||||
#define SET(a, b, c, d, k, s, Ti) \
|
||||
t = a + G(b, c, d) + X[k] + Ti; \
|
||||
a = ROTATE_LEFT(t, s) + b
|
||||
|
||||
/* Do the following 16 operations. */
|
||||
SET(a, b, c, d, 1, 5, T17);
|
||||
SET(d, a, b, c, 6, 9, T18);
|
||||
SET(c, d, a, b, 11, 14, T19);
|
||||
SET(b, c, d, a, 0, 20, T20);
|
||||
SET(a, b, c, d, 5, 5, T21);
|
||||
SET(d, a, b, c, 10, 9, T22);
|
||||
SET(c, d, a, b, 15, 14, T23);
|
||||
SET(b, c, d, a, 4, 20, T24);
|
||||
SET(a, b, c, d, 9, 5, T25);
|
||||
SET(d, a, b, c, 14, 9, T26);
|
||||
SET(c, d, a, b, 3, 14, T27);
|
||||
SET(b, c, d, a, 8, 20, T28);
|
||||
SET(a, b, c, d, 13, 5, T29);
|
||||
SET(d, a, b, c, 2, 9, T30);
|
||||
SET(c, d, a, b, 7, 14, T31);
|
||||
SET(b, c, d, a, 12, 20, T32);
|
||||
#undef SET
|
||||
|
||||
/* Round 3. */
|
||||
/* Let [abcd k s t] denote the operation
|
||||
a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */
|
||||
#define H(x, y, z) ((x) ^ (y) ^ (z))
|
||||
#define SET(a, b, c, d, k, s, Ti) \
|
||||
t = a + H(b, c, d) + X[k] + Ti; \
|
||||
a = ROTATE_LEFT(t, s) + b
|
||||
|
||||
/* Do the following 16 operations. */
|
||||
SET(a, b, c, d, 5, 4, T33);
|
||||
SET(d, a, b, c, 8, 11, T34);
|
||||
SET(c, d, a, b, 11, 16, T35);
|
||||
SET(b, c, d, a, 14, 23, T36);
|
||||
SET(a, b, c, d, 1, 4, T37);
|
||||
SET(d, a, b, c, 4, 11, T38);
|
||||
SET(c, d, a, b, 7, 16, T39);
|
||||
SET(b, c, d, a, 10, 23, T40);
|
||||
SET(a, b, c, d, 13, 4, T41);
|
||||
SET(d, a, b, c, 0, 11, T42);
|
||||
SET(c, d, a, b, 3, 16, T43);
|
||||
SET(b, c, d, a, 6, 23, T44);
|
||||
SET(a, b, c, d, 9, 4, T45);
|
||||
SET(d, a, b, c, 12, 11, T46);
|
||||
SET(c, d, a, b, 15, 16, T47);
|
||||
SET(b, c, d, a, 2, 23, T48);
|
||||
#undef SET
|
||||
|
||||
/* Round 4. */
|
||||
/* Let [abcd k s t] denote the operation
|
||||
a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */
|
||||
#define I(x, y, z) ((y) ^ ((x) | ~(z)))
|
||||
#define SET(a, b, c, d, k, s, Ti) \
|
||||
t = a + I(b, c, d) + X[k] + Ti; \
|
||||
a = ROTATE_LEFT(t, s) + b
|
||||
|
||||
/* Do the following 16 operations. */
|
||||
SET(a, b, c, d, 0, 6, T49);
|
||||
SET(d, a, b, c, 7, 10, T50);
|
||||
SET(c, d, a, b, 14, 15, T51);
|
||||
SET(b, c, d, a, 5, 21, T52);
|
||||
SET(a, b, c, d, 12, 6, T53);
|
||||
SET(d, a, b, c, 3, 10, T54);
|
||||
SET(c, d, a, b, 10, 15, T55);
|
||||
SET(b, c, d, a, 1, 21, T56);
|
||||
SET(a, b, c, d, 8, 6, T57);
|
||||
SET(d, a, b, c, 15, 10, T58);
|
||||
SET(c, d, a, b, 6, 15, T59);
|
||||
SET(b, c, d, a, 13, 21, T60);
|
||||
SET(a, b, c, d, 4, 6, T61);
|
||||
SET(d, a, b, c, 11, 10, T62);
|
||||
SET(c, d, a, b, 2, 15, T63);
|
||||
SET(b, c, d, a, 9, 21, T64);
|
||||
#undef SET
|
||||
|
||||
/* Then perform the following additions. (That is increment each
|
||||
of the four registers by the value it had before this block
|
||||
was started.) */
|
||||
pms->abcd[0] += a;
|
||||
pms->abcd[1] += b;
|
||||
pms->abcd[2] += c;
|
||||
pms->abcd[3] += d;
|
||||
}
|
||||
|
||||
MD5_STATIC void
|
||||
md5_init(md5_state_t *pms)
|
||||
{
|
||||
pms->count[0] = pms->count[1] = 0;
|
||||
pms->abcd[0] = 0x67452301;
|
||||
pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476;
|
||||
pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301;
|
||||
pms->abcd[3] = 0x10325476;
|
||||
}
|
||||
|
||||
MD5_STATIC void
|
||||
md5_append(md5_state_t *pms, const md5_byte_t *data, size_t nbytes)
|
||||
{
|
||||
const md5_byte_t *p = data;
|
||||
size_t left = nbytes;
|
||||
size_t offset = (pms->count[0] >> 3) & 63;
|
||||
md5_word_t nbits = (md5_word_t)(nbytes << 3);
|
||||
|
||||
if (nbytes <= 0)
|
||||
return;
|
||||
|
||||
/* Update the message length. */
|
||||
pms->count[1] += (md5_word_t)(nbytes >> 29);
|
||||
pms->count[0] += nbits;
|
||||
if (pms->count[0] < nbits)
|
||||
pms->count[1]++;
|
||||
|
||||
/* Process an initial partial block. */
|
||||
if (offset) {
|
||||
size_t copy = (offset + nbytes > 64 ? 64 - offset : nbytes);
|
||||
|
||||
memcpy(pms->buf + offset, p, copy);
|
||||
if (offset + copy < 64)
|
||||
return;
|
||||
p += copy;
|
||||
left -= copy;
|
||||
md5_process(pms, pms->buf);
|
||||
}
|
||||
|
||||
/* Process full blocks. */
|
||||
for (; left >= 64; p += 64, left -= 64)
|
||||
md5_process(pms, p);
|
||||
|
||||
/* Process a final partial block. */
|
||||
if (left)
|
||||
memcpy(pms->buf, p, left);
|
||||
}
|
||||
|
||||
MD5_STATIC void
|
||||
md5_finish(md5_state_t *pms, md5_byte_t digest[16])
|
||||
{
|
||||
static const md5_byte_t pad[64] = {0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
||||
md5_byte_t data[8];
|
||||
int i;
|
||||
|
||||
/* Save the length before padding. */
|
||||
for (i = 0; i < 8; ++i)
|
||||
data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3));
|
||||
/* Pad to 56 bytes mod 64. */
|
||||
md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1);
|
||||
/* Append the length. */
|
||||
md5_append(pms, data, 8);
|
||||
for (i = 0; i < 16; ++i)
|
||||
digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3));
|
||||
}
|
||||
250
LinuxGUI/Ventoy2Disk/Lib/libhttp/include/mod_duktape.inl
Normal file
250
LinuxGUI/Ventoy2Disk/Lib/libhttp/include/mod_duktape.inl
Normal file
@@ -0,0 +1,250 @@
|
||||
/* This file is part of the CivetWeb web server.
|
||||
* See https://github.com/civetweb/civetweb/
|
||||
* (C) 2015 by the CivetWeb authors, MIT license.
|
||||
*/
|
||||
|
||||
#include "duktape.h"
|
||||
|
||||
/* TODO: the mg context should be added to duktape as well */
|
||||
/* Alternative: redefine a new, clean API from scratch (instead of using mg),
|
||||
* or at least do not add problematic functions. */
|
||||
/* For evaluation purposes, currently only "send" is supported.
|
||||
* All other ~50 functions will be added later. */
|
||||
|
||||
/* Note: This is only experimental support, so the API may still change. */
|
||||
|
||||
static const char *civetweb_conn_id = "\xFF"
|
||||
"civetweb_conn";
|
||||
static const char *civetweb_ctx_id = "\xFF"
|
||||
"civetweb_ctx";
|
||||
|
||||
|
||||
static void *
|
||||
mg_duk_mem_alloc(void *udata, duk_size_t size)
|
||||
{
|
||||
return mg_malloc(size);
|
||||
}
|
||||
|
||||
|
||||
static void *
|
||||
mg_duk_mem_realloc(void *udata, void *ptr, duk_size_t newsize)
|
||||
{
|
||||
return mg_realloc(ptr, newsize);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
mg_duk_mem_free(void *udata, void *ptr)
|
||||
{
|
||||
mg_free(ptr);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
mg_duk_fatal_handler(duk_context *ctx, duk_errcode_t code, const char *msg)
|
||||
{
|
||||
/* Script is called "protected" (duk_peval_file), so script errors should
|
||||
* never yield in a call to this function. Maybe calls prior to executing
|
||||
* the script could raise a fatal error. */
|
||||
struct mg_connection *conn;
|
||||
|
||||
duk_push_global_stash(ctx);
|
||||
duk_get_prop_string(ctx, -1, civetweb_conn_id);
|
||||
conn = (struct mg_connection *)duk_to_pointer(ctx, -1);
|
||||
|
||||
mg_cry(conn, "%s", msg);
|
||||
}
|
||||
|
||||
|
||||
static duk_ret_t
|
||||
duk_itf_write(duk_context *ctx)
|
||||
{
|
||||
struct mg_connection *conn;
|
||||
duk_double_t ret;
|
||||
duk_size_t len = 0;
|
||||
const char *val = duk_require_lstring(ctx, -1, &len);
|
||||
|
||||
/*
|
||||
duk_push_global_stash(ctx);
|
||||
duk_get_prop_string(ctx, -1, civetweb_conn_id);
|
||||
conn = (struct mg_connection *)duk_to_pointer(ctx, -1);
|
||||
*/
|
||||
duk_push_current_function(ctx);
|
||||
duk_get_prop_string(ctx, -1, civetweb_conn_id);
|
||||
conn = (struct mg_connection *)duk_to_pointer(ctx, -1);
|
||||
|
||||
if (!conn) {
|
||||
duk_error(ctx,
|
||||
DUK_ERR_INTERNAL_ERROR,
|
||||
"function not available without connection object");
|
||||
/* probably never reached, but satisfies static code analysis */
|
||||
return DUK_RET_INTERNAL_ERROR;
|
||||
}
|
||||
|
||||
ret = mg_write(conn, val, len);
|
||||
|
||||
duk_push_number(ctx, ret);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static duk_ret_t
|
||||
duk_itf_read(duk_context *ctx)
|
||||
{
|
||||
struct mg_connection *conn;
|
||||
char buf[1024];
|
||||
int len;
|
||||
|
||||
duk_push_global_stash(ctx);
|
||||
duk_get_prop_string(ctx, -1, civetweb_conn_id);
|
||||
conn = (struct mg_connection *)duk_to_pointer(ctx, -1);
|
||||
|
||||
if (!conn) {
|
||||
duk_error(ctx,
|
||||
DUK_ERR_INTERNAL_ERROR,
|
||||
"function not available without connection object");
|
||||
/* probably never reached, but satisfies static code analysis */
|
||||
return DUK_RET_INTERNAL_ERROR;
|
||||
}
|
||||
|
||||
len = mg_read(conn, buf, sizeof(buf));
|
||||
|
||||
duk_push_lstring(ctx, buf, len);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static duk_ret_t
|
||||
duk_itf_getoption(duk_context *ctx)
|
||||
{
|
||||
struct mg_context *cv_ctx;
|
||||
const char *ret;
|
||||
duk_size_t len = 0;
|
||||
const char *val = duk_require_lstring(ctx, -1, &len);
|
||||
|
||||
duk_push_current_function(ctx);
|
||||
duk_get_prop_string(ctx, -1, civetweb_ctx_id);
|
||||
cv_ctx = (struct mg_context *)duk_to_pointer(ctx, -1);
|
||||
|
||||
if (!cv_ctx) {
|
||||
duk_error(ctx,
|
||||
DUK_ERR_INTERNAL_ERROR,
|
||||
"function not available without connection object");
|
||||
/* probably never reached, but satisfies static code analysis */
|
||||
return DUK_RET_INTERNAL_ERROR;
|
||||
}
|
||||
|
||||
ret = mg_get_option(cv_ctx, val);
|
||||
if (ret) {
|
||||
duk_push_string(ctx, ret);
|
||||
} else {
|
||||
duk_push_null(ctx);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
mg_exec_duktape_script(struct mg_connection *conn, const char *script_name)
|
||||
{
|
||||
int i;
|
||||
duk_context *ctx = NULL;
|
||||
|
||||
conn->must_close = 1;
|
||||
|
||||
/* Create Duktape interpreter state */
|
||||
ctx = duk_create_heap(mg_duk_mem_alloc,
|
||||
mg_duk_mem_realloc,
|
||||
mg_duk_mem_free,
|
||||
NULL,
|
||||
mg_duk_fatal_handler);
|
||||
if (!ctx) {
|
||||
mg_cry(conn, "Failed to create a Duktape heap.");
|
||||
goto exec_duktape_finished;
|
||||
}
|
||||
|
||||
/* Add "conn" object */
|
||||
duk_push_global_object(ctx);
|
||||
duk_push_object(ctx); /* create a new table/object ("conn") */
|
||||
|
||||
duk_push_c_function(ctx, duk_itf_write, 1 /* 1 = nargs */);
|
||||
duk_push_pointer(ctx, (void *)conn);
|
||||
duk_put_prop_string(ctx, -2, civetweb_conn_id);
|
||||
duk_put_prop_string(ctx, -2, "write"); /* add function conn.write */
|
||||
|
||||
duk_push_c_function(ctx, duk_itf_read, 0 /* 0 = nargs */);
|
||||
duk_push_pointer(ctx, (void *)conn);
|
||||
duk_put_prop_string(ctx, -2, civetweb_conn_id);
|
||||
duk_put_prop_string(ctx, -2, "read"); /* add function conn.read */
|
||||
|
||||
duk_push_string(ctx, conn->request_info.request_method);
|
||||
duk_put_prop_string(ctx, -2, "request_method"); /* add string conn.r... */
|
||||
|
||||
duk_push_string(ctx, conn->request_info.request_uri);
|
||||
duk_put_prop_string(ctx, -2, "request_uri");
|
||||
|
||||
duk_push_string(ctx, conn->request_info.local_uri);
|
||||
duk_put_prop_string(ctx, -2, "uri");
|
||||
|
||||
duk_push_string(ctx, conn->request_info.http_version);
|
||||
duk_put_prop_string(ctx, -2, "http_version");
|
||||
|
||||
duk_push_string(ctx, conn->request_info.query_string);
|
||||
duk_put_prop_string(ctx, -2, "query_string");
|
||||
|
||||
duk_push_string(ctx, conn->request_info.remote_addr);
|
||||
duk_put_prop_string(ctx, -2, "remote_addr");
|
||||
|
||||
duk_push_int(ctx, conn->request_info.remote_port);
|
||||
duk_put_prop_string(ctx, -2, "remote_port");
|
||||
|
||||
duk_push_int(ctx, ntohs(conn->client.lsa.sin.sin_port));
|
||||
duk_put_prop_string(ctx, -2, "server_port");
|
||||
|
||||
duk_push_object(ctx); /* subfolder "conn.http_headers" */
|
||||
for (i = 0; i < conn->request_info.num_headers; i++) {
|
||||
duk_push_string(ctx, conn->request_info.http_headers[i].value);
|
||||
duk_put_prop_string(ctx, -2, conn->request_info.http_headers[i].name);
|
||||
}
|
||||
duk_put_prop_string(ctx, -2, "http_headers");
|
||||
|
||||
duk_put_prop_string(ctx, -2, "conn"); /* call the table "conn" */
|
||||
|
||||
/* Add "civetweb" object */
|
||||
duk_push_global_object(ctx);
|
||||
duk_push_object(ctx); /* create a new table/object ("conn") */
|
||||
|
||||
duk_push_string(ctx, CIVETWEB_VERSION);
|
||||
duk_put_prop_string(ctx, -2, "version");
|
||||
|
||||
duk_push_string(ctx, script_name);
|
||||
duk_put_prop_string(ctx, -2, "script_name");
|
||||
|
||||
if (conn->ctx != NULL) {
|
||||
duk_push_c_function(ctx, duk_itf_getoption, 1 /* 1 = nargs */);
|
||||
duk_push_pointer(ctx, (void *)(conn->ctx));
|
||||
duk_put_prop_string(ctx, -2, civetweb_ctx_id);
|
||||
duk_put_prop_string(ctx, -2, "getoption"); /* add function conn.write */
|
||||
|
||||
if (conn->ctx->systemName != NULL) {
|
||||
duk_push_string(ctx, conn->ctx->systemName);
|
||||
duk_put_prop_string(ctx, -2, "system");
|
||||
}
|
||||
}
|
||||
|
||||
duk_put_prop_string(ctx, -2, "civetweb"); /* call the table "civetweb" */
|
||||
|
||||
duk_push_global_stash(ctx);
|
||||
duk_push_pointer(ctx, (void *)conn);
|
||||
duk_put_prop_string(ctx, -2, civetweb_conn_id);
|
||||
|
||||
if (duk_peval_file(ctx, script_name) != 0) {
|
||||
mg_cry(conn, "%s", duk_safe_to_string(ctx, -1));
|
||||
goto exec_duktape_finished;
|
||||
}
|
||||
duk_pop(ctx); /* ignore result */
|
||||
|
||||
exec_duktape_finished:
|
||||
duk_destroy_heap(ctx);
|
||||
}
|
||||
1840
LinuxGUI/Ventoy2Disk/Lib/libhttp/include/mod_lua.inl
Normal file
1840
LinuxGUI/Ventoy2Disk/Lib/libhttp/include/mod_lua.inl
Normal file
File diff suppressed because it is too large
Load Diff
150
LinuxGUI/Ventoy2Disk/Lib/libhttp/include/timer.inl
Normal file
150
LinuxGUI/Ventoy2Disk/Lib/libhttp/include/timer.inl
Normal file
@@ -0,0 +1,150 @@
|
||||
|
||||
#if !defined(MAX_TIMERS)
|
||||
#define MAX_TIMERS MAX_WORKER_THREADS
|
||||
#endif
|
||||
|
||||
typedef int (*taction)(void *arg);
|
||||
|
||||
struct ttimer {
|
||||
double time;
|
||||
double period;
|
||||
taction action;
|
||||
void *arg;
|
||||
};
|
||||
|
||||
struct ttimers {
|
||||
pthread_t threadid; /* Timer thread ID */
|
||||
pthread_mutex_t mutex; /* Protects timer lists */
|
||||
struct ttimer timers[MAX_TIMERS]; /* List of timers */
|
||||
unsigned timer_count; /* Current size of timer list */
|
||||
};
|
||||
|
||||
static int
|
||||
timer_add(struct mg_context *ctx,
|
||||
double next_time,
|
||||
double period,
|
||||
int is_relative,
|
||||
taction action,
|
||||
void *arg)
|
||||
{
|
||||
unsigned u, v;
|
||||
int error = 0;
|
||||
struct timespec now;
|
||||
|
||||
if (ctx->stop_flag) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (is_relative) {
|
||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||
next_time += now.tv_sec;
|
||||
next_time += now.tv_nsec * 1.0E-9;
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&ctx->timers->mutex);
|
||||
if (ctx->timers->timer_count == MAX_TIMERS) {
|
||||
error = 1;
|
||||
} else {
|
||||
for (u = 0; u < ctx->timers->timer_count; u++) {
|
||||
if (ctx->timers->timers[u].time < next_time) {
|
||||
for (v = ctx->timers->timer_count; v > u; v--) {
|
||||
ctx->timers->timers[v] = ctx->timers->timers[v - 1];
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
ctx->timers->timers[u].time = next_time;
|
||||
ctx->timers->timers[u].period = period;
|
||||
ctx->timers->timers[u].action = action;
|
||||
ctx->timers->timers[u].arg = arg;
|
||||
ctx->timers->timer_count++;
|
||||
}
|
||||
pthread_mutex_unlock(&ctx->timers->mutex);
|
||||
return error;
|
||||
}
|
||||
|
||||
static void
|
||||
timer_thread_run(void *thread_func_param)
|
||||
{
|
||||
struct mg_context *ctx = (struct mg_context *)thread_func_param;
|
||||
struct timespec now;
|
||||
double d;
|
||||
unsigned u;
|
||||
int re_schedule;
|
||||
struct ttimer t;
|
||||
|
||||
mg_set_thread_name("timer");
|
||||
|
||||
if (ctx->callbacks.init_thread) {
|
||||
/* Timer thread */
|
||||
ctx->callbacks.init_thread(ctx, 2);
|
||||
}
|
||||
|
||||
#if defined(HAVE_CLOCK_NANOSLEEP) /* Linux with librt */
|
||||
/* TODO */
|
||||
while (clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &request, &request)
|
||||
== EINTR) { /*nop*/
|
||||
;
|
||||
}
|
||||
#else
|
||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||
d = (double)now.tv_sec + (double)now.tv_nsec * 1.0E-9;
|
||||
while (ctx->stop_flag == 0) {
|
||||
pthread_mutex_lock(&ctx->timers->mutex);
|
||||
if (ctx->timers->timer_count > 0 && d >= ctx->timers->timers[0].time) {
|
||||
t = ctx->timers->timers[0];
|
||||
for (u = 1; u < ctx->timers->timer_count; u++) {
|
||||
ctx->timers->timers[u - 1] = ctx->timers->timers[u];
|
||||
}
|
||||
ctx->timers->timer_count--;
|
||||
pthread_mutex_unlock(&ctx->timers->mutex);
|
||||
re_schedule = t.action(t.arg);
|
||||
if (re_schedule && (t.period > 0)) {
|
||||
timer_add(ctx, t.time + t.period, t.period, 0, t.action, t.arg);
|
||||
}
|
||||
continue;
|
||||
} else {
|
||||
pthread_mutex_unlock(&ctx->timers->mutex);
|
||||
}
|
||||
mg_sleep(1);
|
||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||
d = (double)now.tv_sec + (double)now.tv_nsec * 1.0E-9;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
static unsigned __stdcall timer_thread(void *thread_func_param)
|
||||
{
|
||||
timer_thread_run(thread_func_param);
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
static void *
|
||||
timer_thread(void *thread_func_param)
|
||||
{
|
||||
timer_thread_run(thread_func_param);
|
||||
return NULL;
|
||||
}
|
||||
#endif /* _WIN32 */
|
||||
|
||||
static int
|
||||
timers_init(struct mg_context *ctx)
|
||||
{
|
||||
ctx->timers = (struct ttimers *)mg_calloc(sizeof(struct ttimers), 1);
|
||||
(void)pthread_mutex_init(&ctx->timers->mutex, NULL);
|
||||
|
||||
/* Start timer thread */
|
||||
mg_start_thread_with_id(timer_thread, ctx, &ctx->timers->threadid);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
timers_exit(struct mg_context *ctx)
|
||||
{
|
||||
if (ctx->timers) {
|
||||
(void)pthread_mutex_destroy(&ctx->timers->mutex);
|
||||
mg_free(ctx->timers);
|
||||
}
|
||||
}
|
||||
BIN
LinuxGUI/Ventoy2Disk/Lib/libhttp/libhttp-1.8.tar.gz
Normal file
BIN
LinuxGUI/Ventoy2Disk/Lib/libhttp/libhttp-1.8.tar.gz
Normal file
Binary file not shown.
10
LinuxGUI/Ventoy2Disk/Lib/xz-embedded/COPYING
Normal file
10
LinuxGUI/Ventoy2Disk/Lib/xz-embedded/COPYING
Normal file
@@ -0,0 +1,10 @@
|
||||
|
||||
Licensing of XZ Embedded
|
||||
========================
|
||||
|
||||
All the files in this package have been written by Lasse Collin
|
||||
and/or Igor Pavlov. All these files have been put into the
|
||||
public domain. You can do whatever you want with these files.
|
||||
|
||||
As usual, this software is provided "as is", without any warranty.
|
||||
|
||||
163
LinuxGUI/Ventoy2Disk/Lib/xz-embedded/README
Normal file
163
LinuxGUI/Ventoy2Disk/Lib/xz-embedded/README
Normal file
@@ -0,0 +1,163 @@
|
||||
|
||||
XZ Embedded
|
||||
===========
|
||||
|
||||
XZ Embedded is a relatively small, limited implementation of the .xz
|
||||
file format. Currently only decoding is implemented.
|
||||
|
||||
XZ Embedded was written for use in the Linux kernel, but the code can
|
||||
be easily used in other environments too, including regular userspace
|
||||
applications. See userspace/xzminidec.c for an example program.
|
||||
|
||||
This README contains information that is useful only when the copy
|
||||
of XZ Embedded isn't part of the Linux kernel tree. You should also
|
||||
read linux/Documentation/xz.txt even if you aren't using XZ Embedded
|
||||
as part of Linux; information in that file is not repeated in this
|
||||
README.
|
||||
|
||||
Compiling the Linux kernel module
|
||||
|
||||
The xz_dec module depends on crc32 module, so make sure that you have
|
||||
it enabled (CONFIG_CRC32).
|
||||
|
||||
Building the xz_dec and xz_dec_test modules without support for BCJ
|
||||
filters:
|
||||
|
||||
cd linux/lib/xz
|
||||
make -C /path/to/kernel/source \
|
||||
KCPPFLAGS=-I"$(pwd)/../../include" M="$(pwd)" \
|
||||
CONFIG_XZ_DEC=m CONFIG_XZ_DEC_TEST=m
|
||||
|
||||
Building the xz_dec and xz_dec_test modules with support for BCJ
|
||||
filters:
|
||||
|
||||
cd linux/lib/xz
|
||||
make -C /path/to/kernel/source \
|
||||
KCPPFLAGS=-I"$(pwd)/../../include" M="$(pwd)" \
|
||||
CONFIG_XZ_DEC=m CONFIG_XZ_DEC_TEST=m CONFIG_XZ_DEC_BCJ=y \
|
||||
CONFIG_XZ_DEC_X86=y CONFIG_XZ_DEC_POWERPC=y \
|
||||
CONFIG_XZ_DEC_IA64=y CONFIG_XZ_DEC_ARM=y \
|
||||
CONFIG_XZ_DEC_ARMTHUMB=y CONFIG_XZ_DEC_SPARC=y
|
||||
|
||||
If you want only one or a few of the BCJ filters, omit the appropriate
|
||||
variables. CONFIG_XZ_DEC_BCJ=y is always required to build the support
|
||||
code shared between all BCJ filters.
|
||||
|
||||
Most people don't need the xz_dec_test module. You can skip building
|
||||
it by omitting CONFIG_XZ_DEC_TEST=m from the make command line.
|
||||
|
||||
Compiler requirements
|
||||
|
||||
XZ Embedded should compile as either GNU-C89 (used in the Linux
|
||||
kernel) or with any C99 compiler. Getting the code to compile with
|
||||
non-GNU C89 compiler or a C++ compiler should be quite easy as
|
||||
long as there is a data type for unsigned 64-bit integer (or the
|
||||
code is modified not to support large files, which needs some more
|
||||
care than just using 32-bit integer instead of 64-bit).
|
||||
|
||||
If you use GCC, try to use a recent version. For example, on x86-32,
|
||||
xz_dec_lzma2.c compiled with GCC 3.3.6 is 15-25 % slower than when
|
||||
compiled with GCC 4.3.3.
|
||||
|
||||
Embedding into userspace applications
|
||||
|
||||
To embed the XZ decoder, copy the following files into a single
|
||||
directory in your source code tree:
|
||||
|
||||
linux/include/linux/xz.h
|
||||
linux/lib/xz/xz_crc32.c
|
||||
linux/lib/xz/xz_dec_lzma2.c
|
||||
linux/lib/xz/xz_dec_stream.c
|
||||
linux/lib/xz/xz_lzma2.h
|
||||
linux/lib/xz/xz_private.h
|
||||
linux/lib/xz/xz_stream.h
|
||||
userspace/xz_config.h
|
||||
|
||||
Alternatively, xz.h may be placed into a different directory but then
|
||||
that directory must be in the compiler include path when compiling
|
||||
the .c files.
|
||||
|
||||
Your code should use only the functions declared in xz.h. The rest of
|
||||
the .h files are meant only for internal use in XZ Embedded.
|
||||
|
||||
You may want to modify xz_config.h to be more suitable for your build
|
||||
environment. Probably you should at least skim through it even if the
|
||||
default file works as is.
|
||||
|
||||
Integrity check support
|
||||
|
||||
XZ Embedded always supports the integrity check types None and
|
||||
CRC32. Support for CRC64 is optional. SHA-256 is currently not
|
||||
supported in XZ Embedded although the .xz format does support it.
|
||||
The xz tool from XZ Utils uses CRC64 by default, but CRC32 is usually
|
||||
enough in embedded systems to keep the code size smaller.
|
||||
|
||||
If you want support for CRC64, you need to copy linux/lib/xz/xz_crc64.c
|
||||
into your application, and #define XZ_USE_CRC64 in xz_config.h or in
|
||||
compiler flags.
|
||||
|
||||
When using the internal CRC32 or CRC64, their lookup tables need to be
|
||||
initialized with xz_crc32_init() and xz_crc64_init(), respectively.
|
||||
See xz.h for details.
|
||||
|
||||
To use external CRC32 or CRC64 code instead of the code from
|
||||
xz_crc32.c or xz_crc64.c, the following #defines may be used
|
||||
in xz_config.h or in compiler flags:
|
||||
|
||||
#define XZ_INTERNAL_CRC32 0
|
||||
#define XZ_INTERNAL_CRC64 0
|
||||
|
||||
Then it is up to you to provide compatible xz_crc32() or xz_crc64()
|
||||
functions.
|
||||
|
||||
If the .xz file being decompressed uses an integrity check type that
|
||||
isn't supported by XZ Embedded, it is treated as an error and the
|
||||
file cannot be decompressed. For multi-call mode, this can be modified
|
||||
by #defining XZ_DEC_ANY_CHECK. Then xz_dec_run() will return
|
||||
XZ_UNSUPPORTED_CHECK when unsupported check type is detected. After
|
||||
that decompression can be continued normally except that the
|
||||
integrity check won't be verified. In single-call mode there's
|
||||
no way to continue decoding, so XZ_DEC_ANY_CHECK is almost useless
|
||||
in single-call mode.
|
||||
|
||||
BCJ filter support
|
||||
|
||||
If you want support for one or more BCJ filters, you need to copy also
|
||||
linux/lib/xz/xz_dec_bcj.c into your application, and use appropriate
|
||||
#defines in xz_config.h or in compiler flags. You don't need these
|
||||
#defines in the code that just uses XZ Embedded via xz.h, but having
|
||||
them always #defined doesn't hurt either.
|
||||
|
||||
#define Instruction set BCJ filter endianness
|
||||
XZ_DEC_X86 x86-32 or x86-64 Little endian only
|
||||
XZ_DEC_POWERPC PowerPC Big endian only
|
||||
XZ_DEC_IA64 Itanium (IA-64) Big or little endian
|
||||
XZ_DEC_ARM ARM Little endian only
|
||||
XZ_DEC_ARMTHUMB ARM-Thumb Little endian only
|
||||
XZ_DEC_SPARC SPARC Big or little endian
|
||||
|
||||
While some architectures are (partially) bi-endian, the endianness
|
||||
setting doesn't change the endianness of the instructions on all
|
||||
architectures. That's why Itanium and SPARC filters work for both big
|
||||
and little endian executables (Itanium has little endian instructions
|
||||
and SPARC has big endian instructions).
|
||||
|
||||
There currently is no filter for little endian PowerPC or big endian
|
||||
ARM or ARM-Thumb. Implementing filters for them can be considered if
|
||||
there is a need for such filters in real-world applications.
|
||||
|
||||
Notes about shared libraries
|
||||
|
||||
If you are including XZ Embedded into a shared library, you very
|
||||
probably should rename the xz_* functions to prevent symbol
|
||||
conflicts in case your library is linked against some other library
|
||||
or application that also has XZ Embedded in it (which may even be
|
||||
a different version of XZ Embedded). TODO: Provide an easy way
|
||||
to do this.
|
||||
|
||||
Please don't create a shared library of XZ Embedded itself unless
|
||||
it is fine to rebuild everything depending on that shared library
|
||||
everytime you upgrade to a newer version of XZ Embedded. There are
|
||||
no API or ABI stability guarantees between different versions of
|
||||
XZ Embedded.
|
||||
|
||||
122
LinuxGUI/Ventoy2Disk/Lib/xz-embedded/linux/Documentation/xz.txt
Normal file
122
LinuxGUI/Ventoy2Disk/Lib/xz-embedded/linux/Documentation/xz.txt
Normal file
@@ -0,0 +1,122 @@
|
||||
|
||||
XZ data compression in Linux
|
||||
============================
|
||||
|
||||
Introduction
|
||||
|
||||
XZ is a general purpose data compression format with high compression
|
||||
ratio and relatively fast decompression. The primary compression
|
||||
algorithm (filter) is LZMA2. Additional filters can be used to improve
|
||||
compression ratio even further. E.g. Branch/Call/Jump (BCJ) filters
|
||||
improve compression ratio of executable data.
|
||||
|
||||
The XZ decompressor in Linux is called XZ Embedded. It supports
|
||||
the LZMA2 filter and optionally also BCJ filters. CRC32 is supported
|
||||
for integrity checking. The home page of XZ Embedded is at
|
||||
<http://tukaani.org/xz/embedded.html>, where you can find the
|
||||
latest version and also information about using the code outside
|
||||
the Linux kernel.
|
||||
|
||||
For userspace, XZ Utils provide a zlib-like compression library
|
||||
and a gzip-like command line tool. XZ Utils can be downloaded from
|
||||
<http://tukaani.org/xz/>.
|
||||
|
||||
XZ related components in the kernel
|
||||
|
||||
The xz_dec module provides XZ decompressor with single-call (buffer
|
||||
to buffer) and multi-call (stateful) APIs. The usage of the xz_dec
|
||||
module is documented in include/linux/xz.h.
|
||||
|
||||
The xz_dec_test module is for testing xz_dec. xz_dec_test is not
|
||||
useful unless you are hacking the XZ decompressor. xz_dec_test
|
||||
allocates a char device major dynamically to which one can write
|
||||
.xz files from userspace. The decompressed output is thrown away.
|
||||
Keep an eye on dmesg to see diagnostics printed by xz_dec_test.
|
||||
See the xz_dec_test source code for the details.
|
||||
|
||||
For decompressing the kernel image, initramfs, and initrd, there
|
||||
is a wrapper function in lib/decompress_unxz.c. Its API is the
|
||||
same as in other decompress_*.c files, which is defined in
|
||||
include/linux/decompress/generic.h.
|
||||
|
||||
scripts/xz_wrap.sh is a wrapper for the xz command line tool found
|
||||
from XZ Utils. The wrapper sets compression options to values suitable
|
||||
for compressing the kernel image.
|
||||
|
||||
For kernel makefiles, two commands are provided for use with
|
||||
$(call if_needed). The kernel image should be compressed with
|
||||
$(call if_needed,xzkern) which will use a BCJ filter and a big LZMA2
|
||||
dictionary. It will also append a four-byte trailer containing the
|
||||
uncompressed size of the file, which is needed by the boot code.
|
||||
Other things should be compressed with $(call if_needed,xzmisc)
|
||||
which will use no BCJ filter and 1 MiB LZMA2 dictionary.
|
||||
|
||||
Notes on compression options
|
||||
|
||||
Since the XZ Embedded supports only streams with no integrity check or
|
||||
CRC32, make sure that you don't use some other integrity check type
|
||||
when encoding files that are supposed to be decoded by the kernel. With
|
||||
liblzma, you need to use either LZMA_CHECK_NONE or LZMA_CHECK_CRC32
|
||||
when encoding. With the xz command line tool, use --check=none or
|
||||
--check=crc32.
|
||||
|
||||
Using CRC32 is strongly recommended unless there is some other layer
|
||||
which will verify the integrity of the uncompressed data anyway.
|
||||
Double checking the integrity would probably be waste of CPU cycles.
|
||||
Note that the headers will always have a CRC32 which will be validated
|
||||
by the decoder; you can only change the integrity check type (or
|
||||
disable it) for the actual uncompressed data.
|
||||
|
||||
In userspace, LZMA2 is typically used with dictionary sizes of several
|
||||
megabytes. The decoder needs to have the dictionary in RAM, thus big
|
||||
dictionaries cannot be used for files that are intended to be decoded
|
||||
by the kernel. 1 MiB is probably the maximum reasonable dictionary
|
||||
size for in-kernel use (maybe more is OK for initramfs). The presets
|
||||
in XZ Utils may not be optimal when creating files for the kernel,
|
||||
so don't hesitate to use custom settings. Example:
|
||||
|
||||
xz --check=crc32 --lzma2=dict=512KiB inputfile
|
||||
|
||||
An exception to above dictionary size limitation is when the decoder
|
||||
is used in single-call mode. Decompressing the kernel itself is an
|
||||
example of this situation. In single-call mode, the memory usage
|
||||
doesn't depend on the dictionary size, and it is perfectly fine to
|
||||
use a big dictionary: for maximum compression, the dictionary should
|
||||
be at least as big as the uncompressed data itself.
|
||||
|
||||
Future plans
|
||||
|
||||
Creating a limited XZ encoder may be considered if people think it is
|
||||
useful. LZMA2 is slower to compress than e.g. Deflate or LZO even at
|
||||
the fastest settings, so it isn't clear if LZMA2 encoder is wanted
|
||||
into the kernel.
|
||||
|
||||
Support for limited random-access reading is planned for the
|
||||
decompression code. I don't know if it could have any use in the
|
||||
kernel, but I know that it would be useful in some embedded projects
|
||||
outside the Linux kernel.
|
||||
|
||||
Conformance to the .xz file format specification
|
||||
|
||||
There are a couple of corner cases where things have been simplified
|
||||
at expense of detecting errors as early as possible. These should not
|
||||
matter in practice all, since they don't cause security issues. But
|
||||
it is good to know this if testing the code e.g. with the test files
|
||||
from XZ Utils.
|
||||
|
||||
Reporting bugs
|
||||
|
||||
Before reporting a bug, please check that it's not fixed already
|
||||
at upstream. See <http://tukaani.org/xz/embedded.html> to get the
|
||||
latest code.
|
||||
|
||||
Report bugs to <lasse.collin@tukaani.org> or visit #tukaani on
|
||||
Freenode and talk to Larhzu. I don't actively read LKML or other
|
||||
kernel-related mailing lists, so if there's something I should know,
|
||||
you should email to me personally or use IRC.
|
||||
|
||||
Don't bother Igor Pavlov with questions about the XZ implementation
|
||||
in the kernel or about XZ Utils. While these two implementations
|
||||
include essential code that is directly based on Igor Pavlov's code,
|
||||
these implementations aren't maintained nor supported by him.
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Wrapper for decompressing XZ-compressed kernel, initramfs, and initrd
|
||||
*
|
||||
* Author: Lasse Collin <lasse.collin@tukaani.org>
|
||||
*
|
||||
* This file has been put into the public domain.
|
||||
* You can do whatever you want with this file.
|
||||
*/
|
||||
|
||||
#ifndef DECOMPRESS_UNXZ_H
|
||||
#define DECOMPRESS_UNXZ_H
|
||||
|
||||
int unxz(unsigned char *in, int in_size,
|
||||
int (*fill)(void *dest, unsigned int size),
|
||||
int (*flush)(void *src, unsigned int size),
|
||||
unsigned char *out, int *in_used,
|
||||
void (*error)(char *x));
|
||||
|
||||
#endif
|
||||
304
LinuxGUI/Ventoy2Disk/Lib/xz-embedded/linux/include/linux/xz.h
Normal file
304
LinuxGUI/Ventoy2Disk/Lib/xz-embedded/linux/include/linux/xz.h
Normal file
@@ -0,0 +1,304 @@
|
||||
/*
|
||||
* XZ decompressor
|
||||
*
|
||||
* Authors: Lasse Collin <lasse.collin@tukaani.org>
|
||||
* Igor Pavlov <http://7-zip.org/>
|
||||
*
|
||||
* This file has been put into the public domain.
|
||||
* You can do whatever you want with this file.
|
||||
*/
|
||||
|
||||
#ifndef XZ_H
|
||||
#define XZ_H
|
||||
|
||||
#ifdef __KERNEL__
|
||||
# include <linux/stddef.h>
|
||||
# include <linux/types.h>
|
||||
#else
|
||||
# include <stddef.h>
|
||||
# include <stdint.h>
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* In Linux, this is used to make extern functions static when needed. */
|
||||
#ifndef XZ_EXTERN
|
||||
# define XZ_EXTERN extern
|
||||
#endif
|
||||
|
||||
/**
|
||||
* enum xz_mode - Operation mode
|
||||
*
|
||||
* @XZ_SINGLE: Single-call mode. This uses less RAM than
|
||||
* than multi-call modes, because the LZMA2
|
||||
* dictionary doesn't need to be allocated as
|
||||
* part of the decoder state. All required data
|
||||
* structures are allocated at initialization,
|
||||
* so xz_dec_run() cannot return XZ_MEM_ERROR.
|
||||
* @XZ_PREALLOC: Multi-call mode with preallocated LZMA2
|
||||
* dictionary buffer. All data structures are
|
||||
* allocated at initialization, so xz_dec_run()
|
||||
* cannot return XZ_MEM_ERROR.
|
||||
* @XZ_DYNALLOC: Multi-call mode. The LZMA2 dictionary is
|
||||
* allocated once the required size has been
|
||||
* parsed from the stream headers. If the
|
||||
* allocation fails, xz_dec_run() will return
|
||||
* XZ_MEM_ERROR.
|
||||
*
|
||||
* It is possible to enable support only for a subset of the above
|
||||
* modes at compile time by defining XZ_DEC_SINGLE, XZ_DEC_PREALLOC,
|
||||
* or XZ_DEC_DYNALLOC. The xz_dec kernel module is always compiled
|
||||
* with support for all operation modes, but the preboot code may
|
||||
* be built with fewer features to minimize code size.
|
||||
*/
|
||||
enum xz_mode {
|
||||
XZ_SINGLE,
|
||||
XZ_PREALLOC,
|
||||
XZ_DYNALLOC
|
||||
};
|
||||
|
||||
/**
|
||||
* enum xz_ret - Return codes
|
||||
* @XZ_OK: Everything is OK so far. More input or more
|
||||
* output space is required to continue. This
|
||||
* return code is possible only in multi-call mode
|
||||
* (XZ_PREALLOC or XZ_DYNALLOC).
|
||||
* @XZ_STREAM_END: Operation finished successfully.
|
||||
* @XZ_UNSUPPORTED_CHECK: Integrity check type is not supported. Decoding
|
||||
* is still possible in multi-call mode by simply
|
||||
* calling xz_dec_run() again.
|
||||
* Note that this return value is used only if
|
||||
* XZ_DEC_ANY_CHECK was defined at build time,
|
||||
* which is not used in the kernel. Unsupported
|
||||
* check types return XZ_OPTIONS_ERROR if
|
||||
* XZ_DEC_ANY_CHECK was not defined at build time.
|
||||
* @XZ_MEM_ERROR: Allocating memory failed. This return code is
|
||||
* possible only if the decoder was initialized
|
||||
* with XZ_DYNALLOC. The amount of memory that was
|
||||
* tried to be allocated was no more than the
|
||||
* dict_max argument given to xz_dec_init().
|
||||
* @XZ_MEMLIMIT_ERROR: A bigger LZMA2 dictionary would be needed than
|
||||
* allowed by the dict_max argument given to
|
||||
* xz_dec_init(). This return value is possible
|
||||
* only in multi-call mode (XZ_PREALLOC or
|
||||
* XZ_DYNALLOC); the single-call mode (XZ_SINGLE)
|
||||
* ignores the dict_max argument.
|
||||
* @XZ_FORMAT_ERROR: File format was not recognized (wrong magic
|
||||
* bytes).
|
||||
* @XZ_OPTIONS_ERROR: This implementation doesn't support the requested
|
||||
* compression options. In the decoder this means
|
||||
* that the header CRC32 matches, but the header
|
||||
* itself specifies something that we don't support.
|
||||
* @XZ_DATA_ERROR: Compressed data is corrupt.
|
||||
* @XZ_BUF_ERROR: Cannot make any progress. Details are slightly
|
||||
* different between multi-call and single-call
|
||||
* mode; more information below.
|
||||
*
|
||||
* In multi-call mode, XZ_BUF_ERROR is returned when two consecutive calls
|
||||
* to XZ code cannot consume any input and cannot produce any new output.
|
||||
* This happens when there is no new input available, or the output buffer
|
||||
* is full while at least one output byte is still pending. Assuming your
|
||||
* code is not buggy, you can get this error only when decoding a compressed
|
||||
* stream that is truncated or otherwise corrupt.
|
||||
*
|
||||
* In single-call mode, XZ_BUF_ERROR is returned only when the output buffer
|
||||
* is too small or the compressed input is corrupt in a way that makes the
|
||||
* decoder produce more output than the caller expected. When it is
|
||||
* (relatively) clear that the compressed input is truncated, XZ_DATA_ERROR
|
||||
* is used instead of XZ_BUF_ERROR.
|
||||
*/
|
||||
enum xz_ret {
|
||||
XZ_OK,
|
||||
XZ_STREAM_END,
|
||||
XZ_UNSUPPORTED_CHECK,
|
||||
XZ_MEM_ERROR,
|
||||
XZ_MEMLIMIT_ERROR,
|
||||
XZ_FORMAT_ERROR,
|
||||
XZ_OPTIONS_ERROR,
|
||||
XZ_DATA_ERROR,
|
||||
XZ_BUF_ERROR
|
||||
};
|
||||
|
||||
/**
|
||||
* struct xz_buf - Passing input and output buffers to XZ code
|
||||
* @in: Beginning of the input buffer. This may be NULL if and only
|
||||
* if in_pos is equal to in_size.
|
||||
* @in_pos: Current position in the input buffer. This must not exceed
|
||||
* in_size.
|
||||
* @in_size: Size of the input buffer
|
||||
* @out: Beginning of the output buffer. This may be NULL if and only
|
||||
* if out_pos is equal to out_size.
|
||||
* @out_pos: Current position in the output buffer. This must not exceed
|
||||
* out_size.
|
||||
* @out_size: Size of the output buffer
|
||||
*
|
||||
* Only the contents of the output buffer from out[out_pos] onward, and
|
||||
* the variables in_pos and out_pos are modified by the XZ code.
|
||||
*/
|
||||
struct xz_buf {
|
||||
const uint8_t *in;
|
||||
size_t in_pos;
|
||||
size_t in_size;
|
||||
|
||||
uint8_t *out;
|
||||
size_t out_pos;
|
||||
size_t out_size;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct xz_dec - Opaque type to hold the XZ decoder state
|
||||
*/
|
||||
struct xz_dec;
|
||||
|
||||
/**
|
||||
* xz_dec_init() - Allocate and initialize a XZ decoder state
|
||||
* @mode: Operation mode
|
||||
* @dict_max: Maximum size of the LZMA2 dictionary (history buffer) for
|
||||
* multi-call decoding. This is ignored in single-call mode
|
||||
* (mode == XZ_SINGLE). LZMA2 dictionary is always 2^n bytes
|
||||
* or 2^n + 2^(n-1) bytes (the latter sizes are less common
|
||||
* in practice), so other values for dict_max don't make sense.
|
||||
* In the kernel, dictionary sizes of 64 KiB, 128 KiB, 256 KiB,
|
||||
* 512 KiB, and 1 MiB are probably the only reasonable values,
|
||||
* except for kernel and initramfs images where a bigger
|
||||
* dictionary can be fine and useful.
|
||||
*
|
||||
* Single-call mode (XZ_SINGLE): xz_dec_run() decodes the whole stream at
|
||||
* once. The caller must provide enough output space or the decoding will
|
||||
* fail. The output space is used as the dictionary buffer, which is why
|
||||
* there is no need to allocate the dictionary as part of the decoder's
|
||||
* internal state.
|
||||
*
|
||||
* Because the output buffer is used as the workspace, streams encoded using
|
||||
* a big dictionary are not a problem in single-call mode. It is enough that
|
||||
* the output buffer is big enough to hold the actual uncompressed data; it
|
||||
* can be smaller than the dictionary size stored in the stream headers.
|
||||
*
|
||||
* Multi-call mode with preallocated dictionary (XZ_PREALLOC): dict_max bytes
|
||||
* of memory is preallocated for the LZMA2 dictionary. This way there is no
|
||||
* risk that xz_dec_run() could run out of memory, since xz_dec_run() will
|
||||
* never allocate any memory. Instead, if the preallocated dictionary is too
|
||||
* small for decoding the given input stream, xz_dec_run() will return
|
||||
* XZ_MEMLIMIT_ERROR. Thus, it is important to know what kind of data will be
|
||||
* decoded to avoid allocating excessive amount of memory for the dictionary.
|
||||
*
|
||||
* Multi-call mode with dynamically allocated dictionary (XZ_DYNALLOC):
|
||||
* dict_max specifies the maximum allowed dictionary size that xz_dec_run()
|
||||
* may allocate once it has parsed the dictionary size from the stream
|
||||
* headers. This way excessive allocations can be avoided while still
|
||||
* limiting the maximum memory usage to a sane value to prevent running the
|
||||
* system out of memory when decompressing streams from untrusted sources.
|
||||
*
|
||||
* On success, xz_dec_init() returns a pointer to struct xz_dec, which is
|
||||
* ready to be used with xz_dec_run(). If memory allocation fails,
|
||||
* xz_dec_init() returns NULL.
|
||||
*/
|
||||
XZ_EXTERN struct xz_dec *xz_dec_init(enum xz_mode mode, uint32_t dict_max);
|
||||
|
||||
/**
|
||||
* xz_dec_run() - Run the XZ decoder
|
||||
* @s: Decoder state allocated using xz_dec_init()
|
||||
* @b: Input and output buffers
|
||||
*
|
||||
* The possible return values depend on build options and operation mode.
|
||||
* See enum xz_ret for details.
|
||||
*
|
||||
* Note that if an error occurs in single-call mode (return value is not
|
||||
* XZ_STREAM_END), b->in_pos and b->out_pos are not modified and the
|
||||
* contents of the output buffer from b->out[b->out_pos] onward are
|
||||
* undefined. This is true even after XZ_BUF_ERROR, because with some filter
|
||||
* chains, there may be a second pass over the output buffer, and this pass
|
||||
* cannot be properly done if the output buffer is truncated. Thus, you
|
||||
* cannot give the single-call decoder a too small buffer and then expect to
|
||||
* get that amount valid data from the beginning of the stream. You must use
|
||||
* the multi-call decoder if you don't want to uncompress the whole stream.
|
||||
*/
|
||||
XZ_EXTERN enum xz_ret xz_dec_run(struct xz_dec *s, struct xz_buf *b);
|
||||
|
||||
/**
|
||||
* xz_dec_reset() - Reset an already allocated decoder state
|
||||
* @s: Decoder state allocated using xz_dec_init()
|
||||
*
|
||||
* This function can be used to reset the multi-call decoder state without
|
||||
* freeing and reallocating memory with xz_dec_end() and xz_dec_init().
|
||||
*
|
||||
* In single-call mode, xz_dec_reset() is always called in the beginning of
|
||||
* xz_dec_run(). Thus, explicit call to xz_dec_reset() is useful only in
|
||||
* multi-call mode.
|
||||
*/
|
||||
XZ_EXTERN void xz_dec_reset(struct xz_dec *s);
|
||||
|
||||
/**
|
||||
* xz_dec_end() - Free the memory allocated for the decoder state
|
||||
* @s: Decoder state allocated using xz_dec_init(). If s is NULL,
|
||||
* this function does nothing.
|
||||
*/
|
||||
XZ_EXTERN void xz_dec_end(struct xz_dec *s);
|
||||
|
||||
/*
|
||||
* Standalone build (userspace build or in-kernel build for boot time use)
|
||||
* needs a CRC32 implementation. For normal in-kernel use, kernel's own
|
||||
* CRC32 module is used instead, and users of this module don't need to
|
||||
* care about the functions below.
|
||||
*/
|
||||
#ifndef XZ_INTERNAL_CRC32
|
||||
# ifdef __KERNEL__
|
||||
# define XZ_INTERNAL_CRC32 0
|
||||
# else
|
||||
# define XZ_INTERNAL_CRC32 1
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
* If CRC64 support has been enabled with XZ_USE_CRC64, a CRC64
|
||||
* implementation is needed too.
|
||||
*/
|
||||
#ifndef XZ_USE_CRC64
|
||||
# undef XZ_INTERNAL_CRC64
|
||||
# define XZ_INTERNAL_CRC64 0
|
||||
#endif
|
||||
#ifndef XZ_INTERNAL_CRC64
|
||||
# ifdef __KERNEL__
|
||||
# error Using CRC64 in the kernel has not been implemented.
|
||||
# else
|
||||
# define XZ_INTERNAL_CRC64 1
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if XZ_INTERNAL_CRC32
|
||||
/*
|
||||
* This must be called before any other xz_* function to initialize
|
||||
* the CRC32 lookup table.
|
||||
*/
|
||||
XZ_EXTERN void xz_crc32_init(void);
|
||||
|
||||
/*
|
||||
* Update CRC32 value using the polynomial from IEEE-802.3. To start a new
|
||||
* calculation, the third argument must be zero. To continue the calculation,
|
||||
* the previously returned value is passed as the third argument.
|
||||
*/
|
||||
XZ_EXTERN uint32_t xz_crc32(const uint8_t *buf, size_t size, uint32_t crc);
|
||||
#endif
|
||||
|
||||
#if XZ_INTERNAL_CRC64
|
||||
/*
|
||||
* This must be called before any other xz_* function (except xz_crc32_init())
|
||||
* to initialize the CRC64 lookup table.
|
||||
*/
|
||||
XZ_EXTERN void xz_crc64_init(void);
|
||||
|
||||
/*
|
||||
* Update CRC64 value using the polynomial from ECMA-182. To start a new
|
||||
* calculation, the third argument must be zero. To continue the calculation,
|
||||
* the previously returned value is passed as the third argument.
|
||||
*/
|
||||
XZ_EXTERN uint64_t xz_crc64(const uint8_t *buf, size_t size, uint64_t crc);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
397
LinuxGUI/Ventoy2Disk/Lib/xz-embedded/linux/lib/decompress_unxz.c
Normal file
397
LinuxGUI/Ventoy2Disk/Lib/xz-embedded/linux/lib/decompress_unxz.c
Normal file
@@ -0,0 +1,397 @@
|
||||
/*
|
||||
* Wrapper for decompressing XZ-compressed kernel, initramfs, and initrd
|
||||
*
|
||||
* Author: Lasse Collin <lasse.collin@tukaani.org>
|
||||
*
|
||||
* This file has been put into the public domain.
|
||||
* You can do whatever you want with this file.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Important notes about in-place decompression
|
||||
*
|
||||
* At least on x86, the kernel is decompressed in place: the compressed data
|
||||
* is placed to the end of the output buffer, and the decompressor overwrites
|
||||
* most of the compressed data. There must be enough safety margin to
|
||||
* guarantee that the write position is always behind the read position.
|
||||
*
|
||||
* The safety margin for XZ with LZMA2 or BCJ+LZMA2 is calculated below.
|
||||
* Note that the margin with XZ is bigger than with Deflate (gzip)!
|
||||
*
|
||||
* The worst case for in-place decompression is that the beginning of
|
||||
* the file is compressed extremely well, and the rest of the file is
|
||||
* uncompressible. Thus, we must look for worst-case expansion when the
|
||||
* compressor is encoding uncompressible data.
|
||||
*
|
||||
* The structure of the .xz file in case of a compresed kernel is as follows.
|
||||
* Sizes (as bytes) of the fields are in parenthesis.
|
||||
*
|
||||
* Stream Header (12)
|
||||
* Block Header:
|
||||
* Block Header (8-12)
|
||||
* Compressed Data (N)
|
||||
* Block Padding (0-3)
|
||||
* CRC32 (4)
|
||||
* Index (8-20)
|
||||
* Stream Footer (12)
|
||||
*
|
||||
* Normally there is exactly one Block, but let's assume that there are
|
||||
* 2-4 Blocks just in case. Because Stream Header and also Block Header
|
||||
* of the first Block don't make the decompressor produce any uncompressed
|
||||
* data, we can ignore them from our calculations. Block Headers of possible
|
||||
* additional Blocks have to be taken into account still. With these
|
||||
* assumptions, it is safe to assume that the total header overhead is
|
||||
* less than 128 bytes.
|
||||
*
|
||||
* Compressed Data contains LZMA2 or BCJ+LZMA2 encoded data. Since BCJ
|
||||
* doesn't change the size of the data, it is enough to calculate the
|
||||
* safety margin for LZMA2.
|
||||
*
|
||||
* LZMA2 stores the data in chunks. Each chunk has a header whose size is
|
||||
* a maximum of 6 bytes, but to get round 2^n numbers, let's assume that
|
||||
* the maximum chunk header size is 8 bytes. After the chunk header, there
|
||||
* may be up to 64 KiB of actual payload in the chunk. Often the payload is
|
||||
* quite a bit smaller though; to be safe, let's assume that an average
|
||||
* chunk has only 32 KiB of payload.
|
||||
*
|
||||
* The maximum uncompressed size of the payload is 2 MiB. The minimum
|
||||
* uncompressed size of the payload is in practice never less than the
|
||||
* payload size itself. The LZMA2 format would allow uncompressed size
|
||||
* to be less than the payload size, but no sane compressor creates such
|
||||
* files. LZMA2 supports storing uncompressible data in uncompressed form,
|
||||
* so there's never a need to create payloads whose uncompressed size is
|
||||
* smaller than the compressed size.
|
||||
*
|
||||
* The assumption, that the uncompressed size of the payload is never
|
||||
* smaller than the payload itself, is valid only when talking about
|
||||
* the payload as a whole. It is possible that the payload has parts where
|
||||
* the decompressor consumes more input than it produces output. Calculating
|
||||
* the worst case for this would be tricky. Instead of trying to do that,
|
||||
* let's simply make sure that the decompressor never overwrites any bytes
|
||||
* of the payload which it is currently reading.
|
||||
*
|
||||
* Now we have enough information to calculate the safety margin. We need
|
||||
* - 128 bytes for the .xz file format headers;
|
||||
* - 8 bytes per every 32 KiB of uncompressed size (one LZMA2 chunk header
|
||||
* per chunk, each chunk having average payload size of 32 KiB); and
|
||||
* - 64 KiB (biggest possible LZMA2 chunk payload size) to make sure that
|
||||
* the decompressor never overwrites anything from the LZMA2 chunk
|
||||
* payload it is currently reading.
|
||||
*
|
||||
* We get the following formula:
|
||||
*
|
||||
* safety_margin = 128 + uncompressed_size * 8 / 32768 + 65536
|
||||
* = 128 + (uncompressed_size >> 12) + 65536
|
||||
*
|
||||
* For comparison, according to arch/x86/boot/compressed/misc.c, the
|
||||
* equivalent formula for Deflate is this:
|
||||
*
|
||||
* safety_margin = 18 + (uncompressed_size >> 12) + 32768
|
||||
*
|
||||
* Thus, when updating Deflate-only in-place kernel decompressor to
|
||||
* support XZ, the fixed overhead has to be increased from 18+32768 bytes
|
||||
* to 128+65536 bytes.
|
||||
*/
|
||||
|
||||
/*
|
||||
* STATIC is defined to "static" if we are being built for kernel
|
||||
* decompression (pre-boot code). <linux/decompress/mm.h> will define
|
||||
* STATIC to empty if it wasn't already defined. Since we will need to
|
||||
* know later if we are being used for kernel decompression, we define
|
||||
* XZ_PREBOOT here.
|
||||
*/
|
||||
#ifdef STATIC
|
||||
# define XZ_PREBOOT
|
||||
#endif
|
||||
#ifdef __KERNEL__
|
||||
# include <linux/decompress/mm.h>
|
||||
#endif
|
||||
#define XZ_EXTERN STATIC
|
||||
|
||||
#ifndef XZ_PREBOOT
|
||||
# include <linux/slab.h>
|
||||
# include <linux/xz.h>
|
||||
#else
|
||||
/*
|
||||
* Use the internal CRC32 code instead of kernel's CRC32 module, which
|
||||
* is not available in early phase of booting.
|
||||
*/
|
||||
#define XZ_INTERNAL_CRC32 1
|
||||
|
||||
/*
|
||||
* For boot time use, we enable only the BCJ filter of the current
|
||||
* architecture or none if no BCJ filter is available for the architecture.
|
||||
*/
|
||||
#ifdef CONFIG_X86
|
||||
# define XZ_DEC_X86
|
||||
#endif
|
||||
#ifdef CONFIG_PPC
|
||||
# define XZ_DEC_POWERPC
|
||||
#endif
|
||||
#ifdef CONFIG_ARM
|
||||
# define XZ_DEC_ARM
|
||||
#endif
|
||||
#ifdef CONFIG_IA64
|
||||
# define XZ_DEC_IA64
|
||||
#endif
|
||||
#ifdef CONFIG_SPARC
|
||||
# define XZ_DEC_SPARC
|
||||
#endif
|
||||
|
||||
/*
|
||||
* This will get the basic headers so that memeq() and others
|
||||
* can be defined.
|
||||
*/
|
||||
#include "xz/xz_private.h"
|
||||
|
||||
/*
|
||||
* Replace the normal allocation functions with the versions from
|
||||
* <linux/decompress/mm.h>. vfree() needs to support vfree(NULL)
|
||||
* when XZ_DYNALLOC is used, but the pre-boot free() doesn't support it.
|
||||
* Workaround it here because the other decompressors don't need it.
|
||||
*/
|
||||
#undef kmalloc
|
||||
#undef kfree
|
||||
#undef vmalloc
|
||||
#undef vfree
|
||||
#define kmalloc(size, flags) malloc(size)
|
||||
#define kfree(ptr) free(ptr)
|
||||
#define vmalloc(size) malloc(size)
|
||||
#define vfree(ptr) do { if (ptr != NULL) free(ptr); } while (0)
|
||||
|
||||
/*
|
||||
* FIXME: Not all basic memory functions are provided in architecture-specific
|
||||
* files (yet). We define our own versions here for now, but this should be
|
||||
* only a temporary solution.
|
||||
*
|
||||
* memeq and memzero are not used much and any remotely sane implementation
|
||||
* is fast enough. memcpy/memmove speed matters in multi-call mode, but
|
||||
* the kernel image is decompressed in single-call mode, in which only
|
||||
* memcpy speed can matter and only if there is a lot of uncompressible data
|
||||
* (LZMA2 stores uncompressible chunks in uncompressed form). Thus, the
|
||||
* functions below should just be kept small; it's probably not worth
|
||||
* optimizing for speed.
|
||||
*/
|
||||
|
||||
#ifndef memeq
|
||||
static bool memeq(const void *a, const void *b, size_t size)
|
||||
{
|
||||
const uint8_t *x = a;
|
||||
const uint8_t *y = b;
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < size; ++i)
|
||||
if (x[i] != y[i])
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef memzero
|
||||
static void memzero(void *buf, size_t size)
|
||||
{
|
||||
uint8_t *b = buf;
|
||||
uint8_t *e = b + size;
|
||||
|
||||
while (b != e)
|
||||
*b++ = '\0';
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
/* Not static to avoid a conflict with the prototype in the Linux headers. */
|
||||
void *memmove(void *dest, const void *src, size_t size)
|
||||
{
|
||||
uint8_t *d = dest;
|
||||
const uint8_t *s = src;
|
||||
size_t i;
|
||||
|
||||
if (d < s) {
|
||||
for (i = 0; i < size; ++i)
|
||||
d[i] = s[i];
|
||||
} else if (d > s) {
|
||||
i = size;
|
||||
while (i-- > 0)
|
||||
d[i] = s[i];
|
||||
}
|
||||
|
||||
return dest;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Since we need memmove anyway, would use it as memcpy too.
|
||||
* Commented out for now to avoid breaking things.
|
||||
*/
|
||||
/*
|
||||
#ifndef memcpy
|
||||
# define memcpy memmove
|
||||
#endif
|
||||
*/
|
||||
|
||||
#include "xz/xz_crc32.c"
|
||||
#include "xz/xz_dec_stream.c"
|
||||
#include "xz/xz_dec_lzma2.c"
|
||||
#include "xz/xz_dec_bcj.c"
|
||||
|
||||
#endif /* XZ_PREBOOT */
|
||||
|
||||
/* Size of the input and output buffers in multi-call mode */
|
||||
#define XZ_IOBUF_SIZE 4096
|
||||
|
||||
/*
|
||||
* This function implements the API defined in <linux/decompress/generic.h>.
|
||||
*
|
||||
* This wrapper will automatically choose single-call or multi-call mode
|
||||
* of the native XZ decoder API. The single-call mode can be used only when
|
||||
* both input and output buffers are available as a single chunk, i.e. when
|
||||
* fill() and flush() won't be used.
|
||||
*/
|
||||
int INIT unxz(unsigned char *in, int in_size,
|
||||
int (*fill)(void *dest, unsigned int size),
|
||||
int (*flush)(void *src, unsigned int size),
|
||||
unsigned char *out, int *in_used,
|
||||
void (*error)(char *x))
|
||||
{
|
||||
struct xz_buf b;
|
||||
struct xz_dec *s;
|
||||
enum xz_ret ret;
|
||||
bool must_free_in = false;
|
||||
|
||||
#if XZ_INTERNAL_CRC32
|
||||
xz_crc32_init();
|
||||
#endif
|
||||
|
||||
if (in_used != NULL)
|
||||
*in_used = 0;
|
||||
|
||||
if (fill == NULL && flush == NULL)
|
||||
s = xz_dec_init(XZ_SINGLE, 0);
|
||||
else
|
||||
s = xz_dec_init(XZ_DYNALLOC, (uint32_t)-1);
|
||||
|
||||
if (s == NULL)
|
||||
goto error_alloc_state;
|
||||
|
||||
if (flush == NULL) {
|
||||
b.out = out;
|
||||
b.out_size = (size_t)-1;
|
||||
} else {
|
||||
b.out_size = XZ_IOBUF_SIZE;
|
||||
b.out = malloc(XZ_IOBUF_SIZE);
|
||||
if (b.out == NULL)
|
||||
goto error_alloc_out;
|
||||
}
|
||||
|
||||
if (in == NULL) {
|
||||
must_free_in = true;
|
||||
in = malloc(XZ_IOBUF_SIZE);
|
||||
if (in == NULL)
|
||||
goto error_alloc_in;
|
||||
}
|
||||
|
||||
b.in = in;
|
||||
b.in_pos = 0;
|
||||
b.in_size = in_size;
|
||||
b.out_pos = 0;
|
||||
|
||||
if (fill == NULL && flush == NULL) {
|
||||
ret = xz_dec_run(s, &b);
|
||||
} else {
|
||||
do {
|
||||
if (b.in_pos == b.in_size && fill != NULL) {
|
||||
if (in_used != NULL)
|
||||
*in_used += b.in_pos;
|
||||
|
||||
b.in_pos = 0;
|
||||
|
||||
in_size = fill(in, XZ_IOBUF_SIZE);
|
||||
if (in_size < 0) {
|
||||
/*
|
||||
* This isn't an optimal error code
|
||||
* but it probably isn't worth making
|
||||
* a new one either.
|
||||
*/
|
||||
ret = XZ_BUF_ERROR;
|
||||
break;
|
||||
}
|
||||
|
||||
b.in_size = in_size;
|
||||
}
|
||||
|
||||
ret = xz_dec_run(s, &b);
|
||||
|
||||
if (flush != NULL && (b.out_pos == b.out_size
|
||||
|| (ret != XZ_OK && b.out_pos > 0))) {
|
||||
/*
|
||||
* Setting ret here may hide an error
|
||||
* returned by xz_dec_run(), but probably
|
||||
* it's not too bad.
|
||||
*/
|
||||
if (flush(b.out, b.out_pos) != (int)b.out_pos)
|
||||
ret = XZ_BUF_ERROR;
|
||||
|
||||
b.out_pos = 0;
|
||||
}
|
||||
} while (ret == XZ_OK);
|
||||
|
||||
if (must_free_in)
|
||||
free(in);
|
||||
|
||||
if (flush != NULL)
|
||||
free(b.out);
|
||||
}
|
||||
|
||||
if (in_used != NULL)
|
||||
*in_used += b.in_pos;
|
||||
|
||||
xz_dec_end(s);
|
||||
|
||||
switch (ret) {
|
||||
case XZ_STREAM_END:
|
||||
return 0;
|
||||
|
||||
case XZ_MEM_ERROR:
|
||||
/* This can occur only in multi-call mode. */
|
||||
error("XZ decompressor ran out of memory");
|
||||
break;
|
||||
|
||||
case XZ_FORMAT_ERROR:
|
||||
error("Input is not in the XZ format (wrong magic bytes)");
|
||||
break;
|
||||
|
||||
case XZ_OPTIONS_ERROR:
|
||||
error("Input was encoded with settings that are not "
|
||||
"supported by this XZ decoder");
|
||||
break;
|
||||
|
||||
case XZ_DATA_ERROR:
|
||||
case XZ_BUF_ERROR:
|
||||
error("XZ-compressed data is corrupt");
|
||||
break;
|
||||
|
||||
default:
|
||||
error("Bug in the XZ decompressor");
|
||||
break;
|
||||
}
|
||||
|
||||
return -1;
|
||||
|
||||
error_alloc_in:
|
||||
if (flush != NULL)
|
||||
free(b.out);
|
||||
|
||||
error_alloc_out:
|
||||
xz_dec_end(s);
|
||||
|
||||
error_alloc_state:
|
||||
error("XZ decompressor ran out of memory");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* This macro is used by architecture-specific files to decompress
|
||||
* the kernel image.
|
||||
*/
|
||||
#define decompress unxz
|
||||
57
LinuxGUI/Ventoy2Disk/Lib/xz-embedded/linux/lib/xz/Kconfig
Normal file
57
LinuxGUI/Ventoy2Disk/Lib/xz-embedded/linux/lib/xz/Kconfig
Normal file
@@ -0,0 +1,57 @@
|
||||
config XZ_DEC
|
||||
tristate "XZ decompression support"
|
||||
select CRC32
|
||||
help
|
||||
LZMA2 compression algorithm and BCJ filters are supported using
|
||||
the .xz file format as the container. For integrity checking,
|
||||
CRC32 is supported. See Documentation/xz.txt for more information.
|
||||
|
||||
if XZ_DEC
|
||||
|
||||
config XZ_DEC_X86
|
||||
bool "x86 BCJ filter decoder"
|
||||
default y if X86
|
||||
select XZ_DEC_BCJ
|
||||
|
||||
config XZ_DEC_POWERPC
|
||||
bool "PowerPC BCJ filter decoder"
|
||||
default y if PPC
|
||||
select XZ_DEC_BCJ
|
||||
|
||||
config XZ_DEC_IA64
|
||||
bool "IA-64 BCJ filter decoder"
|
||||
default y if IA64
|
||||
select XZ_DEC_BCJ
|
||||
|
||||
config XZ_DEC_ARM
|
||||
bool "ARM BCJ filter decoder"
|
||||
default y if ARM
|
||||
select XZ_DEC_BCJ
|
||||
|
||||
config XZ_DEC_ARMTHUMB
|
||||
bool "ARM-Thumb BCJ filter decoder"
|
||||
default y if (ARM && ARM_THUMB)
|
||||
select XZ_DEC_BCJ
|
||||
|
||||
config XZ_DEC_SPARC
|
||||
bool "SPARC BCJ filter decoder"
|
||||
default y if SPARC
|
||||
select XZ_DEC_BCJ
|
||||
|
||||
endif
|
||||
|
||||
config XZ_DEC_BCJ
|
||||
bool
|
||||
default n
|
||||
|
||||
config XZ_DEC_TEST
|
||||
tristate "XZ decompressor tester"
|
||||
default n
|
||||
depends on XZ_DEC
|
||||
help
|
||||
This allows passing .xz files to the in-kernel XZ decoder via
|
||||
a character special file. It calculates CRC32 of the decompressed
|
||||
data and writes diagnostics to the system log.
|
||||
|
||||
Unless you are developing the XZ decoder, you don't need this
|
||||
and should say N.
|
||||
@@ -0,0 +1,5 @@
|
||||
obj-$(CONFIG_XZ_DEC) += xz_dec.o
|
||||
xz_dec-y := xz_dec_syms.o xz_dec_stream.o xz_dec_lzma2.o
|
||||
xz_dec-$(CONFIG_XZ_DEC_BCJ) += xz_dec_bcj.o
|
||||
|
||||
obj-$(CONFIG_XZ_DEC_TEST) += xz_dec_test.o
|
||||
59
LinuxGUI/Ventoy2Disk/Lib/xz-embedded/linux/lib/xz/xz_crc32.c
Normal file
59
LinuxGUI/Ventoy2Disk/Lib/xz-embedded/linux/lib/xz/xz_crc32.c
Normal file
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* CRC32 using the polynomial from IEEE-802.3
|
||||
*
|
||||
* Authors: Lasse Collin <lasse.collin@tukaani.org>
|
||||
* Igor Pavlov <http://7-zip.org/>
|
||||
*
|
||||
* This file has been put into the public domain.
|
||||
* You can do whatever you want with this file.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This is not the fastest implementation, but it is pretty compact.
|
||||
* The fastest versions of xz_crc32() on modern CPUs without hardware
|
||||
* accelerated CRC instruction are 3-5 times as fast as this version,
|
||||
* but they are bigger and use more memory for the lookup table.
|
||||
*/
|
||||
|
||||
#include "xz_private.h"
|
||||
|
||||
/*
|
||||
* STATIC_RW_DATA is used in the pre-boot environment on some architectures.
|
||||
* See <linux/decompress/mm.h> for details.
|
||||
*/
|
||||
#ifndef STATIC_RW_DATA
|
||||
# define STATIC_RW_DATA static
|
||||
#endif
|
||||
|
||||
STATIC_RW_DATA uint32_t xz_crc32_table[256];
|
||||
|
||||
XZ_EXTERN void xz_crc32_init(void)
|
||||
{
|
||||
const uint32_t poly = 0xEDB88320;
|
||||
|
||||
uint32_t i;
|
||||
uint32_t j;
|
||||
uint32_t r;
|
||||
|
||||
for (i = 0; i < 256; ++i) {
|
||||
r = i;
|
||||
for (j = 0; j < 8; ++j)
|
||||
r = (r >> 1) ^ (poly & ~((r & 1) - 1));
|
||||
|
||||
xz_crc32_table[i] = r;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
XZ_EXTERN uint32_t xz_crc32(const uint8_t *buf, size_t size, uint32_t crc)
|
||||
{
|
||||
crc = ~crc;
|
||||
|
||||
while (size != 0) {
|
||||
crc = xz_crc32_table[*buf++ ^ (crc & 0xFF)] ^ (crc >> 8);
|
||||
--size;
|
||||
}
|
||||
|
||||
return ~crc;
|
||||
}
|
||||
50
LinuxGUI/Ventoy2Disk/Lib/xz-embedded/linux/lib/xz/xz_crc64.c
Normal file
50
LinuxGUI/Ventoy2Disk/Lib/xz-embedded/linux/lib/xz/xz_crc64.c
Normal file
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* CRC64 using the polynomial from ECMA-182
|
||||
*
|
||||
* This file is similar to xz_crc32.c. See the comments there.
|
||||
*
|
||||
* Authors: Lasse Collin <lasse.collin@tukaani.org>
|
||||
* Igor Pavlov <http://7-zip.org/>
|
||||
*
|
||||
* This file has been put into the public domain.
|
||||
* You can do whatever you want with this file.
|
||||
*/
|
||||
|
||||
#include "xz_private.h"
|
||||
|
||||
#ifndef STATIC_RW_DATA
|
||||
# define STATIC_RW_DATA static
|
||||
#endif
|
||||
|
||||
STATIC_RW_DATA uint64_t xz_crc64_table[256];
|
||||
|
||||
XZ_EXTERN void xz_crc64_init(void)
|
||||
{
|
||||
const uint64_t poly = 0xC96C5795D7870F42;
|
||||
|
||||
uint32_t i;
|
||||
uint32_t j;
|
||||
uint64_t r;
|
||||
|
||||
for (i = 0; i < 256; ++i) {
|
||||
r = i;
|
||||
for (j = 0; j < 8; ++j)
|
||||
r = (r >> 1) ^ (poly & ~((r & 1) - 1));
|
||||
|
||||
xz_crc64_table[i] = r;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
XZ_EXTERN uint64_t xz_crc64(const uint8_t *buf, size_t size, uint64_t crc)
|
||||
{
|
||||
crc = ~crc;
|
||||
|
||||
while (size != 0) {
|
||||
crc = xz_crc64_table[*buf++ ^ (crc & 0xFF)] ^ (crc >> 8);
|
||||
--size;
|
||||
}
|
||||
|
||||
return ~crc;
|
||||
}
|
||||
574
LinuxGUI/Ventoy2Disk/Lib/xz-embedded/linux/lib/xz/xz_dec_bcj.c
Normal file
574
LinuxGUI/Ventoy2Disk/Lib/xz-embedded/linux/lib/xz/xz_dec_bcj.c
Normal file
@@ -0,0 +1,574 @@
|
||||
/*
|
||||
* Branch/Call/Jump (BCJ) filter decoders
|
||||
*
|
||||
* Authors: Lasse Collin <lasse.collin@tukaani.org>
|
||||
* Igor Pavlov <http://7-zip.org/>
|
||||
*
|
||||
* This file has been put into the public domain.
|
||||
* You can do whatever you want with this file.
|
||||
*/
|
||||
|
||||
#include "xz_private.h"
|
||||
|
||||
/*
|
||||
* The rest of the file is inside this ifdef. It makes things a little more
|
||||
* convenient when building without support for any BCJ filters.
|
||||
*/
|
||||
#ifdef XZ_DEC_BCJ
|
||||
|
||||
struct xz_dec_bcj {
|
||||
/* Type of the BCJ filter being used */
|
||||
enum {
|
||||
BCJ_X86 = 4, /* x86 or x86-64 */
|
||||
BCJ_POWERPC = 5, /* Big endian only */
|
||||
BCJ_IA64 = 6, /* Big or little endian */
|
||||
BCJ_ARM = 7, /* Little endian only */
|
||||
BCJ_ARMTHUMB = 8, /* Little endian only */
|
||||
BCJ_SPARC = 9 /* Big or little endian */
|
||||
} type;
|
||||
|
||||
/*
|
||||
* Return value of the next filter in the chain. We need to preserve
|
||||
* this information across calls, because we must not call the next
|
||||
* filter anymore once it has returned XZ_STREAM_END.
|
||||
*/
|
||||
enum xz_ret ret;
|
||||
|
||||
/* True if we are operating in single-call mode. */
|
||||
bool single_call;
|
||||
|
||||
/*
|
||||
* Absolute position relative to the beginning of the uncompressed
|
||||
* data (in a single .xz Block). We care only about the lowest 32
|
||||
* bits so this doesn't need to be uint64_t even with big files.
|
||||
*/
|
||||
uint32_t pos;
|
||||
|
||||
/* x86 filter state */
|
||||
uint32_t x86_prev_mask;
|
||||
|
||||
/* Temporary space to hold the variables from struct xz_buf */
|
||||
uint8_t *out;
|
||||
size_t out_pos;
|
||||
size_t out_size;
|
||||
|
||||
struct {
|
||||
/* Amount of already filtered data in the beginning of buf */
|
||||
size_t filtered;
|
||||
|
||||
/* Total amount of data currently stored in buf */
|
||||
size_t size;
|
||||
|
||||
/*
|
||||
* Buffer to hold a mix of filtered and unfiltered data. This
|
||||
* needs to be big enough to hold Alignment + 2 * Look-ahead:
|
||||
*
|
||||
* Type Alignment Look-ahead
|
||||
* x86 1 4
|
||||
* PowerPC 4 0
|
||||
* IA-64 16 0
|
||||
* ARM 4 0
|
||||
* ARM-Thumb 2 2
|
||||
* SPARC 4 0
|
||||
*/
|
||||
uint8_t buf[16];
|
||||
} temp;
|
||||
};
|
||||
|
||||
#ifdef XZ_DEC_X86
|
||||
/*
|
||||
* This is used to test the most significant byte of a memory address
|
||||
* in an x86 instruction.
|
||||
*/
|
||||
static inline int bcj_x86_test_msbyte(uint8_t b)
|
||||
{
|
||||
return b == 0x00 || b == 0xFF;
|
||||
}
|
||||
|
||||
static size_t bcj_x86(struct xz_dec_bcj *s, uint8_t *buf, size_t size)
|
||||
{
|
||||
static const bool mask_to_allowed_status[8]
|
||||
= { true, true, true, false, true, false, false, false };
|
||||
|
||||
static const uint8_t mask_to_bit_num[8] = { 0, 1, 2, 2, 3, 3, 3, 3 };
|
||||
|
||||
size_t i;
|
||||
size_t prev_pos = (size_t)-1;
|
||||
uint32_t prev_mask = s->x86_prev_mask;
|
||||
uint32_t src;
|
||||
uint32_t dest;
|
||||
uint32_t j;
|
||||
uint8_t b;
|
||||
|
||||
if (size <= 4)
|
||||
return 0;
|
||||
|
||||
size -= 4;
|
||||
for (i = 0; i < size; ++i) {
|
||||
if ((buf[i] & 0xFE) != 0xE8)
|
||||
continue;
|
||||
|
||||
prev_pos = i - prev_pos;
|
||||
if (prev_pos > 3) {
|
||||
prev_mask = 0;
|
||||
} else {
|
||||
prev_mask = (prev_mask << (prev_pos - 1)) & 7;
|
||||
if (prev_mask != 0) {
|
||||
b = buf[i + 4 - mask_to_bit_num[prev_mask]];
|
||||
if (!mask_to_allowed_status[prev_mask]
|
||||
|| bcj_x86_test_msbyte(b)) {
|
||||
prev_pos = i;
|
||||
prev_mask = (prev_mask << 1) | 1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
prev_pos = i;
|
||||
|
||||
if (bcj_x86_test_msbyte(buf[i + 4])) {
|
||||
src = get_unaligned_le32(buf + i + 1);
|
||||
while (true) {
|
||||
dest = src - (s->pos + (uint32_t)i + 5);
|
||||
if (prev_mask == 0)
|
||||
break;
|
||||
|
||||
j = mask_to_bit_num[prev_mask] * 8;
|
||||
b = (uint8_t)(dest >> (24 - j));
|
||||
if (!bcj_x86_test_msbyte(b))
|
||||
break;
|
||||
|
||||
src = dest ^ (((uint32_t)1 << (32 - j)) - 1);
|
||||
}
|
||||
|
||||
dest &= 0x01FFFFFF;
|
||||
dest |= (uint32_t)0 - (dest & 0x01000000);
|
||||
put_unaligned_le32(dest, buf + i + 1);
|
||||
i += 4;
|
||||
} else {
|
||||
prev_mask = (prev_mask << 1) | 1;
|
||||
}
|
||||
}
|
||||
|
||||
prev_pos = i - prev_pos;
|
||||
s->x86_prev_mask = prev_pos > 3 ? 0 : prev_mask << (prev_pos - 1);
|
||||
return i;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef XZ_DEC_POWERPC
|
||||
static size_t bcj_powerpc(struct xz_dec_bcj *s, uint8_t *buf, size_t size)
|
||||
{
|
||||
size_t i;
|
||||
uint32_t instr;
|
||||
|
||||
for (i = 0; i + 4 <= size; i += 4) {
|
||||
instr = get_unaligned_be32(buf + i);
|
||||
if ((instr & 0xFC000003) == 0x48000001) {
|
||||
instr &= 0x03FFFFFC;
|
||||
instr -= s->pos + (uint32_t)i;
|
||||
instr &= 0x03FFFFFC;
|
||||
instr |= 0x48000001;
|
||||
put_unaligned_be32(instr, buf + i);
|
||||
}
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef XZ_DEC_IA64
|
||||
static size_t bcj_ia64(struct xz_dec_bcj *s, uint8_t *buf, size_t size)
|
||||
{
|
||||
static const uint8_t branch_table[32] = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
4, 4, 6, 6, 0, 0, 7, 7,
|
||||
4, 4, 0, 0, 4, 4, 0, 0
|
||||
};
|
||||
|
||||
/*
|
||||
* The local variables take a little bit stack space, but it's less
|
||||
* than what LZMA2 decoder takes, so it doesn't make sense to reduce
|
||||
* stack usage here without doing that for the LZMA2 decoder too.
|
||||
*/
|
||||
|
||||
/* Loop counters */
|
||||
size_t i;
|
||||
size_t j;
|
||||
|
||||
/* Instruction slot (0, 1, or 2) in the 128-bit instruction word */
|
||||
uint32_t slot;
|
||||
|
||||
/* Bitwise offset of the instruction indicated by slot */
|
||||
uint32_t bit_pos;
|
||||
|
||||
/* bit_pos split into byte and bit parts */
|
||||
uint32_t byte_pos;
|
||||
uint32_t bit_res;
|
||||
|
||||
/* Address part of an instruction */
|
||||
uint32_t addr;
|
||||
|
||||
/* Mask used to detect which instructions to convert */
|
||||
uint32_t mask;
|
||||
|
||||
/* 41-bit instruction stored somewhere in the lowest 48 bits */
|
||||
uint64_t instr;
|
||||
|
||||
/* Instruction normalized with bit_res for easier manipulation */
|
||||
uint64_t norm;
|
||||
|
||||
for (i = 0; i + 16 <= size; i += 16) {
|
||||
mask = branch_table[buf[i] & 0x1F];
|
||||
for (slot = 0, bit_pos = 5; slot < 3; ++slot, bit_pos += 41) {
|
||||
if (((mask >> slot) & 1) == 0)
|
||||
continue;
|
||||
|
||||
byte_pos = bit_pos >> 3;
|
||||
bit_res = bit_pos & 7;
|
||||
instr = 0;
|
||||
for (j = 0; j < 6; ++j)
|
||||
instr |= (uint64_t)(buf[i + j + byte_pos])
|
||||
<< (8 * j);
|
||||
|
||||
norm = instr >> bit_res;
|
||||
|
||||
if (((norm >> 37) & 0x0F) == 0x05
|
||||
&& ((norm >> 9) & 0x07) == 0) {
|
||||
addr = (norm >> 13) & 0x0FFFFF;
|
||||
addr |= ((uint32_t)(norm >> 36) & 1) << 20;
|
||||
addr <<= 4;
|
||||
addr -= s->pos + (uint32_t)i;
|
||||
addr >>= 4;
|
||||
|
||||
norm &= ~((uint64_t)0x8FFFFF << 13);
|
||||
norm |= (uint64_t)(addr & 0x0FFFFF) << 13;
|
||||
norm |= (uint64_t)(addr & 0x100000)
|
||||
<< (36 - 20);
|
||||
|
||||
instr &= (1 << bit_res) - 1;
|
||||
instr |= norm << bit_res;
|
||||
|
||||
for (j = 0; j < 6; j++)
|
||||
buf[i + j + byte_pos]
|
||||
= (uint8_t)(instr >> (8 * j));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef XZ_DEC_ARM
|
||||
static size_t bcj_arm(struct xz_dec_bcj *s, uint8_t *buf, size_t size)
|
||||
{
|
||||
size_t i;
|
||||
uint32_t addr;
|
||||
|
||||
for (i = 0; i + 4 <= size; i += 4) {
|
||||
if (buf[i + 3] == 0xEB) {
|
||||
addr = (uint32_t)buf[i] | ((uint32_t)buf[i + 1] << 8)
|
||||
| ((uint32_t)buf[i + 2] << 16);
|
||||
addr <<= 2;
|
||||
addr -= s->pos + (uint32_t)i + 8;
|
||||
addr >>= 2;
|
||||
buf[i] = (uint8_t)addr;
|
||||
buf[i + 1] = (uint8_t)(addr >> 8);
|
||||
buf[i + 2] = (uint8_t)(addr >> 16);
|
||||
}
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef XZ_DEC_ARMTHUMB
|
||||
static size_t bcj_armthumb(struct xz_dec_bcj *s, uint8_t *buf, size_t size)
|
||||
{
|
||||
size_t i;
|
||||
uint32_t addr;
|
||||
|
||||
for (i = 0; i + 4 <= size; i += 2) {
|
||||
if ((buf[i + 1] & 0xF8) == 0xF0
|
||||
&& (buf[i + 3] & 0xF8) == 0xF8) {
|
||||
addr = (((uint32_t)buf[i + 1] & 0x07) << 19)
|
||||
| ((uint32_t)buf[i] << 11)
|
||||
| (((uint32_t)buf[i + 3] & 0x07) << 8)
|
||||
| (uint32_t)buf[i + 2];
|
||||
addr <<= 1;
|
||||
addr -= s->pos + (uint32_t)i + 4;
|
||||
addr >>= 1;
|
||||
buf[i + 1] = (uint8_t)(0xF0 | ((addr >> 19) & 0x07));
|
||||
buf[i] = (uint8_t)(addr >> 11);
|
||||
buf[i + 3] = (uint8_t)(0xF8 | ((addr >> 8) & 0x07));
|
||||
buf[i + 2] = (uint8_t)addr;
|
||||
i += 2;
|
||||
}
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef XZ_DEC_SPARC
|
||||
static size_t bcj_sparc(struct xz_dec_bcj *s, uint8_t *buf, size_t size)
|
||||
{
|
||||
size_t i;
|
||||
uint32_t instr;
|
||||
|
||||
for (i = 0; i + 4 <= size; i += 4) {
|
||||
instr = get_unaligned_be32(buf + i);
|
||||
if ((instr >> 22) == 0x100 || (instr >> 22) == 0x1FF) {
|
||||
instr <<= 2;
|
||||
instr -= s->pos + (uint32_t)i;
|
||||
instr >>= 2;
|
||||
instr = ((uint32_t)0x40000000 - (instr & 0x400000))
|
||||
| 0x40000000 | (instr & 0x3FFFFF);
|
||||
put_unaligned_be32(instr, buf + i);
|
||||
}
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Apply the selected BCJ filter. Update *pos and s->pos to match the amount
|
||||
* of data that got filtered.
|
||||
*
|
||||
* NOTE: This is implemented as a switch statement to avoid using function
|
||||
* pointers, which could be problematic in the kernel boot code, which must
|
||||
* avoid pointers to static data (at least on x86).
|
||||
*/
|
||||
static void bcj_apply(struct xz_dec_bcj *s,
|
||||
uint8_t *buf, size_t *pos, size_t size)
|
||||
{
|
||||
size_t filtered;
|
||||
|
||||
buf += *pos;
|
||||
size -= *pos;
|
||||
|
||||
switch (s->type) {
|
||||
#ifdef XZ_DEC_X86
|
||||
case BCJ_X86:
|
||||
filtered = bcj_x86(s, buf, size);
|
||||
break;
|
||||
#endif
|
||||
#ifdef XZ_DEC_POWERPC
|
||||
case BCJ_POWERPC:
|
||||
filtered = bcj_powerpc(s, buf, size);
|
||||
break;
|
||||
#endif
|
||||
#ifdef XZ_DEC_IA64
|
||||
case BCJ_IA64:
|
||||
filtered = bcj_ia64(s, buf, size);
|
||||
break;
|
||||
#endif
|
||||
#ifdef XZ_DEC_ARM
|
||||
case BCJ_ARM:
|
||||
filtered = bcj_arm(s, buf, size);
|
||||
break;
|
||||
#endif
|
||||
#ifdef XZ_DEC_ARMTHUMB
|
||||
case BCJ_ARMTHUMB:
|
||||
filtered = bcj_armthumb(s, buf, size);
|
||||
break;
|
||||
#endif
|
||||
#ifdef XZ_DEC_SPARC
|
||||
case BCJ_SPARC:
|
||||
filtered = bcj_sparc(s, buf, size);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
/* Never reached but silence compiler warnings. */
|
||||
filtered = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
*pos += filtered;
|
||||
s->pos += filtered;
|
||||
}
|
||||
|
||||
/*
|
||||
* Flush pending filtered data from temp to the output buffer.
|
||||
* Move the remaining mixture of possibly filtered and unfiltered
|
||||
* data to the beginning of temp.
|
||||
*/
|
||||
static void bcj_flush(struct xz_dec_bcj *s, struct xz_buf *b)
|
||||
{
|
||||
size_t copy_size;
|
||||
|
||||
copy_size = min_t(size_t, s->temp.filtered, b->out_size - b->out_pos);
|
||||
memcpy(b->out + b->out_pos, s->temp.buf, copy_size);
|
||||
b->out_pos += copy_size;
|
||||
|
||||
s->temp.filtered -= copy_size;
|
||||
s->temp.size -= copy_size;
|
||||
memmove(s->temp.buf, s->temp.buf + copy_size, s->temp.size);
|
||||
}
|
||||
|
||||
/*
|
||||
* The BCJ filter functions are primitive in sense that they process the
|
||||
* data in chunks of 1-16 bytes. To hide this issue, this function does
|
||||
* some buffering.
|
||||
*/
|
||||
XZ_EXTERN enum xz_ret xz_dec_bcj_run(struct xz_dec_bcj *s,
|
||||
struct xz_dec_lzma2 *lzma2,
|
||||
struct xz_buf *b)
|
||||
{
|
||||
size_t out_start;
|
||||
|
||||
/*
|
||||
* Flush pending already filtered data to the output buffer. Return
|
||||
* immediatelly if we couldn't flush everything, or if the next
|
||||
* filter in the chain had already returned XZ_STREAM_END.
|
||||
*/
|
||||
if (s->temp.filtered > 0) {
|
||||
bcj_flush(s, b);
|
||||
if (s->temp.filtered > 0)
|
||||
return XZ_OK;
|
||||
|
||||
if (s->ret == XZ_STREAM_END)
|
||||
return XZ_STREAM_END;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we have more output space than what is currently pending in
|
||||
* temp, copy the unfiltered data from temp to the output buffer
|
||||
* and try to fill the output buffer by decoding more data from the
|
||||
* next filter in the chain. Apply the BCJ filter on the new data
|
||||
* in the output buffer. If everything cannot be filtered, copy it
|
||||
* to temp and rewind the output buffer position accordingly.
|
||||
*
|
||||
* This needs to be always run when temp.size == 0 to handle a special
|
||||
* case where the output buffer is full and the next filter has no
|
||||
* more output coming but hasn't returned XZ_STREAM_END yet.
|
||||
*/
|
||||
if (s->temp.size < b->out_size - b->out_pos || s->temp.size == 0) {
|
||||
out_start = b->out_pos;
|
||||
memcpy(b->out + b->out_pos, s->temp.buf, s->temp.size);
|
||||
b->out_pos += s->temp.size;
|
||||
|
||||
s->ret = xz_dec_lzma2_run(lzma2, b);
|
||||
if (s->ret != XZ_STREAM_END
|
||||
&& (s->ret != XZ_OK || s->single_call))
|
||||
return s->ret;
|
||||
|
||||
bcj_apply(s, b->out, &out_start, b->out_pos);
|
||||
|
||||
/*
|
||||
* As an exception, if the next filter returned XZ_STREAM_END,
|
||||
* we can do that too, since the last few bytes that remain
|
||||
* unfiltered are meant to remain unfiltered.
|
||||
*/
|
||||
if (s->ret == XZ_STREAM_END)
|
||||
return XZ_STREAM_END;
|
||||
|
||||
s->temp.size = b->out_pos - out_start;
|
||||
b->out_pos -= s->temp.size;
|
||||
memcpy(s->temp.buf, b->out + b->out_pos, s->temp.size);
|
||||
|
||||
/*
|
||||
* If there wasn't enough input to the next filter to fill
|
||||
* the output buffer with unfiltered data, there's no point
|
||||
* to try decoding more data to temp.
|
||||
*/
|
||||
if (b->out_pos + s->temp.size < b->out_size)
|
||||
return XZ_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* We have unfiltered data in temp. If the output buffer isn't full
|
||||
* yet, try to fill the temp buffer by decoding more data from the
|
||||
* next filter. Apply the BCJ filter on temp. Then we hopefully can
|
||||
* fill the actual output buffer by copying filtered data from temp.
|
||||
* A mix of filtered and unfiltered data may be left in temp; it will
|
||||
* be taken care on the next call to this function.
|
||||
*/
|
||||
if (b->out_pos < b->out_size) {
|
||||
/* Make b->out{,_pos,_size} temporarily point to s->temp. */
|
||||
s->out = b->out;
|
||||
s->out_pos = b->out_pos;
|
||||
s->out_size = b->out_size;
|
||||
b->out = s->temp.buf;
|
||||
b->out_pos = s->temp.size;
|
||||
b->out_size = sizeof(s->temp.buf);
|
||||
|
||||
s->ret = xz_dec_lzma2_run(lzma2, b);
|
||||
|
||||
s->temp.size = b->out_pos;
|
||||
b->out = s->out;
|
||||
b->out_pos = s->out_pos;
|
||||
b->out_size = s->out_size;
|
||||
|
||||
if (s->ret != XZ_OK && s->ret != XZ_STREAM_END)
|
||||
return s->ret;
|
||||
|
||||
bcj_apply(s, s->temp.buf, &s->temp.filtered, s->temp.size);
|
||||
|
||||
/*
|
||||
* If the next filter returned XZ_STREAM_END, we mark that
|
||||
* everything is filtered, since the last unfiltered bytes
|
||||
* of the stream are meant to be left as is.
|
||||
*/
|
||||
if (s->ret == XZ_STREAM_END)
|
||||
s->temp.filtered = s->temp.size;
|
||||
|
||||
bcj_flush(s, b);
|
||||
if (s->temp.filtered > 0)
|
||||
return XZ_OK;
|
||||
}
|
||||
|
||||
return s->ret;
|
||||
}
|
||||
|
||||
XZ_EXTERN struct xz_dec_bcj *xz_dec_bcj_create(bool single_call)
|
||||
{
|
||||
struct xz_dec_bcj *s = kmalloc(sizeof(*s), GFP_KERNEL);
|
||||
if (s != NULL)
|
||||
s->single_call = single_call;
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
XZ_EXTERN enum xz_ret xz_dec_bcj_reset(struct xz_dec_bcj *s, uint8_t id)
|
||||
{
|
||||
switch (id) {
|
||||
#ifdef XZ_DEC_X86
|
||||
case BCJ_X86:
|
||||
#endif
|
||||
#ifdef XZ_DEC_POWERPC
|
||||
case BCJ_POWERPC:
|
||||
#endif
|
||||
#ifdef XZ_DEC_IA64
|
||||
case BCJ_IA64:
|
||||
#endif
|
||||
#ifdef XZ_DEC_ARM
|
||||
case BCJ_ARM:
|
||||
#endif
|
||||
#ifdef XZ_DEC_ARMTHUMB
|
||||
case BCJ_ARMTHUMB:
|
||||
#endif
|
||||
#ifdef XZ_DEC_SPARC
|
||||
case BCJ_SPARC:
|
||||
#endif
|
||||
break;
|
||||
|
||||
default:
|
||||
/* Unsupported Filter ID */
|
||||
return XZ_OPTIONS_ERROR;
|
||||
}
|
||||
|
||||
s->type = id;
|
||||
s->ret = XZ_OK;
|
||||
s->pos = 0;
|
||||
s->x86_prev_mask = 0;
|
||||
s->temp.filtered = 0;
|
||||
s->temp.size = 0;
|
||||
|
||||
return XZ_OK;
|
||||
}
|
||||
|
||||
#endif
|
||||
1171
LinuxGUI/Ventoy2Disk/Lib/xz-embedded/linux/lib/xz/xz_dec_lzma2.c
Normal file
1171
LinuxGUI/Ventoy2Disk/Lib/xz-embedded/linux/lib/xz/xz_dec_lzma2.c
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,847 @@
|
||||
/*
|
||||
* .xz Stream decoder
|
||||
*
|
||||
* Author: Lasse Collin <lasse.collin@tukaani.org>
|
||||
*
|
||||
* This file has been put into the public domain.
|
||||
* You can do whatever you want with this file.
|
||||
*/
|
||||
|
||||
#include "xz_private.h"
|
||||
#include "xz_stream.h"
|
||||
|
||||
#ifdef XZ_USE_CRC64
|
||||
# define IS_CRC64(check_type) ((check_type) == XZ_CHECK_CRC64)
|
||||
#else
|
||||
# define IS_CRC64(check_type) false
|
||||
#endif
|
||||
|
||||
/* Hash used to validate the Index field */
|
||||
struct xz_dec_hash {
|
||||
vli_type unpadded;
|
||||
vli_type uncompressed;
|
||||
uint32_t crc32;
|
||||
};
|
||||
|
||||
struct xz_dec {
|
||||
/* Position in dec_main() */
|
||||
enum {
|
||||
SEQ_STREAM_HEADER,
|
||||
SEQ_BLOCK_START,
|
||||
SEQ_BLOCK_HEADER,
|
||||
SEQ_BLOCK_UNCOMPRESS,
|
||||
SEQ_BLOCK_PADDING,
|
||||
SEQ_BLOCK_CHECK,
|
||||
SEQ_INDEX,
|
||||
SEQ_INDEX_PADDING,
|
||||
SEQ_INDEX_CRC32,
|
||||
SEQ_STREAM_FOOTER
|
||||
} sequence;
|
||||
|
||||
/* Position in variable-length integers and Check fields */
|
||||
uint32_t pos;
|
||||
|
||||
/* Variable-length integer decoded by dec_vli() */
|
||||
vli_type vli;
|
||||
|
||||
/* Saved in_pos and out_pos */
|
||||
size_t in_start;
|
||||
size_t out_start;
|
||||
|
||||
#ifdef XZ_USE_CRC64
|
||||
/* CRC32 or CRC64 value in Block or CRC32 value in Index */
|
||||
uint64_t crc;
|
||||
#else
|
||||
/* CRC32 value in Block or Index */
|
||||
uint32_t crc;
|
||||
#endif
|
||||
|
||||
/* Type of the integrity check calculated from uncompressed data */
|
||||
enum xz_check check_type;
|
||||
|
||||
/* Operation mode */
|
||||
enum xz_mode mode;
|
||||
|
||||
/*
|
||||
* True if the next call to xz_dec_run() is allowed to return
|
||||
* XZ_BUF_ERROR.
|
||||
*/
|
||||
bool allow_buf_error;
|
||||
|
||||
/* Information stored in Block Header */
|
||||
struct {
|
||||
/*
|
||||
* Value stored in the Compressed Size field, or
|
||||
* VLI_UNKNOWN if Compressed Size is not present.
|
||||
*/
|
||||
vli_type compressed;
|
||||
|
||||
/*
|
||||
* Value stored in the Uncompressed Size field, or
|
||||
* VLI_UNKNOWN if Uncompressed Size is not present.
|
||||
*/
|
||||
vli_type uncompressed;
|
||||
|
||||
/* Size of the Block Header field */
|
||||
uint32_t size;
|
||||
} block_header;
|
||||
|
||||
/* Information collected when decoding Blocks */
|
||||
struct {
|
||||
/* Observed compressed size of the current Block */
|
||||
vli_type compressed;
|
||||
|
||||
/* Observed uncompressed size of the current Block */
|
||||
vli_type uncompressed;
|
||||
|
||||
/* Number of Blocks decoded so far */
|
||||
vli_type count;
|
||||
|
||||
/*
|
||||
* Hash calculated from the Block sizes. This is used to
|
||||
* validate the Index field.
|
||||
*/
|
||||
struct xz_dec_hash hash;
|
||||
} block;
|
||||
|
||||
/* Variables needed when verifying the Index field */
|
||||
struct {
|
||||
/* Position in dec_index() */
|
||||
enum {
|
||||
SEQ_INDEX_COUNT,
|
||||
SEQ_INDEX_UNPADDED,
|
||||
SEQ_INDEX_UNCOMPRESSED
|
||||
} sequence;
|
||||
|
||||
/* Size of the Index in bytes */
|
||||
vli_type size;
|
||||
|
||||
/* Number of Records (matches block.count in valid files) */
|
||||
vli_type count;
|
||||
|
||||
/*
|
||||
* Hash calculated from the Records (matches block.hash in
|
||||
* valid files).
|
||||
*/
|
||||
struct xz_dec_hash hash;
|
||||
} index;
|
||||
|
||||
/*
|
||||
* Temporary buffer needed to hold Stream Header, Block Header,
|
||||
* and Stream Footer. The Block Header is the biggest (1 KiB)
|
||||
* so we reserve space according to that. buf[] has to be aligned
|
||||
* to a multiple of four bytes; the size_t variables before it
|
||||
* should guarantee this.
|
||||
*/
|
||||
struct {
|
||||
size_t pos;
|
||||
size_t size;
|
||||
uint8_t buf[1024];
|
||||
} temp;
|
||||
|
||||
struct xz_dec_lzma2 *lzma2;
|
||||
|
||||
#ifdef XZ_DEC_BCJ
|
||||
struct xz_dec_bcj *bcj;
|
||||
bool bcj_active;
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifdef XZ_DEC_ANY_CHECK
|
||||
/* Sizes of the Check field with different Check IDs */
|
||||
static const uint8_t check_sizes[16] = {
|
||||
0,
|
||||
4, 4, 4,
|
||||
8, 8, 8,
|
||||
16, 16, 16,
|
||||
32, 32, 32,
|
||||
64, 64, 64
|
||||
};
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Fill s->temp by copying data starting from b->in[b->in_pos]. Caller
|
||||
* must have set s->temp.pos to indicate how much data we are supposed
|
||||
* to copy into s->temp.buf. Return true once s->temp.pos has reached
|
||||
* s->temp.size.
|
||||
*/
|
||||
static bool fill_temp(struct xz_dec *s, struct xz_buf *b)
|
||||
{
|
||||
size_t copy_size = min_t(size_t,
|
||||
b->in_size - b->in_pos, s->temp.size - s->temp.pos);
|
||||
|
||||
memcpy(s->temp.buf + s->temp.pos, b->in + b->in_pos, copy_size);
|
||||
b->in_pos += copy_size;
|
||||
s->temp.pos += copy_size;
|
||||
|
||||
if (s->temp.pos == s->temp.size) {
|
||||
s->temp.pos = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Decode a variable-length integer (little-endian base-128 encoding) */
|
||||
static enum xz_ret dec_vli(struct xz_dec *s, const uint8_t *in,
|
||||
size_t *in_pos, size_t in_size)
|
||||
{
|
||||
uint8_t byte;
|
||||
|
||||
if (s->pos == 0)
|
||||
s->vli = 0;
|
||||
|
||||
while (*in_pos < in_size) {
|
||||
byte = in[*in_pos];
|
||||
++*in_pos;
|
||||
|
||||
s->vli |= (vli_type)(byte & 0x7F) << s->pos;
|
||||
|
||||
if ((byte & 0x80) == 0) {
|
||||
/* Don't allow non-minimal encodings. */
|
||||
if (byte == 0 && s->pos != 0)
|
||||
return XZ_DATA_ERROR;
|
||||
|
||||
s->pos = 0;
|
||||
return XZ_STREAM_END;
|
||||
}
|
||||
|
||||
s->pos += 7;
|
||||
if (s->pos == 7 * VLI_BYTES_MAX)
|
||||
return XZ_DATA_ERROR;
|
||||
}
|
||||
|
||||
return XZ_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Decode the Compressed Data field from a Block. Update and validate
|
||||
* the observed compressed and uncompressed sizes of the Block so that
|
||||
* they don't exceed the values possibly stored in the Block Header
|
||||
* (validation assumes that no integer overflow occurs, since vli_type
|
||||
* is normally uint64_t). Update the CRC32 or CRC64 value if presence of
|
||||
* the CRC32 or CRC64 field was indicated in Stream Header.
|
||||
*
|
||||
* Once the decoding is finished, validate that the observed sizes match
|
||||
* the sizes possibly stored in the Block Header. Update the hash and
|
||||
* Block count, which are later used to validate the Index field.
|
||||
*/
|
||||
static enum xz_ret dec_block(struct xz_dec *s, struct xz_buf *b)
|
||||
{
|
||||
enum xz_ret ret;
|
||||
|
||||
s->in_start = b->in_pos;
|
||||
s->out_start = b->out_pos;
|
||||
|
||||
#ifdef XZ_DEC_BCJ
|
||||
if (s->bcj_active)
|
||||
ret = xz_dec_bcj_run(s->bcj, s->lzma2, b);
|
||||
else
|
||||
#endif
|
||||
ret = xz_dec_lzma2_run(s->lzma2, b);
|
||||
|
||||
s->block.compressed += b->in_pos - s->in_start;
|
||||
s->block.uncompressed += b->out_pos - s->out_start;
|
||||
|
||||
/*
|
||||
* There is no need to separately check for VLI_UNKNOWN, since
|
||||
* the observed sizes are always smaller than VLI_UNKNOWN.
|
||||
*/
|
||||
if (s->block.compressed > s->block_header.compressed
|
||||
|| s->block.uncompressed
|
||||
> s->block_header.uncompressed)
|
||||
return XZ_DATA_ERROR;
|
||||
|
||||
if (s->check_type == XZ_CHECK_CRC32)
|
||||
s->crc = xz_crc32(b->out + s->out_start,
|
||||
b->out_pos - s->out_start, s->crc);
|
||||
#ifdef XZ_USE_CRC64
|
||||
else if (s->check_type == XZ_CHECK_CRC64)
|
||||
s->crc = xz_crc64(b->out + s->out_start,
|
||||
b->out_pos - s->out_start, s->crc);
|
||||
#endif
|
||||
|
||||
if (ret == XZ_STREAM_END) {
|
||||
if (s->block_header.compressed != VLI_UNKNOWN
|
||||
&& s->block_header.compressed
|
||||
!= s->block.compressed)
|
||||
return XZ_DATA_ERROR;
|
||||
|
||||
if (s->block_header.uncompressed != VLI_UNKNOWN
|
||||
&& s->block_header.uncompressed
|
||||
!= s->block.uncompressed)
|
||||
return XZ_DATA_ERROR;
|
||||
|
||||
s->block.hash.unpadded += s->block_header.size
|
||||
+ s->block.compressed;
|
||||
|
||||
#ifdef XZ_DEC_ANY_CHECK
|
||||
s->block.hash.unpadded += check_sizes[s->check_type];
|
||||
#else
|
||||
if (s->check_type == XZ_CHECK_CRC32)
|
||||
s->block.hash.unpadded += 4;
|
||||
else if (IS_CRC64(s->check_type))
|
||||
s->block.hash.unpadded += 8;
|
||||
#endif
|
||||
|
||||
s->block.hash.uncompressed += s->block.uncompressed;
|
||||
s->block.hash.crc32 = xz_crc32(
|
||||
(const uint8_t *)&s->block.hash,
|
||||
sizeof(s->block.hash), s->block.hash.crc32);
|
||||
|
||||
++s->block.count;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Update the Index size and the CRC32 value. */
|
||||
static void index_update(struct xz_dec *s, const struct xz_buf *b)
|
||||
{
|
||||
size_t in_used = b->in_pos - s->in_start;
|
||||
s->index.size += in_used;
|
||||
s->crc = xz_crc32(b->in + s->in_start, in_used, s->crc);
|
||||
}
|
||||
|
||||
/*
|
||||
* Decode the Number of Records, Unpadded Size, and Uncompressed Size
|
||||
* fields from the Index field. That is, Index Padding and CRC32 are not
|
||||
* decoded by this function.
|
||||
*
|
||||
* This can return XZ_OK (more input needed), XZ_STREAM_END (everything
|
||||
* successfully decoded), or XZ_DATA_ERROR (input is corrupt).
|
||||
*/
|
||||
static enum xz_ret dec_index(struct xz_dec *s, struct xz_buf *b)
|
||||
{
|
||||
enum xz_ret ret;
|
||||
|
||||
do {
|
||||
ret = dec_vli(s, b->in, &b->in_pos, b->in_size);
|
||||
if (ret != XZ_STREAM_END) {
|
||||
index_update(s, b);
|
||||
return ret;
|
||||
}
|
||||
|
||||
switch (s->index.sequence) {
|
||||
case SEQ_INDEX_COUNT:
|
||||
s->index.count = s->vli;
|
||||
|
||||
/*
|
||||
* Validate that the Number of Records field
|
||||
* indicates the same number of Records as
|
||||
* there were Blocks in the Stream.
|
||||
*/
|
||||
if (s->index.count != s->block.count)
|
||||
return XZ_DATA_ERROR;
|
||||
|
||||
s->index.sequence = SEQ_INDEX_UNPADDED;
|
||||
break;
|
||||
|
||||
case SEQ_INDEX_UNPADDED:
|
||||
s->index.hash.unpadded += s->vli;
|
||||
s->index.sequence = SEQ_INDEX_UNCOMPRESSED;
|
||||
break;
|
||||
|
||||
case SEQ_INDEX_UNCOMPRESSED:
|
||||
s->index.hash.uncompressed += s->vli;
|
||||
s->index.hash.crc32 = xz_crc32(
|
||||
(const uint8_t *)&s->index.hash,
|
||||
sizeof(s->index.hash),
|
||||
s->index.hash.crc32);
|
||||
--s->index.count;
|
||||
s->index.sequence = SEQ_INDEX_UNPADDED;
|
||||
break;
|
||||
}
|
||||
} while (s->index.count > 0);
|
||||
|
||||
return XZ_STREAM_END;
|
||||
}
|
||||
|
||||
/*
|
||||
* Validate that the next four or eight input bytes match the value
|
||||
* of s->crc. s->pos must be zero when starting to validate the first byte.
|
||||
* The "bits" argument allows using the same code for both CRC32 and CRC64.
|
||||
*/
|
||||
static enum xz_ret crc_validate(struct xz_dec *s, struct xz_buf *b,
|
||||
uint32_t bits)
|
||||
{
|
||||
do {
|
||||
if (b->in_pos == b->in_size)
|
||||
return XZ_OK;
|
||||
|
||||
if (((s->crc >> s->pos) & 0xFF) != b->in[b->in_pos++])
|
||||
return XZ_DATA_ERROR;
|
||||
|
||||
s->pos += 8;
|
||||
|
||||
} while (s->pos < bits);
|
||||
|
||||
s->crc = 0;
|
||||
s->pos = 0;
|
||||
|
||||
return XZ_STREAM_END;
|
||||
}
|
||||
|
||||
#ifdef XZ_DEC_ANY_CHECK
|
||||
/*
|
||||
* Skip over the Check field when the Check ID is not supported.
|
||||
* Returns true once the whole Check field has been skipped over.
|
||||
*/
|
||||
static bool check_skip(struct xz_dec *s, struct xz_buf *b)
|
||||
{
|
||||
while (s->pos < check_sizes[s->check_type]) {
|
||||
if (b->in_pos == b->in_size)
|
||||
return false;
|
||||
|
||||
++b->in_pos;
|
||||
++s->pos;
|
||||
}
|
||||
|
||||
s->pos = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Decode the Stream Header field (the first 12 bytes of the .xz Stream). */
|
||||
static enum xz_ret dec_stream_header(struct xz_dec *s)
|
||||
{
|
||||
if (!memeq(s->temp.buf, HEADER_MAGIC, HEADER_MAGIC_SIZE))
|
||||
return XZ_FORMAT_ERROR;
|
||||
|
||||
if (xz_crc32(s->temp.buf + HEADER_MAGIC_SIZE, 2, 0)
|
||||
!= get_le32(s->temp.buf + HEADER_MAGIC_SIZE + 2))
|
||||
return XZ_DATA_ERROR;
|
||||
|
||||
if (s->temp.buf[HEADER_MAGIC_SIZE] != 0)
|
||||
return XZ_OPTIONS_ERROR;
|
||||
|
||||
/*
|
||||
* Of integrity checks, we support none (Check ID = 0),
|
||||
* CRC32 (Check ID = 1), and optionally CRC64 (Check ID = 4).
|
||||
* However, if XZ_DEC_ANY_CHECK is defined, we will accept other
|
||||
* check types too, but then the check won't be verified and
|
||||
* a warning (XZ_UNSUPPORTED_CHECK) will be given.
|
||||
*/
|
||||
s->check_type = s->temp.buf[HEADER_MAGIC_SIZE + 1];
|
||||
|
||||
#ifdef XZ_DEC_ANY_CHECK
|
||||
if (s->check_type > XZ_CHECK_MAX)
|
||||
return XZ_OPTIONS_ERROR;
|
||||
|
||||
if (s->check_type > XZ_CHECK_CRC32 && !IS_CRC64(s->check_type))
|
||||
return XZ_UNSUPPORTED_CHECK;
|
||||
#else
|
||||
if (s->check_type > XZ_CHECK_CRC32 && !IS_CRC64(s->check_type))
|
||||
return XZ_OPTIONS_ERROR;
|
||||
#endif
|
||||
|
||||
return XZ_OK;
|
||||
}
|
||||
|
||||
/* Decode the Stream Footer field (the last 12 bytes of the .xz Stream) */
|
||||
static enum xz_ret dec_stream_footer(struct xz_dec *s)
|
||||
{
|
||||
if (!memeq(s->temp.buf + 10, FOOTER_MAGIC, FOOTER_MAGIC_SIZE))
|
||||
return XZ_DATA_ERROR;
|
||||
|
||||
if (xz_crc32(s->temp.buf + 4, 6, 0) != get_le32(s->temp.buf))
|
||||
return XZ_DATA_ERROR;
|
||||
|
||||
/*
|
||||
* Validate Backward Size. Note that we never added the size of the
|
||||
* Index CRC32 field to s->index.size, thus we use s->index.size / 4
|
||||
* instead of s->index.size / 4 - 1.
|
||||
*/
|
||||
if ((s->index.size >> 2) != get_le32(s->temp.buf + 4))
|
||||
return XZ_DATA_ERROR;
|
||||
|
||||
if (s->temp.buf[8] != 0 || s->temp.buf[9] != s->check_type)
|
||||
return XZ_DATA_ERROR;
|
||||
|
||||
/*
|
||||
* Use XZ_STREAM_END instead of XZ_OK to be more convenient
|
||||
* for the caller.
|
||||
*/
|
||||
return XZ_STREAM_END;
|
||||
}
|
||||
|
||||
/* Decode the Block Header and initialize the filter chain. */
|
||||
static enum xz_ret dec_block_header(struct xz_dec *s)
|
||||
{
|
||||
enum xz_ret ret;
|
||||
|
||||
/*
|
||||
* Validate the CRC32. We know that the temp buffer is at least
|
||||
* eight bytes so this is safe.
|
||||
*/
|
||||
s->temp.size -= 4;
|
||||
if (xz_crc32(s->temp.buf, s->temp.size, 0)
|
||||
!= get_le32(s->temp.buf + s->temp.size))
|
||||
return XZ_DATA_ERROR;
|
||||
|
||||
s->temp.pos = 2;
|
||||
|
||||
/*
|
||||
* Catch unsupported Block Flags. We support only one or two filters
|
||||
* in the chain, so we catch that with the same test.
|
||||
*/
|
||||
#ifdef XZ_DEC_BCJ
|
||||
if (s->temp.buf[1] & 0x3E)
|
||||
#else
|
||||
if (s->temp.buf[1] & 0x3F)
|
||||
#endif
|
||||
return XZ_OPTIONS_ERROR;
|
||||
|
||||
/* Compressed Size */
|
||||
if (s->temp.buf[1] & 0x40) {
|
||||
if (dec_vli(s, s->temp.buf, &s->temp.pos, s->temp.size)
|
||||
!= XZ_STREAM_END)
|
||||
return XZ_DATA_ERROR;
|
||||
|
||||
s->block_header.compressed = s->vli;
|
||||
} else {
|
||||
s->block_header.compressed = VLI_UNKNOWN;
|
||||
}
|
||||
|
||||
/* Uncompressed Size */
|
||||
if (s->temp.buf[1] & 0x80) {
|
||||
if (dec_vli(s, s->temp.buf, &s->temp.pos, s->temp.size)
|
||||
!= XZ_STREAM_END)
|
||||
return XZ_DATA_ERROR;
|
||||
|
||||
s->block_header.uncompressed = s->vli;
|
||||
} else {
|
||||
s->block_header.uncompressed = VLI_UNKNOWN;
|
||||
}
|
||||
|
||||
#ifdef XZ_DEC_BCJ
|
||||
/* If there are two filters, the first one must be a BCJ filter. */
|
||||
s->bcj_active = s->temp.buf[1] & 0x01;
|
||||
if (s->bcj_active) {
|
||||
if (s->temp.size - s->temp.pos < 2)
|
||||
return XZ_OPTIONS_ERROR;
|
||||
|
||||
ret = xz_dec_bcj_reset(s->bcj, s->temp.buf[s->temp.pos++]);
|
||||
if (ret != XZ_OK)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* We don't support custom start offset,
|
||||
* so Size of Properties must be zero.
|
||||
*/
|
||||
if (s->temp.buf[s->temp.pos++] != 0x00)
|
||||
return XZ_OPTIONS_ERROR;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Valid Filter Flags always take at least two bytes. */
|
||||
if (s->temp.size - s->temp.pos < 2)
|
||||
return XZ_DATA_ERROR;
|
||||
|
||||
/* Filter ID = LZMA2 */
|
||||
if (s->temp.buf[s->temp.pos++] != 0x21)
|
||||
return XZ_OPTIONS_ERROR;
|
||||
|
||||
/* Size of Properties = 1-byte Filter Properties */
|
||||
if (s->temp.buf[s->temp.pos++] != 0x01)
|
||||
return XZ_OPTIONS_ERROR;
|
||||
|
||||
/* Filter Properties contains LZMA2 dictionary size. */
|
||||
if (s->temp.size - s->temp.pos < 1)
|
||||
return XZ_DATA_ERROR;
|
||||
|
||||
ret = xz_dec_lzma2_reset(s->lzma2, s->temp.buf[s->temp.pos++]);
|
||||
if (ret != XZ_OK)
|
||||
return ret;
|
||||
|
||||
/* The rest must be Header Padding. */
|
||||
while (s->temp.pos < s->temp.size)
|
||||
if (s->temp.buf[s->temp.pos++] != 0x00)
|
||||
return XZ_OPTIONS_ERROR;
|
||||
|
||||
s->temp.pos = 0;
|
||||
s->block.compressed = 0;
|
||||
s->block.uncompressed = 0;
|
||||
|
||||
return XZ_OK;
|
||||
}
|
||||
|
||||
static enum xz_ret dec_main(struct xz_dec *s, struct xz_buf *b)
|
||||
{
|
||||
enum xz_ret ret;
|
||||
|
||||
/*
|
||||
* Store the start position for the case when we are in the middle
|
||||
* of the Index field.
|
||||
*/
|
||||
s->in_start = b->in_pos;
|
||||
|
||||
while (true) {
|
||||
switch (s->sequence) {
|
||||
case SEQ_STREAM_HEADER:
|
||||
/*
|
||||
* Stream Header is copied to s->temp, and then
|
||||
* decoded from there. This way if the caller
|
||||
* gives us only little input at a time, we can
|
||||
* still keep the Stream Header decoding code
|
||||
* simple. Similar approach is used in many places
|
||||
* in this file.
|
||||
*/
|
||||
if (!fill_temp(s, b))
|
||||
return XZ_OK;
|
||||
|
||||
/*
|
||||
* If dec_stream_header() returns
|
||||
* XZ_UNSUPPORTED_CHECK, it is still possible
|
||||
* to continue decoding if working in multi-call
|
||||
* mode. Thus, update s->sequence before calling
|
||||
* dec_stream_header().
|
||||
*/
|
||||
s->sequence = SEQ_BLOCK_START;
|
||||
|
||||
ret = dec_stream_header(s);
|
||||
if (ret != XZ_OK)
|
||||
return ret;
|
||||
|
||||
case SEQ_BLOCK_START:
|
||||
/* We need one byte of input to continue. */
|
||||
if (b->in_pos == b->in_size)
|
||||
return XZ_OK;
|
||||
|
||||
/* See if this is the beginning of the Index field. */
|
||||
if (b->in[b->in_pos] == 0) {
|
||||
s->in_start = b->in_pos++;
|
||||
s->sequence = SEQ_INDEX;
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculate the size of the Block Header and
|
||||
* prepare to decode it.
|
||||
*/
|
||||
s->block_header.size
|
||||
= ((uint32_t)b->in[b->in_pos] + 1) * 4;
|
||||
|
||||
s->temp.size = s->block_header.size;
|
||||
s->temp.pos = 0;
|
||||
s->sequence = SEQ_BLOCK_HEADER;
|
||||
|
||||
case SEQ_BLOCK_HEADER:
|
||||
if (!fill_temp(s, b))
|
||||
return XZ_OK;
|
||||
|
||||
ret = dec_block_header(s);
|
||||
if (ret != XZ_OK)
|
||||
return ret;
|
||||
|
||||
s->sequence = SEQ_BLOCK_UNCOMPRESS;
|
||||
|
||||
case SEQ_BLOCK_UNCOMPRESS:
|
||||
ret = dec_block(s, b);
|
||||
if (ret != XZ_STREAM_END)
|
||||
return ret;
|
||||
|
||||
s->sequence = SEQ_BLOCK_PADDING;
|
||||
|
||||
case SEQ_BLOCK_PADDING:
|
||||
/*
|
||||
* Size of Compressed Data + Block Padding
|
||||
* must be a multiple of four. We don't need
|
||||
* s->block.compressed for anything else
|
||||
* anymore, so we use it here to test the size
|
||||
* of the Block Padding field.
|
||||
*/
|
||||
while (s->block.compressed & 3) {
|
||||
if (b->in_pos == b->in_size)
|
||||
return XZ_OK;
|
||||
|
||||
if (b->in[b->in_pos++] != 0)
|
||||
return XZ_DATA_ERROR;
|
||||
|
||||
++s->block.compressed;
|
||||
}
|
||||
|
||||
s->sequence = SEQ_BLOCK_CHECK;
|
||||
|
||||
case SEQ_BLOCK_CHECK:
|
||||
if (s->check_type == XZ_CHECK_CRC32) {
|
||||
ret = crc_validate(s, b, 32);
|
||||
if (ret != XZ_STREAM_END)
|
||||
return ret;
|
||||
}
|
||||
else if (IS_CRC64(s->check_type)) {
|
||||
ret = crc_validate(s, b, 64);
|
||||
if (ret != XZ_STREAM_END)
|
||||
return ret;
|
||||
}
|
||||
#ifdef XZ_DEC_ANY_CHECK
|
||||
else if (!check_skip(s, b)) {
|
||||
return XZ_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
s->sequence = SEQ_BLOCK_START;
|
||||
break;
|
||||
|
||||
case SEQ_INDEX:
|
||||
ret = dec_index(s, b);
|
||||
if (ret != XZ_STREAM_END)
|
||||
return ret;
|
||||
|
||||
s->sequence = SEQ_INDEX_PADDING;
|
||||
|
||||
case SEQ_INDEX_PADDING:
|
||||
while ((s->index.size + (b->in_pos - s->in_start))
|
||||
& 3) {
|
||||
if (b->in_pos == b->in_size) {
|
||||
index_update(s, b);
|
||||
return XZ_OK;
|
||||
}
|
||||
|
||||
if (b->in[b->in_pos++] != 0)
|
||||
return XZ_DATA_ERROR;
|
||||
}
|
||||
|
||||
/* Finish the CRC32 value and Index size. */
|
||||
index_update(s, b);
|
||||
|
||||
/* Compare the hashes to validate the Index field. */
|
||||
if (!memeq(&s->block.hash, &s->index.hash,
|
||||
sizeof(s->block.hash)))
|
||||
return XZ_DATA_ERROR;
|
||||
|
||||
s->sequence = SEQ_INDEX_CRC32;
|
||||
|
||||
case SEQ_INDEX_CRC32:
|
||||
ret = crc_validate(s, b, 32);
|
||||
if (ret != XZ_STREAM_END)
|
||||
return ret;
|
||||
|
||||
s->temp.size = STREAM_HEADER_SIZE;
|
||||
s->sequence = SEQ_STREAM_FOOTER;
|
||||
|
||||
case SEQ_STREAM_FOOTER:
|
||||
if (!fill_temp(s, b))
|
||||
return XZ_OK;
|
||||
|
||||
return dec_stream_footer(s);
|
||||
}
|
||||
}
|
||||
|
||||
/* Never reached */
|
||||
}
|
||||
|
||||
/*
|
||||
* xz_dec_run() is a wrapper for dec_main() to handle some special cases in
|
||||
* multi-call and single-call decoding.
|
||||
*
|
||||
* In multi-call mode, we must return XZ_BUF_ERROR when it seems clear that we
|
||||
* are not going to make any progress anymore. This is to prevent the caller
|
||||
* from calling us infinitely when the input file is truncated or otherwise
|
||||
* corrupt. Since zlib-style API allows that the caller fills the input buffer
|
||||
* only when the decoder doesn't produce any new output, we have to be careful
|
||||
* to avoid returning XZ_BUF_ERROR too easily: XZ_BUF_ERROR is returned only
|
||||
* after the second consecutive call to xz_dec_run() that makes no progress.
|
||||
*
|
||||
* In single-call mode, if we couldn't decode everything and no error
|
||||
* occurred, either the input is truncated or the output buffer is too small.
|
||||
* Since we know that the last input byte never produces any output, we know
|
||||
* that if all the input was consumed and decoding wasn't finished, the file
|
||||
* must be corrupt. Otherwise the output buffer has to be too small or the
|
||||
* file is corrupt in a way that decoding it produces too big output.
|
||||
*
|
||||
* If single-call decoding fails, we reset b->in_pos and b->out_pos back to
|
||||
* their original values. This is because with some filter chains there won't
|
||||
* be any valid uncompressed data in the output buffer unless the decoding
|
||||
* actually succeeds (that's the price to pay of using the output buffer as
|
||||
* the workspace).
|
||||
*/
|
||||
XZ_EXTERN enum xz_ret xz_dec_run(struct xz_dec *s, struct xz_buf *b)
|
||||
{
|
||||
size_t in_start;
|
||||
size_t out_start;
|
||||
enum xz_ret ret;
|
||||
|
||||
if (DEC_IS_SINGLE(s->mode))
|
||||
xz_dec_reset(s);
|
||||
|
||||
in_start = b->in_pos;
|
||||
out_start = b->out_pos;
|
||||
ret = dec_main(s, b);
|
||||
|
||||
if (DEC_IS_SINGLE(s->mode)) {
|
||||
if (ret == XZ_OK)
|
||||
ret = b->in_pos == b->in_size
|
||||
? XZ_DATA_ERROR : XZ_BUF_ERROR;
|
||||
|
||||
if (ret != XZ_STREAM_END) {
|
||||
b->in_pos = in_start;
|
||||
b->out_pos = out_start;
|
||||
}
|
||||
|
||||
} else if (ret == XZ_OK && in_start == b->in_pos
|
||||
&& out_start == b->out_pos) {
|
||||
if (s->allow_buf_error)
|
||||
ret = XZ_BUF_ERROR;
|
||||
|
||||
s->allow_buf_error = true;
|
||||
} else {
|
||||
s->allow_buf_error = false;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
XZ_EXTERN struct xz_dec *xz_dec_init(enum xz_mode mode, uint32_t dict_max)
|
||||
{
|
||||
struct xz_dec *s = kmalloc(sizeof(*s), GFP_KERNEL);
|
||||
if (s == NULL)
|
||||
return NULL;
|
||||
|
||||
s->mode = mode;
|
||||
|
||||
#ifdef XZ_DEC_BCJ
|
||||
s->bcj = xz_dec_bcj_create(DEC_IS_SINGLE(mode));
|
||||
if (s->bcj == NULL)
|
||||
goto error_bcj;
|
||||
#endif
|
||||
|
||||
s->lzma2 = xz_dec_lzma2_create(mode, dict_max);
|
||||
if (s->lzma2 == NULL)
|
||||
goto error_lzma2;
|
||||
|
||||
xz_dec_reset(s);
|
||||
return s;
|
||||
|
||||
error_lzma2:
|
||||
#ifdef XZ_DEC_BCJ
|
||||
xz_dec_bcj_end(s->bcj);
|
||||
error_bcj:
|
||||
#endif
|
||||
kfree(s);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
XZ_EXTERN void xz_dec_reset(struct xz_dec *s)
|
||||
{
|
||||
s->sequence = SEQ_STREAM_HEADER;
|
||||
s->allow_buf_error = false;
|
||||
s->pos = 0;
|
||||
s->crc = 0;
|
||||
memzero(&s->block, sizeof(s->block));
|
||||
memzero(&s->index, sizeof(s->index));
|
||||
s->temp.pos = 0;
|
||||
s->temp.size = STREAM_HEADER_SIZE;
|
||||
}
|
||||
|
||||
XZ_EXTERN void xz_dec_end(struct xz_dec *s)
|
||||
{
|
||||
if (s != NULL) {
|
||||
xz_dec_lzma2_end(s->lzma2);
|
||||
#ifdef XZ_DEC_BCJ
|
||||
xz_dec_bcj_end(s->bcj);
|
||||
#endif
|
||||
kfree(s);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* XZ decoder module information
|
||||
*
|
||||
* Author: Lasse Collin <lasse.collin@tukaani.org>
|
||||
*
|
||||
* This file has been put into the public domain.
|
||||
* You can do whatever you want with this file.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/xz.h>
|
||||
|
||||
EXPORT_SYMBOL(xz_dec_init);
|
||||
EXPORT_SYMBOL(xz_dec_reset);
|
||||
EXPORT_SYMBOL(xz_dec_run);
|
||||
EXPORT_SYMBOL(xz_dec_end);
|
||||
|
||||
MODULE_DESCRIPTION("XZ decompressor");
|
||||
MODULE_VERSION("1.0");
|
||||
MODULE_AUTHOR("Lasse Collin <lasse.collin@tukaani.org> and Igor Pavlov");
|
||||
|
||||
/*
|
||||
* This code is in the public domain, but in Linux it's simplest to just
|
||||
* say it's GPL and consider the authors as the copyright holders.
|
||||
*/
|
||||
MODULE_LICENSE("GPL");
|
||||
220
LinuxGUI/Ventoy2Disk/Lib/xz-embedded/linux/lib/xz/xz_dec_test.c
Normal file
220
LinuxGUI/Ventoy2Disk/Lib/xz-embedded/linux/lib/xz/xz_dec_test.c
Normal file
@@ -0,0 +1,220 @@
|
||||
/*
|
||||
* XZ decoder tester
|
||||
*
|
||||
* Author: Lasse Collin <lasse.collin@tukaani.org>
|
||||
*
|
||||
* This file has been put into the public domain.
|
||||
* You can do whatever you want with this file.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/crc32.h>
|
||||
#include <linux/xz.h>
|
||||
|
||||
/* Maximum supported dictionary size */
|
||||
#define DICT_MAX (1 << 20)
|
||||
|
||||
/* Device name to pass to register_chrdev(). */
|
||||
#define DEVICE_NAME "xz_dec_test"
|
||||
|
||||
/* Dynamically allocated device major number */
|
||||
static int device_major;
|
||||
|
||||
/*
|
||||
* We reuse the same decoder state, and thus can decode only one
|
||||
* file at a time.
|
||||
*/
|
||||
static bool device_is_open;
|
||||
|
||||
/* XZ decoder state */
|
||||
static struct xz_dec *state;
|
||||
|
||||
/*
|
||||
* Return value of xz_dec_run(). We need to avoid calling xz_dec_run() after
|
||||
* it has returned XZ_STREAM_END, so we make this static.
|
||||
*/
|
||||
static enum xz_ret ret;
|
||||
|
||||
/*
|
||||
* Input and output buffers. The input buffer is used as a temporary safe
|
||||
* place for the data coming from the userspace.
|
||||
*/
|
||||
static uint8_t buffer_in[1024];
|
||||
static uint8_t buffer_out[1024];
|
||||
|
||||
/*
|
||||
* Structure to pass the input and output buffers to the XZ decoder.
|
||||
* A few of the fields are never modified so we initialize them here.
|
||||
*/
|
||||
static struct xz_buf buffers = {
|
||||
.in = buffer_in,
|
||||
.out = buffer_out,
|
||||
.out_size = sizeof(buffer_out)
|
||||
};
|
||||
|
||||
/*
|
||||
* CRC32 of uncompressed data. This is used to give the user a simple way
|
||||
* to check that the decoder produces correct output.
|
||||
*/
|
||||
static uint32_t crc;
|
||||
|
||||
static int xz_dec_test_open(struct inode *i, struct file *f)
|
||||
{
|
||||
if (device_is_open)
|
||||
return -EBUSY;
|
||||
|
||||
device_is_open = true;
|
||||
|
||||
xz_dec_reset(state);
|
||||
ret = XZ_OK;
|
||||
crc = 0xFFFFFFFF;
|
||||
|
||||
buffers.in_pos = 0;
|
||||
buffers.in_size = 0;
|
||||
buffers.out_pos = 0;
|
||||
|
||||
printk(KERN_INFO DEVICE_NAME ": opened\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xz_dec_test_release(struct inode *i, struct file *f)
|
||||
{
|
||||
device_is_open = false;
|
||||
|
||||
if (ret == XZ_OK)
|
||||
printk(KERN_INFO DEVICE_NAME ": input was truncated\n");
|
||||
|
||||
printk(KERN_INFO DEVICE_NAME ": closed\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Decode the data given to us from the userspace. CRC32 of the uncompressed
|
||||
* data is calculated and is printed at the end of successful decoding. The
|
||||
* uncompressed data isn't stored anywhere for further use.
|
||||
*
|
||||
* The .xz file must have exactly one Stream and no Stream Padding. The data
|
||||
* after the first Stream is considered to be garbage.
|
||||
*/
|
||||
static ssize_t xz_dec_test_write(struct file *file, const char __user *buf,
|
||||
size_t size, loff_t *pos)
|
||||
{
|
||||
size_t remaining;
|
||||
|
||||
if (ret != XZ_OK) {
|
||||
if (size > 0)
|
||||
printk(KERN_INFO DEVICE_NAME ": %zu bytes of "
|
||||
"garbage at the end of the file\n",
|
||||
size);
|
||||
|
||||
return -ENOSPC;
|
||||
}
|
||||
|
||||
printk(KERN_INFO DEVICE_NAME ": decoding %zu bytes of input\n",
|
||||
size);
|
||||
|
||||
remaining = size;
|
||||
while ((remaining > 0 || buffers.out_pos == buffers.out_size)
|
||||
&& ret == XZ_OK) {
|
||||
if (buffers.in_pos == buffers.in_size) {
|
||||
buffers.in_pos = 0;
|
||||
buffers.in_size = min(remaining, sizeof(buffer_in));
|
||||
if (copy_from_user(buffer_in, buf, buffers.in_size))
|
||||
return -EFAULT;
|
||||
|
||||
buf += buffers.in_size;
|
||||
remaining -= buffers.in_size;
|
||||
}
|
||||
|
||||
buffers.out_pos = 0;
|
||||
ret = xz_dec_run(state, &buffers);
|
||||
crc = crc32(crc, buffer_out, buffers.out_pos);
|
||||
}
|
||||
|
||||
switch (ret) {
|
||||
case XZ_OK:
|
||||
printk(KERN_INFO DEVICE_NAME ": XZ_OK\n");
|
||||
return size;
|
||||
|
||||
case XZ_STREAM_END:
|
||||
printk(KERN_INFO DEVICE_NAME ": XZ_STREAM_END, "
|
||||
"CRC32 = 0x%08X\n", ~crc);
|
||||
return size - remaining - (buffers.in_size - buffers.in_pos);
|
||||
|
||||
case XZ_MEMLIMIT_ERROR:
|
||||
printk(KERN_INFO DEVICE_NAME ": XZ_MEMLIMIT_ERROR\n");
|
||||
break;
|
||||
|
||||
case XZ_FORMAT_ERROR:
|
||||
printk(KERN_INFO DEVICE_NAME ": XZ_FORMAT_ERROR\n");
|
||||
break;
|
||||
|
||||
case XZ_OPTIONS_ERROR:
|
||||
printk(KERN_INFO DEVICE_NAME ": XZ_OPTIONS_ERROR\n");
|
||||
break;
|
||||
|
||||
case XZ_DATA_ERROR:
|
||||
printk(KERN_INFO DEVICE_NAME ": XZ_DATA_ERROR\n");
|
||||
break;
|
||||
|
||||
case XZ_BUF_ERROR:
|
||||
printk(KERN_INFO DEVICE_NAME ": XZ_BUF_ERROR\n");
|
||||
break;
|
||||
|
||||
default:
|
||||
printk(KERN_INFO DEVICE_NAME ": Bug detected!\n");
|
||||
break;
|
||||
}
|
||||
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/* Allocate the XZ decoder state and register the character device. */
|
||||
static int __init xz_dec_test_init(void)
|
||||
{
|
||||
static const struct file_operations fileops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = &xz_dec_test_open,
|
||||
.release = &xz_dec_test_release,
|
||||
.write = &xz_dec_test_write
|
||||
};
|
||||
|
||||
state = xz_dec_init(XZ_PREALLOC, DICT_MAX);
|
||||
if (state == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
device_major = register_chrdev(0, DEVICE_NAME, &fileops);
|
||||
if (device_major < 0) {
|
||||
xz_dec_end(state);
|
||||
return device_major;
|
||||
}
|
||||
|
||||
printk(KERN_INFO DEVICE_NAME ": module loaded\n");
|
||||
printk(KERN_INFO DEVICE_NAME ": Create a device node with "
|
||||
"'mknod " DEVICE_NAME " c %d 0' and write .xz files "
|
||||
"to it.\n", device_major);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit xz_dec_test_exit(void)
|
||||
{
|
||||
unregister_chrdev(device_major, DEVICE_NAME);
|
||||
xz_dec_end(state);
|
||||
printk(KERN_INFO DEVICE_NAME ": module unloaded\n");
|
||||
}
|
||||
|
||||
module_init(xz_dec_test_init);
|
||||
module_exit(xz_dec_test_exit);
|
||||
|
||||
MODULE_DESCRIPTION("XZ decompressor tester");
|
||||
MODULE_VERSION("1.0");
|
||||
MODULE_AUTHOR("Lasse Collin <lasse.collin@tukaani.org>");
|
||||
|
||||
/*
|
||||
* This code is in the public domain, but in Linux it's simplest to just
|
||||
* say it's GPL and consider the authors as the copyright holders.
|
||||
*/
|
||||
MODULE_LICENSE("GPL");
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user