fs: fat: extend FAT write operations
Subsystems (2)
cover fs: fat: extend FAT write operations
This patch series is an attempt to address FAT write related issues in an effort of running UEFI SCT (Self-Certification Test) to verify UEFI support on u-boot.
SCT is a test platform as well as an extentisive collection of test cases for UEFI specification. It can run all the tests automatically and save test results to dedicated log files.
AFAIK, what's missing in the current fat file system to safely run SCT without errors (I don't mean test case failures) are:
* write a file located under sub-directories
* write a file with non-zero offset
* delete a file
* create a directory
Patch#1 to patch#6 are some sort of preparatory ones. Patch#7 implements write with sub-directories path. Patch#8 to patch#10 implement write with non-zero offset. Patch#11 to patch#15 are related to creating a directory. Patch#16 provides delete, but it doesn't actually delete a file but instead return 0 with purging a file content, which is good enough to run SCT for now.
Finally, patch#17 fixes a minor bug in fs-test.sh.
I applied this patch set on top of v2018.07 along with a couple of yet-to--be-upstreamed UEFI-related patches, and could successfully run unmodified SCT[1] on qemu-arm.
AKASHI Takahiro (17):
fs: fat: extend get_fs_info() for write use
fs: fat: handle "." and ".." of root dir correctly with
fat_itr_resolve()
fs: fat: make directory iterator global for write use
fs: fat: assure iterator's ->dent belongs to ->clust
fs: fat: check and normailze file name
fs: fat: write returns error code instead of -1
fs: fat: support write with sub-directory path
fs: fat: refactor write interface for a file offset
fs: fat: support write with non-zero offset
cmd: fat: add offset parameter to fatwrite
fs: add mkdir interface
fs: fat: remember the starting cluster number of directory
fs: fat: support mkdir
cmd: fat: add fatmkdir command
efi_loader: file: support creating a directory
efi_loader: implement a pseudo "file delete"
fs-test: fix false positive error at Test Case 12
cmd/fat.c | 22 +- fs/fat/fat.c | 98 ++-- fs/fat/fat_write.c | 1051 +++++++++++++++++++++++-------------- fs/fs.c | 46 ++ include/fat.h | 37 ++ include/fs.h | 10 + lib/efi_loader/efi_file.c | 24 +- test/fs/fs-test.sh | 2 +- 8 files changed, 825 insertions(+), 465 deletions(-)
Signature · 1 line
2.17.0
PATCH 1/17 fs: fat: extend get_fs_info() for write use
get_fs_info() was introduced in major re-work of read operation by Rob. We want to reuse this function in write operation by extending it with additional members in fsdata structure.
--- fs/fat/fat.c | 3 +++ include/fat.h | 2 ++ 2 files changed, 5 insertions(+)
fs/fat/fat.c +3 -0
@@ -556,6 +556,9 @@ static int get_fs_info(fsdata *mydata)return ret; } + mydata->bs_total_sect = bs.total_sect; + mydata->bs_fats = bs.fats; +if (mydata->fatsize ==32 ) { mydata->fatlength = bs.fat32_length; }else {
include/fat.h +2 -0
@@ -173,6 +173,8 @@ typedef struct {int fatbufnum;/* Used by get_fatent, init to -1 */ int rootdir_size;/* Size of root dir for non-FAT32 */ __u32 root_cluster;/* First cluster of root dir for FAT32 */ +__u32 bs_total_sect;/* Boot sector's number of sectors */ +__u8 bs_fats;/* Boot sector's number of FATs */ } fsdata;static inline u32 clust_to_sect (fsdata *fsdata,u32 clust)
Signature · 1 line
2.17.0
PATCH 1/17 fs: fat: extend get_fs_info() for write use
Quoted 29 lines · AKASHI Takahiro
get_fs_info()was introduced in major re-work of read operation by Rob. We want to reuse this function in write operation by extending it with additional members in fsdata structure.Signed-off-by AKASHI Takahiro <[email protected]>--- fs/fat/fat.c | 3 +++ include/fat.h | 2 ++ 2 files changed, 5 insertions(+)fs/fat/fat.c +3
-0@@ -556,6 +556,9 @@ static int get_fs_info(fsdata *mydata)return ret; } + mydata->bs_total_sect = bs.total_sect; + mydata->bs_fats = bs.fats; +if (mydata->fatsize ==32 ) { mydata->fatlength = bs.fat32_length; }else {include/fat.h +0
-0
include/fat.h typedef struct { · line 176
Quoted 4 lines
include/fat.h +1
-0@@ -173,6 +173,8 @@ typedef struct {int fatbufnum;/* Used by get_fatent, init to -1 */ int rootdir_size;/* Size of root dir for non-FAT32 */ __u32 root_cluster;/* First cluster of root dir for FAT32 */ +__u32 bs_total_sect;/* Boot sector's number of sectors */
How can one sector have multiple sectors? Please, reword the comment to something more obvious.
Best regards
Heinrich
Quoted 5 lines
include/fat.h +1
-0+__u8 bs_fats;/* Boot sector's number of FATs */ } fsdata;static inline u32 clust_to_sect (fsdata *fsdata,u32 clust)
PATCH 1/17 fs: fat: extend get_fs_info() for write use
Quoted 19 lines · Heinrich Schuchardt
Quoted 18 lines · AKASHI Takahiro
get_fs_info()was introduced in major re-work of read operation by Rob. We want to reuse this function in write operation by extending it with additional members in fsdata structure.Signed-off-by AKASHI Takahiro <[email protected]>--- fs/fat/fat.c | 3 +++ include/fat.h | 2 ++ 2 files changed, 5 insertions(+)fs/fat/fat.c +0
-0@@ -556,6 +556,9 @@ static int get_fs_info(fsdata *mydata)return ret; }
Quoted 1 line
fs/fat/fat.c static int get_fs_info(fsdata *mydata) · line 559
Quoted 1 line
fs/fat/fat.c +1
-0+ mydata->bs_total_sect = bs.total_sect;
Please, check here if sectors is non-zero and in this case use that value. Do not rely on total_sect = 0 in later coding to read sectors. Anyway there should be only one place in the coding where we determine the sector count.
The same logic is used in the Linux kernel:
fs/fat/inode.c:1766: total_sectors = bpb.fat_sectors;fs/fat/inode.c:1767: if (total_sectors == 0)fs/fat/inode.c:1768: total_sectors = bpb.fat_total_sect;
Quoted 6 lines
Quoted 6 lines
fs/fat/fat.c +2
-0+ mydata->bs_fats = bs.fats; +if (mydata->fatsize ==32 ) { mydata->fatlength = bs.fat32_length; }else {include/fat.h +0
-0
Quoted 8 lines
include/fat.h typedef struct { · line 176
Quoted 8 lines
index
09e1423685..0c88b59a4a100644include/fat.h +1
-0@@ -173,6 +173,8 @@ typedef struct {int fatbufnum;/* Used by get_fatent, init to -1 */ int rootdir_size;/* Size of root dir for non-FAT32 */ __u32 root_cluster;/* First cluster of root dir for FAT32 */ +__u32 bs_total_sect;/* Boot sector's number of sectors */
Please, use
__u32 total_sect; /* Number of sectors */
Quoted 9 lines
How can one sector have multiple sectors? Please, reword the comment to something more obvious.
Best regards
Heinrich
include/fat.h typedef struct { · line 177
Quoted 1 line
include/fat.h +1
-0+__u8 bs_fats;/* Boot sector's number of FATs */
and
__u8 fats; /* Number of FATs */
This is not information about the boot sector but about the partition.
Best regards
Heinich
Quoted 6 lines
Quoted 4 lines
include/fat.h +0
-0} fsdata;static inline u32 clust_to_sect (fsdata *fsdata,u32 clust)
PATCH 2/17 fs: fat: handle "." and ".." of root dir correctly with fat_itr_resolve()
In reply to AKASHI TakahiroFAT's root directory does not have "." nor ".."
So care must be taken when scanning root directory with fat_itr_resolve(). Without this patch, any file path starting with "." or ".." will not be resolved at all.
--- fs/fat/fat.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+)
fs/fat/fat.c +21 -0
@@ -927,6 +927,27 @@ static int fat_itr_resolve(fat_itr *itr, const char *path, unsigned type)while (next[0 ] && !ISDIRDELIM (next[0 ])) next++; +if (itr->is_root) { +/* root dir doesn't have "." nor ".." */ +if ((((next - path) ==1 ) && !strncmp (path,"." ,1 )) || + (((next - path) ==2 ) && !strncmp (path,".." ,2 ))) { +/* point back to itself */ + itr->clust = itr->fsdata->root_cluster; + itr->dent =NULL ; + itr->remaining =0 ; + itr->last_cluster =0 ; + +if (next[0 ] ==0 ) { +if (type &TYPE_DIR ) +return 0 ; +else +return -ENOENT ; + } + +return fat_itr_resolve (itr, next, type); + } + } +while (fat_itr_next (itr)) {int match =0 ;unsigned n =max (strlen (itr->name), (size_t )(next - path));
Signature · 1 line
2.17.0
PATCH 2/17 fs: fat: handle "." and ".." of root dir correctly with fat_itr_resolve()
Quoted 15 lines · AKASHI Takahiro
FAT's root directory does not have "." nor ".."
So care must be taken when scanning root directory withfat_itr_resolve(). Without this patch, any file path starting with "." or ".." will not be resolved at all.Signed-off-by AKASHI Takahiro <[email protected]>--- fs/fat/fat.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+)fs/fat/fat.c +0
-0
fs/fat/fat.c static int fat_itr_resolve(fat_itr *itr, const char *path, unsigned type) · line 931
Quoted 5 lines
fs/fat/fat.c +2
-0@@ -927,6 +927,27 @@ static int fat_itr_resolve(fat_itr *itr, const char *path, unsigned type)while (next[0 ] && !ISDIRDELIM (next[0 ])) next++; +if (itr->is_root) { +/* root dir doesn't have "." nor ".." */
I understand why root has no ../ but /./ should be valid.
On Linux 'ls /./' displays the root directory.
Best regards
Heinrich
Quoted 23 lines
fs/fat/fat.c +19
-0+if ((((next - path) ==1 ) && !strncmp (path,"." ,1 )) || + (((next - path) ==2 ) && !strncmp (path,".." ,2 ))) { +/* point back to itself */ + itr->clust = itr->fsdata->root_cluster; + itr->dent =NULL ; + itr->remaining =0 ; + itr->last_cluster =0 ; + +if (next[0 ] ==0 ) { +if (type &TYPE_DIR ) +return 0 ; +else +return -ENOENT ; + } + +return fat_itr_resolve (itr, next, type); + } + } +while (fat_itr_next (itr)) {int match =0 ;unsigned n =max (strlen (itr->name), (size_t )(next - path));
PATCH 2/17 fs: fat: handle "." and ".." of root dir correctly with fat_itr_resolve()
Quoted 19 lines · Heinrich Schuchardt
Quoted 18 lines · AKASHI Takahiro
FAT's root directory does not have "." nor ".."
So care must be taken when scanning root directory withfat_itr_resolve(). Without this patch, any file path starting with "." or ".." will not be resolved at all.Signed-off-by AKASHI Takahiro <[email protected]>--- fs/fat/fat.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+)fs/fat/fat.c +0
-0@@ -927,6 +927,27 @@ static int fat_itr_resolve(fat_itr *itr, const char *path, unsigned type)while (next[0 ] && !ISDIRDELIM (next[0 ])) next++;
Quoted 4 lines
fs/fat/fat.c static int fat_itr_resolve(fat_itr *itr, const char *path, unsigned type) · line 931
Quoted 2 lines
fs/fat/fat.c +2
-0+if (itr->is_root) { +/* root dir doesn't have "." nor ".." */ I understand why root has no ../ but /./ should be valid.
What I meant here is that, according to FAT specification, the root directory has neither "." directory entry nor ".." in its associated clusters in contrast to ordinary directories.
So when user specifies "." or ".." (and other variants), we will have to take special care to handle them correctly.
Quoted 1 line
On Linux 'ls /./' displays the root directory.
My code works with any of the following paths:
* .
* ..
* /
* /.
* /.., or
* even any combination of above, like
./.././.././
Note that "ls /.." on linux also shows the root directory.
Please try.
-Takahiro AKASHI
Quoted 28 lines
Best regards
Heinrich
Quoted 23 lines
fs/fat/fat.c +19
-0+if ((((next - path) ==1 ) && !strncmp (path,"." ,1 )) || + (((next - path) ==2 ) && !strncmp (path,".." ,2 ))) { +/* point back to itself */ + itr->clust = itr->fsdata->root_cluster; + itr->dent =NULL ; + itr->remaining =0 ; + itr->last_cluster =0 ; + +if (next[0 ] ==0 ) { +if (type &TYPE_DIR ) +return 0 ; +else +return -ENOENT ; + } + +return fat_itr_resolve (itr, next, type); + } + } +while (fat_itr_next (itr)) {int match =0 ;unsigned n =max (strlen (itr->name), (size_t )(next - path));
PATCH 3/17 fs: fat: make directory iterator global for write use
In reply to AKASHI TakahiroDirectory iterator was introduced in major re-work of read operation by Rob. We want to use it for write operation extensively as well. This patch makes relevant functions, as well as iterator defition, visible outside of fat.c.
--- fs/fat/fat.c | 39 ++++++--------------------------------- include/fat.h | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 33 deletions(-)
fs/fat/fat.c +6 -33
@@ -634,25 +634,6 @@ static int get_fs_info(fsdata *mydata)* For more complete example, see fat_itr_resolve() */ -typedef struct { -fsdata *fsdata;/* filesystem parameters */ -unsigned clust;/* current cluster */ -int last_cluster;/* set once we've read last cluster */ -int is_root;/* is iterator at root directory */ -int remaining;/* remaining dent's in current cluster */ - -/* current iterator position values: */ -dir_entry *dent;/* current directory entry */ -char l_name[VFAT_MAXLEN_BYTES ];/* long (vfat) name */ -char s_name[14 ];/* short 8.3 name */ -char *name;/* l_name if there is one, else s_name */ - -/* storage for current cluster in memory: */ -u8 block[MAX_CLUSTSIZE ]__aligned(ARCH_DMA_MINALIGN) ; -}fat_itr ; - -static int fat_itr_isdir (fat_itr *itr); -/** * fat_itr_root() - initialize an iterator to start at the root * directory
@@ -661,7 +642,7 @@ static int fat_itr_isdir(fat_itr *itr);* @fsdata: filesystem data for the partition * @return 0 on success, else -errno */ -static int fat_itr_root (fat_itr *itr,fsdata *fsdata) +int fat_itr_root (fat_itr *itr,fsdata *fsdata) {if (get_fs_info (fsdata))return -ENXIO ;
@@ -693,7 +674,7 @@ static int fat_itr_root(fat_itr *itr, fsdata *fsdata)* @parent: the iterator pointing at a directory entry in the * parent directory of the directory to iterate */ -static void fat_itr_child (fat_itr *itr,fat_itr *parent) +void fat_itr_child (fat_itr *itr,fat_itr *parent) {fsdata *mydata = parent->fsdata;/* for silly macros */ unsigned clustnum =START (parent->dent);
@@ -713,7 +694,7 @@ static void fat_itr_child(fat_itr *itr, fat_itr *parent) itr->last_cluster =0 ; } -static void *next_cluster (fat_itr *itr) +void *next_cluster (fat_itr *itr) {fsdata *mydata = itr->fsdata;/* for silly macros */ int ret;
@@ -834,7 +815,7 @@ static dir_entry *extract_vfat_name(fat_itr *itr)* @return boolean, 1 if success or 0 if no more entries in the * current directory */ -static int fat_itr_next (fat_itr *itr) +int fat_itr_next (fat_itr *itr) {dir_entry *dent;
@@ -879,19 +860,11 @@ static int fat_itr_next(fat_itr *itr)* @itr: the iterator * @return true if cursor is at a directory */ -static int fat_itr_isdir (fat_itr *itr) +int fat_itr_isdir (fat_itr *itr) {return !!(itr->dent->attr &ATTR_DIR ); } -/* -* Helpers: -*/ - -#define TYPE_FILE 0x1 -#define TYPE_DIR 0x2 -#define TYPE_ANY (TYPE_FILE | TYPE_DIR) -/** * fat_itr_resolve() - traverse directory structure to resolve the * requested path.
@@ -907,7 +880,7 @@ static int fat_itr_isdir(fat_itr *itr)* @type: bitmask of allowable file types * @return 0 on success or -errno */ -static int fat_itr_resolve (fat_itr *itr,const char *path,unsigned type) +int fat_itr_resolve (fat_itr *itr,const char *path,unsigned type) {const char *next;
include/fat.h +32 -0
@@ -187,6 +187,38 @@ static inline u32 sect_to_clust(fsdata *fsdata, int sect)return (sect - fsdata->data_begin) / fsdata->clust_size; } +/* +* Directory iterator +*/ + +#define TYPE_FILE 0x1 +#define TYPE_DIR 0x2 +#define TYPE_ANY (TYPE_FILE | TYPE_DIR) + +typedef struct { +fsdata *fsdata;/* filesystem parameters */ +unsigned clust;/* current cluster */ +int last_cluster;/* set once we've read last cluster */ +int is_root;/* is iterator at root directory */ +int remaining;/* remaining dent's in current cluster */ + +/* current iterator position values: */ +dir_entry *dent;/* current directory entry */ +char l_name[VFAT_MAXLEN_BYTES ];/* long (vfat) name */ +char s_name[14 ];/* short 8.3 name */ +char *name;/* l_name if there is one, else s_name */ + +/* storage for current cluster in memory: */ +u8 block[MAX_CLUSTSIZE ]__aligned(ARCH_DMA_MINALIGN) ; +}fat_itr ; + +int fat_itr_root (fat_itr *itr,fsdata *fsdata); +void fat_itr_child (fat_itr *itr,fat_itr *parent); +void *next_cluster (fat_itr *itr); +int fat_itr_next (fat_itr *itr); +int fat_itr_isdir (fat_itr *itr); +int fat_itr_resolve (fat_itr *itr,const char *path,unsigned type); +int file_fat_detectfs (void );int fat_exists (const char *filename);int fat_size (const char *filename,loff_t *size);
Signature · 1 line
2.17.0
PATCH 3/17 fs: fat: make directory iterator global for write use
Quoted 112 lines · AKASHI Takahiro
Directory iterator was introduced in major re-work of read operation by Rob. We want to use it for write operation extensively as well. This patch makes relevant functions, as well as iterator defition, visible outside of
fat.c.Signed-off-by AKASHI Takahiro <[email protected]>--- fs/fat/fat.c | 39 ++++++--------------------------------- include/fat.h | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 33 deletions(-)fs/fat/fat.c +6
-33@@ -634,25 +634,6 @@ static int get_fs_info(fsdata *mydata)* For more complete example, see fat_itr_resolve() */ -typedef struct { -fsdata *fsdata;/* filesystem parameters */ -unsigned clust;/* current cluster */ -int last_cluster;/* set once we've read last cluster */ -int is_root;/* is iterator at root directory */ -int remaining;/* remaining dent's in current cluster */ - -/* current iterator position values: */ -dir_entry *dent;/* current directory entry */ -char l_name[VFAT_MAXLEN_BYTES ];/* long (vfat) name */ -char s_name[14 ];/* short 8.3 name */ -char *name;/* l_name if there is one, else s_name */ - -/* storage for current cluster in memory: */ -u8 block[MAX_CLUSTSIZE ]__aligned(ARCH_DMA_MINALIGN) ; -}fat_itr ; - -static int fat_itr_isdir (fat_itr *itr); -/** * fat_itr_root() - initialize an iterator to start at the root * directory @@ -661,7 +642,7 @@ static int fat_itr_isdir(fat_itr *itr);* @fsdata: filesystem data for the partition * @return 0 on success, else -errno */ -static int fat_itr_root (fat_itr *itr,fsdata *fsdata) +int fat_itr_root (fat_itr *itr,fsdata *fsdata) {if (get_fs_info (fsdata))return -ENXIO ;@@ -693,7 +674,7 @@ static int fat_itr_root(fat_itr *itr, fsdata *fsdata)* @parent: the iterator pointing at a directory entry in the * parent directory of the directory to iterate */ -static void fat_itr_child (fat_itr *itr,fat_itr *parent) +void fat_itr_child (fat_itr *itr,fat_itr *parent) {fsdata *mydata = parent->fsdata;/* for silly macros */ unsigned clustnum =START (parent->dent);@@ -713,7 +694,7 @@ static void fat_itr_child(fat_itr *itr, fat_itr *parent) itr->last_cluster =0 ; } -static void *next_cluster (fat_itr *itr) +void *next_cluster (fat_itr *itr) {fsdata *mydata = itr->fsdata;/* for silly macros */ int ret;@@ -834,7 +815,7 @@ static dir_entry *extract_vfat_name(fat_itr *itr)* @return boolean, 1 if success or 0 if no more entries in the * current directory */ -static int fat_itr_next (fat_itr *itr) +int fat_itr_next (fat_itr *itr) {dir_entry *dent;@@ -879,19 +860,11 @@ static int fat_itr_next(fat_itr *itr)* @itr: the iterator * @return true if cursor is at a directory */ -static int fat_itr_isdir (fat_itr *itr) +int fat_itr_isdir (fat_itr *itr) {return !!(itr->dent->attr &ATTR_DIR ); } -/* -* Helpers: -*/ - -#define TYPE_FILE 0x1 -#define TYPE_DIR 0x2 -#define TYPE_ANY (TYPE_FILE | TYPE_DIR) -/** * fat_itr_resolve() - traverse directory structure to resolve the * requested path. @@ -907,7 +880,7 @@ static int fat_itr_isdir(fat_itr *itr)* @type: bitmask of allowable file types * @return 0 on success or -errno */ -static int fat_itr_resolve (fat_itr *itr,const char *path,unsigned type) +int fat_itr_resolve (fat_itr *itr,const char *path,unsigned type) {const char *next;include/fat.h +0
-0
include/fat.h static inline u32 sect_to_clust(fsdata *fsdata, int sect) · line 196
Quoted 10 lines
include/fat.h +7
-0@@ -187,6 +187,38 @@ static inline u32 sect_to_clust(fsdata *fsdata, int sect)return (sect - fsdata->data_begin) / fsdata->clust_size; } +/* +* Directory iterator +*/ + +#define TYPE_FILE 0x1 +#define TYPE_DIR 0x2 +#define TYPE_ANY (TYPE_FILE | TYPE_DIR)
Please, rename these to something more specific like FS_ITER_ANY.
TYPE_ANY already is defined in fs/reiserfs/reiserfs_private.h:
fs/reiserfs/reiserfs_private.h:160:#define TYPE_ANY 15
Best regards
Heinrich
Quoted 29 lines
include/fat.h +25
-0+ +typedef struct { +fsdata *fsdata;/* filesystem parameters */ +unsigned clust;/* current cluster */ +int last_cluster;/* set once we've read last cluster */ +int is_root;/* is iterator at root directory */ +int remaining;/* remaining dent's in current cluster */ + +/* current iterator position values: */ +dir_entry *dent;/* current directory entry */ +char l_name[VFAT_MAXLEN_BYTES ];/* long (vfat) name */ +char s_name[14 ];/* short 8.3 name */ +char *name;/* l_name if there is one, else s_name */ + +/* storage for current cluster in memory: */ +u8 block[MAX_CLUSTSIZE ]__aligned(ARCH_DMA_MINALIGN) ; +}fat_itr ; + +int fat_itr_root (fat_itr *itr,fsdata *fsdata); +void fat_itr_child (fat_itr *itr,fat_itr *parent); +void *next_cluster (fat_itr *itr); +int fat_itr_next (fat_itr *itr); +int fat_itr_isdir (fat_itr *itr); +int fat_itr_resolve (fat_itr *itr,const char *path,unsigned type); +int file_fat_detectfs (void );int fat_exists (const char *filename);int fat_size (const char *filename,loff_t *size);
PATCH 3/17 fs: fat: make directory iterator global for write use
Quoted 126 lines · Heinrich Schuchardt
Quoted 112 lines · AKASHI Takahiro
Directory iterator was introduced in major re-work of read operation by Rob. We want to use it for write operation extensively as well. This patch makes relevant functions, as well as iterator defition, visible outside of
fat.c.Signed-off-by AKASHI Takahiro <[email protected]>--- fs/fat/fat.c | 39 ++++++--------------------------------- include/fat.h | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 33 deletions(-)fs/fat/fat.c +6
-33@@ -634,25 +634,6 @@ static int get_fs_info(fsdata *mydata)* For more complete example, see fat_itr_resolve() */ -typedef struct { -fsdata *fsdata;/* filesystem parameters */ -unsigned clust;/* current cluster */ -int last_cluster;/* set once we've read last cluster */ -int is_root;/* is iterator at root directory */ -int remaining;/* remaining dent's in current cluster */ - -/* current iterator position values: */ -dir_entry *dent;/* current directory entry */ -char l_name[VFAT_MAXLEN_BYTES ];/* long (vfat) name */ -char s_name[14 ];/* short 8.3 name */ -char *name;/* l_name if there is one, else s_name */ - -/* storage for current cluster in memory: */ -u8 block[MAX_CLUSTSIZE ]__aligned(ARCH_DMA_MINALIGN) ; -}fat_itr ; - -static int fat_itr_isdir (fat_itr *itr); -/** * fat_itr_root() - initialize an iterator to start at the root * directory @@ -661,7 +642,7 @@ static int fat_itr_isdir(fat_itr *itr);* @fsdata: filesystem data for the partition * @return 0 on success, else -errno */ -static int fat_itr_root (fat_itr *itr,fsdata *fsdata) +int fat_itr_root (fat_itr *itr,fsdata *fsdata) {if (get_fs_info (fsdata))return -ENXIO ;@@ -693,7 +674,7 @@ static int fat_itr_root(fat_itr *itr, fsdata *fsdata)* @parent: the iterator pointing at a directory entry in the * parent directory of the directory to iterate */ -static void fat_itr_child (fat_itr *itr,fat_itr *parent) +void fat_itr_child (fat_itr *itr,fat_itr *parent) {fsdata *mydata = parent->fsdata;/* for silly macros */ unsigned clustnum =START (parent->dent);@@ -713,7 +694,7 @@ static void fat_itr_child(fat_itr *itr, fat_itr *parent) itr->last_cluster =0 ; } -static void *next_cluster (fat_itr *itr) +void *next_cluster (fat_itr *itr) {fsdata *mydata = itr->fsdata;/* for silly macros */ int ret;@@ -834,7 +815,7 @@ static dir_entry *extract_vfat_name(fat_itr *itr)* @return boolean, 1 if success or 0 if no more entries in the * current directory */ -static int fat_itr_next (fat_itr *itr) +int fat_itr_next (fat_itr *itr) {dir_entry *dent;@@ -879,19 +860,11 @@ static int fat_itr_next(fat_itr *itr)* @itr: the iterator * @return true if cursor is at a directory */ -static int fat_itr_isdir (fat_itr *itr) +int fat_itr_isdir (fat_itr *itr) {return !!(itr->dent->attr &ATTR_DIR ); } -/* -* Helpers: -*/ - -#define TYPE_FILE 0x1 -#define TYPE_DIR 0x2 -#define TYPE_ANY (TYPE_FILE | TYPE_DIR) -/** * fat_itr_resolve() - traverse directory structure to resolve the * requested path. @@ -907,7 +880,7 @@ static int fat_itr_isdir(fat_itr *itr)* @type: bitmask of allowable file types * @return 0 on success or -errno */ -static int fat_itr_resolve (fat_itr *itr,const char *path,unsigned type) +int fat_itr_resolve (fat_itr *itr,const char *path,unsigned type) {const char *next;include/fat.h +0
-0include/fat.h static inline u32 sect_to_clust(fsdata *fsdata, int sect) · line 196
Quoted 10 lines
include/fat.h +7
-0@@ -187,6 +187,38 @@ static inline u32 sect_to_clust(fsdata *fsdata, int sect)return (sect - fsdata->data_begin) / fsdata->clust_size; } +/* +* Directory iterator +*/ + +#define TYPE_FILE 0x1 +#define TYPE_DIR 0x2 +#define TYPE_ANY (TYPE_FILE | TYPE_DIR)Please, rename these to something more specific like
FS_ITER_ANY.
Quoted 3 lines
TYPE_ANYalready is defined infs/reiserfs/reiserfs_private.h:fs/reiserfs/reiserfs_private.h:160:#define
TYPE_ANY15
Good catch though the definition above comes directly from Rob's original patch.
Since there is only one occurrence of TYPE_ANY in fs/fat, I'd rather expand it without introducing another definition.
Thanks,
-Takahiro AKASHI
Quoted 34 lines
Best regards
Heinrich
Quoted 29 lines
include/fat.h +25
-0+ +typedef struct { +fsdata *fsdata;/* filesystem parameters */ +unsigned clust;/* current cluster */ +int last_cluster;/* set once we've read last cluster */ +int is_root;/* is iterator at root directory */ +int remaining;/* remaining dent's in current cluster */ + +/* current iterator position values: */ +dir_entry *dent;/* current directory entry */ +char l_name[VFAT_MAXLEN_BYTES ];/* long (vfat) name */ +char s_name[14 ];/* short 8.3 name */ +char *name;/* l_name if there is one, else s_name */ + +/* storage for current cluster in memory: */ +u8 block[MAX_CLUSTSIZE ]__aligned(ARCH_DMA_MINALIGN) ; +}fat_itr ; + +int fat_itr_root (fat_itr *itr,fsdata *fsdata); +void fat_itr_child (fat_itr *itr,fat_itr *parent); +void *next_cluster (fat_itr *itr); +int fat_itr_next (fat_itr *itr); +int fat_itr_isdir (fat_itr *itr); +int fat_itr_resolve (fat_itr *itr,const char *path,unsigned type); +int file_fat_detectfs (void );int fat_exists (const char *filename);int fat_size (const char *filename,loff_t *size);
PATCH 3/17 fs: fat: make directory iterator global for write use
Quoted 127 lines · AKASHI Takahiro
Quoted 126 lines · Heinrich Schuchardt
Quoted 112 lines · AKASHI Takahiro
Directory iterator was introduced in major re-work of read operation by Rob. We want to use it for write operation extensively as well. This patch makes relevant functions, as well as iterator defition, visible outside of
fat.c.Signed-off-by AKASHI Takahiro <[email protected]>--- fs/fat/fat.c | 39 ++++++--------------------------------- include/fat.h | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 33 deletions(-)fs/fat/fat.c +6
-33@@ -634,25 +634,6 @@ static int get_fs_info(fsdata *mydata)* For more complete example, see fat_itr_resolve() */ -typedef struct { -fsdata *fsdata;/* filesystem parameters */ -unsigned clust;/* current cluster */ -int last_cluster;/* set once we've read last cluster */ -int is_root;/* is iterator at root directory */ -int remaining;/* remaining dent's in current cluster */ - -/* current iterator position values: */ -dir_entry *dent;/* current directory entry */ -char l_name[VFAT_MAXLEN_BYTES ];/* long (vfat) name */ -char s_name[14 ];/* short 8.3 name */ -char *name;/* l_name if there is one, else s_name */ - -/* storage for current cluster in memory: */ -u8 block[MAX_CLUSTSIZE ]__aligned(ARCH_DMA_MINALIGN) ; -}fat_itr ; - -static int fat_itr_isdir (fat_itr *itr); -/** * fat_itr_root() - initialize an iterator to start at the root * directory @@ -661,7 +642,7 @@ static int fat_itr_isdir(fat_itr *itr);* @fsdata: filesystem data for the partition * @return 0 on success, else -errno */ -static int fat_itr_root (fat_itr *itr,fsdata *fsdata) +int fat_itr_root (fat_itr *itr,fsdata *fsdata) {if (get_fs_info (fsdata))return -ENXIO ;@@ -693,7 +674,7 @@ static int fat_itr_root(fat_itr *itr, fsdata *fsdata)* @parent: the iterator pointing at a directory entry in the * parent directory of the directory to iterate */ -static void fat_itr_child (fat_itr *itr,fat_itr *parent) +void fat_itr_child (fat_itr *itr,fat_itr *parent) {fsdata *mydata = parent->fsdata;/* for silly macros */ unsigned clustnum =START (parent->dent);@@ -713,7 +694,7 @@ static void fat_itr_child(fat_itr *itr, fat_itr *parent) itr->last_cluster =0 ; } -static void *next_cluster (fat_itr *itr) +void *next_cluster (fat_itr *itr) {fsdata *mydata = itr->fsdata;/* for silly macros */ int ret;@@ -834,7 +815,7 @@ static dir_entry *extract_vfat_name(fat_itr *itr)* @return boolean, 1 if success or 0 if no more entries in the * current directory */ -static int fat_itr_next (fat_itr *itr) +int fat_itr_next (fat_itr *itr) {dir_entry *dent;@@ -879,19 +860,11 @@ static int fat_itr_next(fat_itr *itr)* @itr: the iterator * @return true if cursor is at a directory */ -static int fat_itr_isdir (fat_itr *itr) +int fat_itr_isdir (fat_itr *itr) {return !!(itr->dent->attr &ATTR_DIR ); } -/* -* Helpers: -*/ - -#define TYPE_FILE 0x1 -#define TYPE_DIR 0x2 -#define TYPE_ANY (TYPE_FILE | TYPE_DIR) -/** * fat_itr_resolve() - traverse directory structure to resolve the * requested path. @@ -907,7 +880,7 @@ static int fat_itr_isdir(fat_itr *itr)* @type: bitmask of allowable file types * @return 0 on success or -errno */ -static int fat_itr_resolve (fat_itr *itr,const char *path,unsigned type) +int fat_itr_resolve (fat_itr *itr,const char *path,unsigned type) {const char *next;include/fat.h +0
-0include/fat.h static inline u32 sect_to_clust(fsdata *fsdata, int sect) · line 196
Quoted 10 lines
include/fat.h +7
-0@@ -187,6 +187,38 @@ static inline u32 sect_to_clust(fsdata *fsdata, int sect)return (sect - fsdata->data_begin) / fsdata->clust_size; } +/* +* Directory iterator +*/ + +#define TYPE_FILE 0x1 +#define TYPE_DIR 0x2 +#define TYPE_ANY (TYPE_FILE | TYPE_DIR)Please, rename these to something more specific like
FS_ITER_ANY.
Quoted 6 lines
Quoted 3 lines
TYPE_ANYalready is defined infs/reiserfs/reiserfs_private.h:fs/reiserfs/reiserfs_private.h:160:#define
TYPE_ANY15Good catch though the definition above comes directly from Rob's original patch.
Oops, looking at the code closely, the duplication will never be hit because reiserfs_private.h is a private header.
Quoted 2 lines
Since there is only one occurrence of
TYPE_ANYin fs/fat, I'd rather expand it without introducing another definition.
I will put this change on hold unless a maintainer sticks to this idea.
Quoted 38 lines
Thanks,
-Takahiro AKASHIQuoted 34 lines
Best regards
Heinrich
Quoted 29 lines
include/fat.h +25
-0+ +typedef struct { +fsdata *fsdata;/* filesystem parameters */ +unsigned clust;/* current cluster */ +int last_cluster;/* set once we've read last cluster */ +int is_root;/* is iterator at root directory */ +int remaining;/* remaining dent's in current cluster */ + +/* current iterator position values: */ +dir_entry *dent;/* current directory entry */ +char l_name[VFAT_MAXLEN_BYTES ];/* long (vfat) name */ +char s_name[14 ];/* short 8.3 name */ +char *name;/* l_name if there is one, else s_name */ + +/* storage for current cluster in memory: */ +u8 block[MAX_CLUSTSIZE ]__aligned(ARCH_DMA_MINALIGN) ; +}fat_itr ; + +int fat_itr_root (fat_itr *itr,fsdata *fsdata); +void fat_itr_child (fat_itr *itr,fat_itr *parent); +void *next_cluster (fat_itr *itr); +int fat_itr_next (fat_itr *itr); +int fat_itr_isdir (fat_itr *itr); +int fat_itr_resolve (fat_itr *itr,const char *path,unsigned type); +int file_fat_detectfs (void );int fat_exists (const char *filename);int fat_size (const char *filename,loff_t *size);
PATCH 3/17 fs: fat: make directory iterator global for write use
In reply to AKASHI TakahiroQuoted 128 lines · AKASHI Takahiro
Directory iterator was introduced in major re-work of read operation by Rob. We want to use it for write operation extensively as well. This patch makes relevant functions, as well as iterator defition, visible outside of
fat.c.Signed-off-by AKASHI Takahiro <[email protected]>--- fs/fat/fat.c | 39 ++++++--------------------------------- include/fat.h | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 33 deletions(-)fs/fat/fat.c +6
-33@@ -634,25 +634,6 @@ static int get_fs_info(fsdata *mydata)* For more complete example, see fat_itr_resolve() */ -typedef struct { -fsdata *fsdata;/* filesystem parameters */ -unsigned clust;/* current cluster */ -int last_cluster;/* set once we've read last cluster */ -int is_root;/* is iterator at root directory */ -int remaining;/* remaining dent's in current cluster */ - -/* current iterator position values: */ -dir_entry *dent;/* current directory entry */ -char l_name[VFAT_MAXLEN_BYTES ];/* long (vfat) name */ -char s_name[14 ];/* short 8.3 name */ -char *name;/* l_name if there is one, else s_name */ - -/* storage for current cluster in memory: */ -u8 block[MAX_CLUSTSIZE ]__aligned(ARCH_DMA_MINALIGN) ; -}fat_itr ; - -static int fat_itr_isdir (fat_itr *itr); -/** * fat_itr_root() - initialize an iterator to start at the root * directory @@ -661,7 +642,7 @@ static int fat_itr_isdir(fat_itr *itr);* @fsdata: filesystem data for the partition * @return 0 on success, else -errno */ -static int fat_itr_root (fat_itr *itr,fsdata *fsdata) +int fat_itr_root (fat_itr *itr,fsdata *fsdata) {if (get_fs_info (fsdata))return -ENXIO ;@@ -693,7 +674,7 @@ static int fat_itr_root(fat_itr *itr, fsdata *fsdata)* @parent: the iterator pointing at a directory entry in the * parent directory of the directory to iterate */ -static void fat_itr_child (fat_itr *itr,fat_itr *parent) +void fat_itr_child (fat_itr *itr,fat_itr *parent) {fsdata *mydata = parent->fsdata;/* for silly macros */ unsigned clustnum =START (parent->dent);@@ -713,7 +694,7 @@ static void fat_itr_child(fat_itr *itr, fat_itr *parent) itr->last_cluster =0 ; } -static void *next_cluster (fat_itr *itr) +void *next_cluster (fat_itr *itr) {fsdata *mydata = itr->fsdata;/* for silly macros */ int ret;@@ -834,7 +815,7 @@ static dir_entry *extract_vfat_name(fat_itr *itr)* @return boolean, 1 if success or 0 if no more entries in the * current directory */ -static int fat_itr_next (fat_itr *itr) +int fat_itr_next (fat_itr *itr) {dir_entry *dent;@@ -879,19 +860,11 @@ static int fat_itr_next(fat_itr *itr)* @itr: the iterator * @return true if cursor is at a directory */ -static int fat_itr_isdir (fat_itr *itr) +int fat_itr_isdir (fat_itr *itr) {return !!(itr->dent->attr &ATTR_DIR ); } -/* -* Helpers: -*/ - -#define TYPE_FILE 0x1 -#define TYPE_DIR 0x2 -#define TYPE_ANY (TYPE_FILE | TYPE_DIR) -/** * fat_itr_resolve() - traverse directory structure to resolve the * requested path. @@ -907,7 +880,7 @@ static int fat_itr_isdir(fat_itr *itr)* @type: bitmask of allowable file types * @return 0 on success or -errno */ -static int fat_itr_resolve (fat_itr *itr,const char *path,unsigned type) +int fat_itr_resolve (fat_itr *itr,const char *path,unsigned type) {const char *next;include/fat.h +13
-0@@ -187,6 +187,38 @@ static inline u32 sect_to_clust(fsdata *fsdata, int sect)return (sect - fsdata->data_begin) / fsdata->clust_size; } +/* +* Directory iterator +*/ + +#define TYPE_FILE 0x1 +#define TYPE_DIR 0x2 +#define TYPE_ANY (TYPE_FILE | TYPE_DIR) + +typedef struct { + fsdata *fsdata; /* filesystem parameters */ + unsigned clust; /* current cluster */ + int last_cluster; /* set once we've read last cluster */ + int is_root; /* is iterator at root directory */
include/fat.h static inline u32 sect_to_clust(fsdata *fsdata, int sect) · line 212
Quoted 10 lines
include/fat.h +10
-0+int remaining;/* remaining dent's in current cluster */ + +/* current iterator position values: */ +dir_entry *dent;/* current directory entry */ +char l_name[VFAT_MAXLEN_BYTES ];/* long (vfat) name */ +char s_name[14 ];/* short 8.3 name */ +char *name;/* l_name if there is one, else s_name */ + +/* storage for current cluster in memory: */ +u8 block[MAX_CLUSTSIZE ]__aligned(ARCH_DMA_MINALIGN) ;
If CONFIG_FAT is not set, MAX_CLUSTSIZE is empty. And you get a build error:
CC fs/fs.o
In file included from fs/fs.c:12:0:include/fat.h:20:23: error: ‘CONFIG_FS_FAT_MAX_CLUSTSIZE’ undeclared here (not in a function); did you mean ‘CONFIG_SYS_MAX_FLASH_SECT’?
#define MAX_CLUSTSIZE CONFIG_FS_FAT_MAX_CLUSTSIZE
^
include/fat.h:214:19: note: in expansion of macro ‘MAX_CLUSTSIZE’
u8 block[MAX_CLUSTSIZE] __aligned(ARCH_DMA_MINALIGN);
^~~~~~~~~~~~~make[1]: *** [scripts/Makefile.build:279: fs/fs.o] Error 1
We should not assume that every board uses FAT.
Best regards
Heinrich
Quoted 13 lines
include/fat.h +9
-0+} fat_itr; + +int fat_itr_root (fat_itr *itr,fsdata *fsdata); +void fat_itr_child (fat_itr *itr,fat_itr *parent); +void *next_cluster (fat_itr *itr); +int fat_itr_next (fat_itr *itr); +int fat_itr_isdir (fat_itr *itr); +int fat_itr_resolve (fat_itr *itr,const char *path,unsigned type); +int file_fat_detectfs (void );int fat_exists (const char *filename);int fat_size (const char *filename,loff_t *size);
PATCH 3/17 fs: fat: make directory iterator global for write use
Quoted 146 lines · Heinrich Schuchardt
Quoted 128 lines · AKASHI Takahiro
Directory iterator was introduced in major re-work of read operation by Rob. We want to use it for write operation extensively as well. This patch makes relevant functions, as well as iterator defition, visible outside of
fat.c.Signed-off-by AKASHI Takahiro <[email protected]>--- fs/fat/fat.c | 39 ++++++--------------------------------- include/fat.h | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 33 deletions(-)fs/fat/fat.c +6
-33@@ -634,25 +634,6 @@ static int get_fs_info(fsdata *mydata)* For more complete example, see fat_itr_resolve() */ -typedef struct { -fsdata *fsdata;/* filesystem parameters */ -unsigned clust;/* current cluster */ -int last_cluster;/* set once we've read last cluster */ -int is_root;/* is iterator at root directory */ -int remaining;/* remaining dent's in current cluster */ - -/* current iterator position values: */ -dir_entry *dent;/* current directory entry */ -char l_name[VFAT_MAXLEN_BYTES ];/* long (vfat) name */ -char s_name[14 ];/* short 8.3 name */ -char *name;/* l_name if there is one, else s_name */ - -/* storage for current cluster in memory: */ -u8 block[MAX_CLUSTSIZE ]__aligned(ARCH_DMA_MINALIGN) ; -}fat_itr ; - -static int fat_itr_isdir (fat_itr *itr); -/** * fat_itr_root() - initialize an iterator to start at the root * directory @@ -661,7 +642,7 @@ static int fat_itr_isdir(fat_itr *itr);* @fsdata: filesystem data for the partition * @return 0 on success, else -errno */ -static int fat_itr_root (fat_itr *itr,fsdata *fsdata) +int fat_itr_root (fat_itr *itr,fsdata *fsdata) {if (get_fs_info (fsdata))return -ENXIO ;@@ -693,7 +674,7 @@ static int fat_itr_root(fat_itr *itr, fsdata *fsdata)* @parent: the iterator pointing at a directory entry in the * parent directory of the directory to iterate */ -static void fat_itr_child (fat_itr *itr,fat_itr *parent) +void fat_itr_child (fat_itr *itr,fat_itr *parent) {fsdata *mydata = parent->fsdata;/* for silly macros */ unsigned clustnum =START (parent->dent);@@ -713,7 +694,7 @@ static void fat_itr_child(fat_itr *itr, fat_itr *parent) itr->last_cluster =0 ; } -static void *next_cluster (fat_itr *itr) +void *next_cluster (fat_itr *itr) {fsdata *mydata = itr->fsdata;/* for silly macros */ int ret;@@ -834,7 +815,7 @@ static dir_entry *extract_vfat_name(fat_itr *itr)* @return boolean, 1 if success or 0 if no more entries in the * current directory */ -static int fat_itr_next (fat_itr *itr) +int fat_itr_next (fat_itr *itr) {dir_entry *dent;@@ -879,19 +860,11 @@ static int fat_itr_next(fat_itr *itr)* @itr: the iterator * @return true if cursor is at a directory */ -static int fat_itr_isdir (fat_itr *itr) +int fat_itr_isdir (fat_itr *itr) {return !!(itr->dent->attr &ATTR_DIR ); } -/* -* Helpers: -*/ - -#define TYPE_FILE 0x1 -#define TYPE_DIR 0x2 -#define TYPE_ANY (TYPE_FILE | TYPE_DIR) -/** * fat_itr_resolve() - traverse directory structure to resolve the * requested path. @@ -907,7 +880,7 @@ static int fat_itr_isdir(fat_itr *itr)* @type: bitmask of allowable file types * @return 0 on success or -errno */ -static int fat_itr_resolve (fat_itr *itr,const char *path,unsigned type) +int fat_itr_resolve (fat_itr *itr,const char *path,unsigned type) {const char *next;include/fat.h +13
-0@@ -187,6 +187,38 @@ static inline u32 sect_to_clust(fsdata *fsdata, int sect)return (sect - fsdata->data_begin) / fsdata->clust_size; } +/* +* Directory iterator +*/ + +#define TYPE_FILE 0x1 +#define TYPE_DIR 0x2 +#define TYPE_ANY (TYPE_FILE | TYPE_DIR) + +typedef struct { + fsdata *fsdata; /* filesystem parameters */ + unsigned clust; /* current cluster */ + int last_cluster; /* set once we've read last cluster */ + int is_root; /* is iterator at root directory */include/fat.h static inline u32 sect_to_clust(fsdata *fsdata, int sect) · line 212
Quoted 10 lines
include/fat.h +10
-0+int remaining;/* remaining dent's in current cluster */ + +/* current iterator position values: */ +dir_entry *dent;/* current directory entry */ +char l_name[VFAT_MAXLEN_BYTES ];/* long (vfat) name */ +char s_name[14 ];/* short 8.3 name */ +char *name;/* l_name if there is one, else s_name */ + +/* storage for current cluster in memory: */ +u8 block[MAX_CLUSTSIZE ]__aligned(ARCH_DMA_MINALIGN) ;If
CONFIG_FATis not set,MAX_CLUSTSIZEis empty. And you get a build error:CC
fs/fs.o
In file included fromfs/fs.c:12:0:include/fat.h:20:23: error: ‘CONFIG_FS_FAT_MAX_CLUSTSIZE’ undeclared here (not in a function); did you mean ‘CONFIG_SYS_MAX_FLASH_SECT’?
Quoted 6 lines
#define MAX_CLUSTSIZE CONFIG_FS_FAT_MAX_CLUSTSIZE ^ include/fat.h:214:19: note: in expansion of macro ‘MAX_CLUSTSIZE’ u8 block[MAX_CLUSTSIZE] __aligned(ARCH_DMA_MINALIGN); ^~~~~~~~~~~~~make[1]: *** [
scripts/Makefile.build:279:fs/fs.o] Error 1
Thank you for catching this.
Quoted 1 line
We should not assume that every board uses FAT.
The contents of include/fat.h is totally private to fat implementation. So I'd like to guard this include file like:
#ifndef _FAT_H
#define _FAT_H
#ifdef CONFIG_FS_FAT
<fat definitions>...
#endif /* CONFIG_FS_FAT */
#endif /* _FAT_H */
-Takahiro AKASHI
Quoted 18 lines
Best regards
Heinrich
Quoted 13 lines
include/fat.h +9
-0+} fat_itr; + +int fat_itr_root (fat_itr *itr,fsdata *fsdata); +void fat_itr_child (fat_itr *itr,fat_itr *parent); +void *next_cluster (fat_itr *itr); +int fat_itr_next (fat_itr *itr); +int fat_itr_isdir (fat_itr *itr); +int fat_itr_resolve (fat_itr *itr,const char *path,unsigned type); +int file_fat_detectfs (void );int fat_exists (const char *filename);int fat_size (const char *filename,loff_t *size);
PATCH 4/17 fs: fat: assure iterator's ->dent belongs to ->clust
In reply to AKASHI TakahiroIn my attempt to re-work write operation, it was revealed that iterator's "clust" does not always point to a cluster to which a current directory entry ("dent") belongs.
This patch assures that it is always true by adding "next_clust" which is used solely for dereferencing a cluster chain.
--- fs/fat/fat.c | 24 ++++++++++++++++-------- include/fat.h | 1 + 2 files changed, 17 insertions(+), 8 deletions(-)
fs/fat/fat.c +16 -8
@@ -649,6 +649,7 @@ int fat_itr_root(fat_itr *itr, fsdata *fsdata) itr->fsdata = fsdata; itr->clust = fsdata->root_cluster; + itr->next_clust = fsdata->root_cluster; itr->dent =NULL ; itr->remaining =0 ; itr->last_cluster =0 ;
@@ -684,9 +685,11 @@ void fat_itr_child(fat_itr *itr, fat_itr *parent) itr->fsdata = parent->fsdata;if (clustnum >0 ) { itr->clust = clustnum; + itr->next_clust = clustnum; itr->is_root =0 ; }else { itr->clust = parent->fsdata->root_cluster; + itr->next_clust = parent->fsdata->root_cluster; itr->is_root =1 ; } itr->dent =NULL ;
@@ -704,7 +707,7 @@ void *next_cluster(fat_itr *itr)if (itr->last_cluster)return NULL ; - sect =clust_to_sect (itr->fsdata, itr->clust); + sect =clust_to_sect (itr->fsdata, itr->next_clust);debug ("FAT read(sect=%d), clust_size=%d, DIRENTSPERBLOCK=%zd\n" , sect, itr->fsdata->clust_size,DIRENTSPERBLOCK );
@@ -725,18 +728,19 @@ void *next_cluster(fat_itr *itr)return NULL ; } + itr->clust = itr->next_clust;if (itr->is_root && itr->fsdata->fatsize !=32 ) { - itr->clust++; - sect =clust_to_sect (itr->fsdata, itr->clust); + itr->next_clust++; + sect =clust_to_sect (itr->fsdata, itr->next_clust);if (sect - itr->fsdata->rootdir_sect >= itr->fsdata->rootdir_size) { -debug ("cursect: 0x%x\n" , itr->clust); +debug ("nextclust: 0x%x\n" , itr->next_clust); itr->last_cluster =1 ; } }else { - itr->clust =get_fatent (itr->fsdata, itr->clust); -if (CHECK_CLUST (itr->clust, itr->fsdata->fatsize)) { -debug ("cursect: 0x%x\n" , itr->clust); + itr->next_clust =get_fatent (itr->fsdata, itr->next_clust); +if (CHECK_CLUST (itr->next_clust, itr->fsdata->fatsize)) { +debug ("nextclust: 0x%x\n" , itr->next_clust); itr->last_cluster =1 ; } }
@@ -752,8 +756,11 @@ static dir_entry *next_dent(fat_itr *itr) itr->fsdata->clust_size;/* have we reached the last cluster? */ -if (!dent) +if (!dent) { +/* a sign for no more entries left */ + itr->dent =NULL ;return NULL ; + } itr->remaining = nbytes /sizeof (dir_entry) -1 ; itr->dent = dent;
@@ -906,6 +913,7 @@ int fat_itr_resolve(fat_itr *itr, const char *path, unsigned type) (((next - path) == 2) && !strncmp(path, "..", 2))) {/* point back to itself */ itr->clust = itr->fsdata->root_cluster; + itr->next_clust = itr->fsdata->root_cluster; itr->dent =NULL ; itr->remaining =0 ; itr->last_cluster =0 ;
include/fat.h +1 -0
@@ -198,6 +198,7 @@ static inline u32 sect_to_clust(fsdata *fsdata, int sect) typedef struct { fsdata *fsdata; /* filesystem parameters */ unsigned clust; /* current cluster */ + unsigned next_clust; /* next cluster if remaining == 0 */ int last_cluster; /* set once we've read last cluster */ int is_root; /* is iterator at root directory */ int remaining; /* remaining dent's in current cluster */
Signature · 1 line
2.17.0
PATCH 5/17 fs: fat: check and normailze file name
In reply to AKASHI TakahiroFAT file system's long file name support is a bit complicated and has some restrictions on its naming. We should be careful about it especially for write as it may easily end up with wrong file system.
normalize_longname() check for the rules and normalize a file name if necessary. Please note, however, that this function is yet to be extended to fully comply with the standard.
--- fs/fat/fat_write.c | 52 +++++++++++++++++++++++++++++++++++++++------- 1 file changed, 44 insertions(+), 8 deletions(-)
fs/fat/fat_write.c +44 -8
@@ -899,6 +899,44 @@ static dir_entry *find_directory_entry(fsdata *mydata, int startsect,return NULL ; } +static int normalize_longname (char *l_filename,const char *filename) +{ +const char *p, legal[] ="!#$%&\'()-.@^`_{}~" ; +char c; +int name_len; + +/* Check that the filename is valid */ +for (p = filename; p < filename +strlen (filename); p++) { + c = *p; + +if (('0' <= c) && (c <='9' )) +continue ; +if (('A' <= c) && (c <='Z' )) +continue ; +if (('a' <= c) && (c <='z' )) +continue ; +if (strchr (legal, c)) +continue ; +/* extended code */ +if ((0x80 <= c) && (c <=0xff )) +continue ; + +return -1 ; + } + +/* Normalize it */ + name_len =strlen (filename); +if (name_len >=VFAT_MAXLEN_BYTES ) +/* should return an error? */ + name_len =VFAT_MAXLEN_BYTES -1 ; + +memcpy (l_filename, filename, name_len); + l_filename[name_len] =0 ;/* terminate the string */ +downcase (l_filename,INT_MAX ); + +return 0 ; +} +static int do_fat_write (const char *filename,void *buffer,loff_t size,loff_t *actwrite) {
@@ -910,7 +948,7 @@ static int do_fat_write(const char *filename, void *buffer, loff_t size,fsdata datablock;fsdata *mydata = &datablock;int cursect; -int ret =-1 , name_len; +int ret =-1 ;char l_filename[VFAT_MAXLEN_BYTES ]; *actwrite = size;
@@ -971,13 +1009,11 @@ static int do_fat_write(const char *filename, void *buffer, loff_t size, } dentptr = (dir_entry *) do_fat_read_at_block; - name_len =strlen (filename); -if (name_len >=VFAT_MAXLEN_BYTES ) - name_len =VFAT_MAXLEN_BYTES -1 ; - -memcpy (l_filename, filename, name_len); - l_filename[name_len] =0 ;/* terminate the string */ -downcase (l_filename,INT_MAX ); +if (normalize_longname (l_filename, filename)) { +printf ("FAT: illegal filename (%s)\n" , filename); + ret = -EINVAL ; + goto exit; + } startsect = mydata->rootdir_sect; retdent = find_directory_entry(mydata, startsect,
Signature · 1 line
2.17.0
PATCH 5/17 fs: fat: check and normailze file name
Quoted 9 lines · AKASHI Takahiro
FAT file system's long file name support is a bit complicated and has some restrictions on its naming. We should be careful about it especially for write as it may easily end up with wrong file system.
normalize_longname()check for the rules and normalize a file name if necessary. Please note, however, that this function is yet to be extended to fully comply with the standard.Signed-off-by AKASHI Takahiro <[email protected]>
The patch has to be rebased on current master due to
fs: fat: cannot write to subdirectories0dc1bfb7302d220a48364263d5632d6d572b069b
which has been merged into U-Boot master.
Quoted 9 lines
--- fs/fat/fat_write.c | 52 +++++++++++++++++++++++++++++++++++++++------- 1 file changed, 44 insertions(+), 8 deletions(-)fs/fat/fat_write.c +0
-0
fs/fat/fat_write.c static dir_entry *find_directory_entry(fsdata *mydata, int startsect, · line 904
Quoted 6 lines
fs/fat/fat_write.c +3
-0@@ -899,6 +899,44 @@ static dir_entry *find_directory_entry(fsdata *mydata, int startsect,return NULL ; } +static int normalize_longname (char *l_filename,const char *filename) +{ +const char *p, legal[] ="!#$%&\'()-.@^`_{}~" ;
The logic below gets simpler if you define the illegal characters like in the aforementioned patch.
Best regards
Heinrich
Quoted 12 lines
fs/fat/fat_write.c +12
-0+char c; +int name_len; + +/* Check that the filename is valid */ +for (p = filename; p < filename +strlen (filename); p++) { + c = *p; + +if (('0' <= c) && (c <='9' )) +continue ; +if (('A' <= c) && (c <='Z' )) +continue ; +if (('a' <= c) && (c <='z' ))
fs/fat/fat_write.c static dir_entry *find_directory_entry(fsdata *mydata, int startsect, · line 926
Quoted 10 lines
fs/fat/fat_write.c +10
-0+continue ; +if (strchr (legal, c)) +continue ; +/* extended code */ +if ((0x80 <= c) && (c <=0xff )) +continue ; + +return -1 ; + } +
<snip />
PATCH 6/17 fs: fat: write returns error code instead of -1
In reply to AKASHI TakahiroIt would be good that FAT write function return error code instead of just returning -1 as fat_read_file() does.
This patch attempts to address this issue although it is 'best effort (or estimate)' for now.
--- fs/fat/fat_write.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-)
fs/fat/fat_write.c +15 -4
@@ -956,7 +956,7 @@ static int do_fat_write(const char *filename, void *buffer, loff_t size,if (read_bootsectandvi (&bs, &volinfo, &mydata->fatsize)) {debug ("error: reading boot sector\n" ); -return -1 ; +return -EIO ; } total_sector = bs.total_sect;
@@ -997,7 +997,7 @@ static int do_fat_write(const char *filename, void *buffer, loff_t size, mydata->fatbuf =memalign (ARCH_DMA_MINALIGN ,FATBUFSIZE );if (mydata->fatbuf ==NULL ) {debug ("Error: allocating memory\n" ); -return -1 ; +return -ENOMEM ; } if (disk_read(cursect,
@@ -1005,6 +1005,7 @@ static int do_fat_write(const char *filename, void *buffer, loff_t size, (mydata->clust_size) : PREFETCH_BLOCKS, do_fat_read_at_block) < 0) {debug ("Error: reading rootdir block\n" ); + ret = -EIO ; goto exit; } dentptr = (dir_entry *) do_fat_read_at_block;
@@ -1029,6 +1030,7 @@ static int do_fat_write(const char *filename, void *buffer, loff_t size, size);if (ret) {printf ("Error: %llu overflow\n" , size); + ret = -ENOSPC ; goto exit; } }
@@ -1036,6 +1038,7 @@ static int do_fat_write(const char *filename, void *buffer, loff_t size, ret =clear_fatent (mydata, start_cluster);if (ret) {printf ("Error: clearing FAT entries\n" ); + ret = -EIO ; goto exit; }
@@ -1045,12 +1048,14 @@ static int do_fat_write(const char *filename, void *buffer, loff_t size, ret = start_cluster =find_empty_cluster (mydata);if (ret <0 ) {printf ("Error: finding empty cluster\n" ); + ret = -ENOSPC ; goto exit; } ret =check_overflow (mydata, start_cluster, size);if (ret) {printf ("Error: %llu overflow\n" , size); + ret = -ENOSPC ; goto exit; }
@@ -1065,12 +1070,14 @@ static int do_fat_write(const char *filename, void *buffer, loff_t size, ret = start_cluster =find_empty_cluster (mydata);if (ret <0 ) {printf ("Error: finding empty cluster\n" ); + ret = -ENOSPC ; goto exit; } ret =check_overflow (mydata, start_cluster, size);if (ret) {printf ("Error: %llu overflow\n" , size); + ret = -ENOSPC ; goto exit; } }else {
@@ -1087,6 +1094,7 @@ static int do_fat_write(const char *filename, void *buffer, loff_t size, ret =set_contents (mydata, retdent, buffer, size, actwrite);if (ret <0 ) {printf ("Error: writing contents\n" ); + ret = -EIO ; goto exit; }debug ("attempt to write 0x%llx bytes\n" , *actwrite);
@@ -1095,14 +1103,17 @@ static int do_fat_write(const char *filename, void *buffer, loff_t size, ret =flush_dirty_fat_buffer (mydata);if (ret) {printf ("Error: flush fat buffer\n" ); + ret = -EIO ; goto exit; }/* Write directory table to device */ ret =set_cluster (mydata, dir_curclust, get_dentfromdir_block, mydata->clust_size * mydata->sect_size); -if (ret) +if (ret) {printf ("Error: writing directory entry\n" ); + ret = -EIO ; + } exit:free (mydata->fatbuf);
@@ -1114,7 +1125,7 @@ int file_fat_write(const char *filename, void *buffer, loff_t offset, {if (offset !=0 ) {printf ("Error: non zero offset is currently not supported.\n" ); -return -1 ; +return -EINVAL ; }printf ("writing %s\n" , filename);
Signature · 1 line
2.17.0
PATCH 6/17 fs: fat: write returns error code instead of -1
Quoted 6 lines · AKASHI Takahiro
It would be good that FAT write function return error code instead of just returning -1 as
fat_read_file()does.
This patch attempts to address this issue although it is 'best effort (or estimate)' for now.Signed-off-by AKASHI Takahiro <[email protected]>
Some of the error message are written with debug() others with printf().
Shouldn't we switch everything to debug() so that the EFI console is not messed up?
Best regards
Heinrich
Quoted 117 lines
--- fs/fat/fat_write.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-)fs/fat/fat_write.c +15
-4@@ -956,7 +956,7 @@ static int do_fat_write(const char *filename, void *buffer, loff_t size,if (read_bootsectandvi (&bs, &volinfo, &mydata->fatsize)) {debug ("error: reading boot sector\n" ); -return -1 ; +return -EIO ; } total_sector = bs.total_sect;@@ -997,7 +997,7 @@ static int do_fat_write(const char *filename, void *buffer, loff_t size, mydata->fatbuf =memalign (ARCH_DMA_MINALIGN ,FATBUFSIZE );if (mydata->fatbuf ==NULL ) {debug ("Error: allocating memory\n" ); -return -1 ; +return -ENOMEM ; } if (disk_read(cursect,@@ -1005,6 +1005,7 @@ static int do_fat_write(const char *filename, void *buffer, loff_t size, (mydata->clust_size) : PREFETCH_BLOCKS, do_fat_read_at_block) < 0) {debug ("Error: reading rootdir block\n" ); + ret = -EIO ; goto exit; } dentptr = (dir_entry *) do_fat_read_at_block;@@ -1029,6 +1030,7 @@ static int do_fat_write(const char *filename, void *buffer, loff_t size, size);if (ret) {printf ("Error: %llu overflow\n" , size); + ret = -ENOSPC ; goto exit; } }@@ -1036,6 +1038,7 @@ static int do_fat_write(const char *filename, void *buffer, loff_t size, ret =clear_fatent (mydata, start_cluster);if (ret) {printf ("Error: clearing FAT entries\n" ); + ret = -EIO ; goto exit; }@@ -1045,12 +1048,14 @@ static int do_fat_write(const char *filename, void *buffer, loff_t size, ret = start_cluster =find_empty_cluster (mydata);if (ret <0 ) {printf ("Error: finding empty cluster\n" ); + ret = -ENOSPC ; goto exit; } ret =check_overflow (mydata, start_cluster, size);if (ret) {printf ("Error: %llu overflow\n" , size); + ret = -ENOSPC ; goto exit; }@@ -1065,12 +1070,14 @@ static int do_fat_write(const char *filename, void *buffer, loff_t size, ret = start_cluster =find_empty_cluster (mydata);if (ret <0 ) {printf ("Error: finding empty cluster\n" ); + ret = -ENOSPC ; goto exit; } ret =check_overflow (mydata, start_cluster, size);if (ret) {printf ("Error: %llu overflow\n" , size); + ret = -ENOSPC ; goto exit; } }else {@@ -1087,6 +1094,7 @@ static int do_fat_write(const char *filename, void *buffer, loff_t size, ret =set_contents (mydata, retdent, buffer, size, actwrite);if (ret <0 ) {printf ("Error: writing contents\n" ); + ret = -EIO ; goto exit; }debug ("attempt to write 0x%llx bytes\n" , *actwrite);@@ -1095,14 +1103,17 @@ static int do_fat_write(const char *filename, void *buffer, loff_t size, ret =flush_dirty_fat_buffer (mydata);if (ret) {printf ("Error: flush fat buffer\n" ); + ret = -EIO ; goto exit; }/* Write directory table to device */ ret =set_cluster (mydata, dir_curclust, get_dentfromdir_block, mydata->clust_size * mydata->sect_size); -if (ret) +if (ret) {printf ("Error: writing directory entry\n" ); + ret = -EIO ; + } exit:free (mydata->fatbuf);@@ -1114,7 +1125,7 @@ int file_fat_write(const char *filename, void *buffer, loff_t offset, {if (offset !=0 ) {printf ("Error: non zero offset is currently not supported.\n" ); -return -1 ; +return -EINVAL ; }printf ("writing %s\n" , filename);
PATCH 6/17 fs: fat: write returns error code instead of -1
Quoted 9 lines · Heinrich Schuchardt
Quoted 6 lines · AKASHI Takahiro
It would be good that FAT write function return error code instead of just returning -1 as
fat_read_file()does.
This patch attempts to address this issue although it is 'best effort (or estimate)' for now.Signed-off-by AKASHI Takahiro <[email protected]>Some of the error message are written with
debug()others withprintf().
Right, but as you know, there is already a mixture of debug() and printf() in the existing code.
Here I tried to do my best to use either one so as to make the usage consistent with existing code though I don't know the exact discipline.
Quoted 2 lines
Shouldn't we switch everything to
debug()so that the EFI console is not messed up?
Is this a different issue, isn't it?
(I suppose that one of Rob's patches tried to address this issue.)
So I'd like to listen to any opinion from other folks, too.
Thanks,
-Takahiro AKASHI
Quoted 122 lines
Best regards
Heinrich
Quoted 117 lines
--- fs/fat/fat_write.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-)fs/fat/fat_write.c +15
-4@@ -956,7 +956,7 @@ static int do_fat_write(const char *filename, void *buffer, loff_t size,if (read_bootsectandvi (&bs, &volinfo, &mydata->fatsize)) {debug ("error: reading boot sector\n" ); -return -1 ; +return -EIO ; } total_sector = bs.total_sect;@@ -997,7 +997,7 @@ static int do_fat_write(const char *filename, void *buffer, loff_t size, mydata->fatbuf =memalign (ARCH_DMA_MINALIGN ,FATBUFSIZE );if (mydata->fatbuf ==NULL ) {debug ("Error: allocating memory\n" ); -return -1 ; +return -ENOMEM ; } if (disk_read(cursect,@@ -1005,6 +1005,7 @@ static int do_fat_write(const char *filename, void *buffer, loff_t size, (mydata->clust_size) : PREFETCH_BLOCKS, do_fat_read_at_block) < 0) {debug ("Error: reading rootdir block\n" ); + ret = -EIO ; goto exit; } dentptr = (dir_entry *) do_fat_read_at_block;@@ -1029,6 +1030,7 @@ static int do_fat_write(const char *filename, void *buffer, loff_t size, size);if (ret) {printf ("Error: %llu overflow\n" , size); + ret = -ENOSPC ; goto exit; } }@@ -1036,6 +1038,7 @@ static int do_fat_write(const char *filename, void *buffer, loff_t size, ret =clear_fatent (mydata, start_cluster);if (ret) {printf ("Error: clearing FAT entries\n" ); + ret = -EIO ; goto exit; }@@ -1045,12 +1048,14 @@ static int do_fat_write(const char *filename, void *buffer, loff_t size, ret = start_cluster =find_empty_cluster (mydata);if (ret <0 ) {printf ("Error: finding empty cluster\n" ); + ret = -ENOSPC ; goto exit; } ret =check_overflow (mydata, start_cluster, size);if (ret) {printf ("Error: %llu overflow\n" , size); + ret = -ENOSPC ; goto exit; }@@ -1065,12 +1070,14 @@ static int do_fat_write(const char *filename, void *buffer, loff_t size, ret = start_cluster =find_empty_cluster (mydata);if (ret <0 ) {printf ("Error: finding empty cluster\n" ); + ret = -ENOSPC ; goto exit; } ret =check_overflow (mydata, start_cluster, size);if (ret) {printf ("Error: %llu overflow\n" , size); + ret = -ENOSPC ; goto exit; } }else {@@ -1087,6 +1094,7 @@ static int do_fat_write(const char *filename, void *buffer, loff_t size, ret =set_contents (mydata, retdent, buffer, size, actwrite);if (ret <0 ) {printf ("Error: writing contents\n" ); + ret = -EIO ; goto exit; }debug ("attempt to write 0x%llx bytes\n" , *actwrite);@@ -1095,14 +1103,17 @@ static int do_fat_write(const char *filename, void *buffer, loff_t size, ret =flush_dirty_fat_buffer (mydata);if (ret) {printf ("Error: flush fat buffer\n" ); + ret = -EIO ; goto exit; }/* Write directory table to device */ ret =set_cluster (mydata, dir_curclust, get_dentfromdir_block, mydata->clust_size * mydata->sect_size); -if (ret) +if (ret) {printf ("Error: writing directory entry\n" ); + ret = -EIO ; + } exit:free (mydata->fatbuf);@@ -1114,7 +1125,7 @@ int file_fat_write(const char *filename, void *buffer, loff_t offset, {if (offset !=0 ) {printf ("Error: non zero offset is currently not supported.\n" ); -return -1 ; +return -EINVAL ; }printf ("writing %s\n" , filename);
PATCH 7/17 fs: fat: support write with sub-directory path
In reply to AKASHI TakahiroIn this patch, write implementation is overhauled and rewritten by making full use of directory iterator. The ovbious bonus is that we are now able to write to a file with a directory path, like /A/B/C/FILE.
Please note that, as there is no notion of "current directory" on u-boot, a file name specified must contain an absolute directory path. Otherwise, "/" (root directory) is assumed.
--- fs/fat/fat.c | 9 - fs/fat/fat_write.c | 469 +++++++++++++++------------------------------ 2 files changed, 157 insertions(+), 321 deletions(-)
fs/fat/fat.c +0 -9
@@ -464,15 +464,6 @@ static __u8 mkcksum(const char name[8], const char ext[3])return ret; } -/* -* TODO these should go away once fat_write is reworked to use the -* directory iterator -*/ -__u8 get_dentfromdir_block[MAX_CLUSTSIZE ] -__aligned(ARCH_DMA_MINALIGN) ; -__u8 do_fat_read_at_block[MAX_CLUSTSIZE ] -__aligned(ARCH_DMA_MINALIGN) ; -/* * Read boot sector and volume info from a FAT filesystem */
fs/fat/fat_write.c +157 -312
607 lines not on this page · raw message
Signature · 1 line
2.17.0
PATCH 8/17 fs: fat: refactor write interface for a file offset
In reply to AKASHI TakahiroThe current write implementation is quite simple: remove existing clusters and then allocating new ones and filling them with data. This, inevitably, enforces always writing from the beginning of a file.
As the first step to lift this restriction, fat_file_write() and set_contents() are modified to accept an additional parameter, file offset and further re-factored so that, in the next patch, all the necessary code will be put into set_contents().
--- fs/fat/fat_write.c | 178 +++++++++++++++++---------------------------- 1 file changed, 65 insertions(+), 113 deletions(-)
fs/fat/fat_write.c +65 -113
@@ -528,6 +528,43 @@ static int clear_fatent(fsdata *mydata, __u32 entry)return 0 ; } +/* +* Set start cluster in directory entry +*/ +static void set_start_cluster (const fsdata *mydata,dir_entry *dentptr, +__u32 start_cluster) +{ +if (mydata->fatsize ==32 ) + dentptr->starthi = +cpu_to_le16 ((start_cluster &0xffff0000 ) >>16 ); + dentptr->start =cpu_to_le16 (start_cluster &0xffff ); +} + +/* +* Check whether adding a file makes the file system to +* exceed the size of the block device +* Return -1 when overflow occurs, otherwise return 0 +*/ +static int check_overflow (fsdata *mydata,__u32 clustnum,loff_t size) +{ +__u32 startsect, sect_num, offset; + +if (clustnum >0 ) { + startsect =clust_to_sect (mydata, clustnum); + }else { + startsect = mydata->rootdir_sect; + } + + sect_num =div_u64_rem (size, mydata->sect_size, &offset); + +if (offset !=0 ) + sect_num++; + +if (startsect + sect_num > total_sector) +return -1 ; +return 0 ; +} +/* * Write at most 'maxsize' bytes from 'buffer' into * the file associated with 'dentptr'
@@ -535,29 +572,36 @@ static int clear_fatent(fsdata *mydata, __u32 entry)* or return -1 on fatal errors. */ static int -set_contents (fsdata *mydata,dir_entry *dentptr,__u8 *buffer, +set_contents (fsdata *mydata,dir_entry *dentptr,loff_t pos,__u8 *buffer,loff_t maxsize,loff_t *gotsize) { -loff_t filesize =FAT2CPU32 (dentptr->size); +loff_t filesize;unsigned int bytesperclust = mydata->clust_size * mydata->sect_size;__u32 curclust =START (dentptr);__u32 endclust =0 , newclust =0 ;loff_t actsize; *gotsize =0 ; -debug ("Filesize: %llu bytes\n" , filesize); - -if (maxsize >0 && filesize > maxsize) - filesize = maxsize; + filesize = maxsize;debug ("%llu bytes\n" , filesize); -if (!curclust) { -if (filesize) { -debug ("error: nonempty clusterless file!\n" ); +if (curclust) { +/* +* release already-allocated clusters anyway +*/ +if (clear_fatent (mydata, curclust)) { +printf ("Error: clearing FAT entries\n" );return -1 ; } -return 0 ; + } + + curclust =find_empty_cluster (mydata); +set_start_cluster (mydata, dentptr, curclust); + +if (check_overflow (mydata, curclust, filesize)) { +printf ("Error: no space left: %llu\n" , filesize); +return -1 ; } actsize = bytesperclust;
@@ -568,6 +612,7 @@ set_contents(fsdata *mydata, dir_entry *dentptr, __u8 *buffer, newclust =determine_fatent (mydata, endclust);if ((newclust -1 ) != endclust) +/* write to <curclust..endclust> */ goto getit;if (CHECK_CLUST (newclust, mydata->fatsize)) {
@@ -614,18 +659,8 @@ getit: actsize = bytesperclust; curclust = endclust = newclust; }while (1 ); -} -/* -* Set start cluster in directory entry -*/ -static void set_start_cluster (const fsdata *mydata,dir_entry *dentptr, -__u32 start_cluster) -{ -if (mydata->fatsize ==32 ) - dentptr->starthi = -cpu_to_le16 ((start_cluster &0xffff0000 ) >>16 ); - dentptr->start =cpu_to_le16 (start_cluster &0xffff ); +return 0 ; }/*
@@ -642,31 +677,6 @@ static void fill_dentry(fsdata *mydata, dir_entry *dentptr,set_name (dentptr, filename); } -/* -* Check whether adding a file makes the file system to -* exceed the size of the block device -* Return -1 when overflow occurs, otherwise return 0 -*/ -static int check_overflow (fsdata *mydata,__u32 clustnum,loff_t size) -{ -__u32 startsect, sect_num, offset; - -if (clustnum >0 ) { - startsect =clust_to_sect (mydata, clustnum); - }else { - startsect = mydata->rootdir_sect; - } - - sect_num =div_u64_rem (size, mydata->sect_size, &offset); - -if (offset !=0 ) - sect_num++; - -if (startsect + sect_num > total_sector) -return -1 ; -return 0 ; -} -/* * Find a directory entry based on filename or start cluster number * If the directory entry is not found,
@@ -784,11 +794,10 @@ static int normalize_longname(char *l_filename, const char *filename)return 0 ; } -static int do_fat_write (const char *filename,void *buffer,loff_t size, -loff_t *actwrite) +int file_fat_write_at (const char *filename,loff_t pos,void *buffer, +loff_t size,loff_t *actwrite) {dir_entry *retdent; -__u32 start_cluster;fsdata datablock = { .fatbuf =NULL , };fsdata *mydata = &datablock;fat_itr *itr =NULL ;
@@ -796,6 +805,8 @@ static int do_fat_write(const char *filename, void *buffer, loff_t size,char *filename_copy, *parent, *basename;char l_filename[VFAT_MAXLEN_BYTES ]; +debug ("writing %s\n" , filename); + filename_copy =strdup (filename);if (!filename_copy)return -ENOMEM ;
@@ -841,47 +852,8 @@ static int do_fat_write(const char *filename, void *buffer, loff_t size, goto exit; } -/* Update file size and start_cluster in a directory entry */ - retdent->size =cpu_to_le32 (size); - start_cluster =START (retdent); - -if (start_cluster) { -if (size) { - ret =check_overflow (mydata, start_cluster, - size); -if (ret) { -printf ("Error: %llu overflow\n" , size); - ret = -ENOSPC ; - goto exit; - } - } - - ret =clear_fatent (mydata, start_cluster); -if (ret) { -printf ("Error: clearing FAT entries\n" ); - ret = -EIO ; - goto exit; - } - -if (!size) -set_start_cluster (mydata, retdent,0 ); - }else if (size) { - ret = start_cluster =find_empty_cluster (mydata); -if (ret <0 ) { -printf ("Error: finding empty cluster\n" ); - ret = -ENOSPC ; - goto exit; - } - - ret =check_overflow (mydata, start_cluster, size); -if (ret) { -printf ("Error: %llu overflow\n" , size); - ret = -ENOSPC ; - goto exit; - } - -set_start_cluster (mydata, retdent, start_cluster); - } +/* Update file size in a directory entry */ + retdent->size =cpu_to_le32 (pos + size); }else {/* Create a new file */
@@ -909,32 +881,13 @@ static int do_fat_write(const char *filename, void *buffer, loff_t size, goto exit; } -if (size) { - ret = start_cluster =find_empty_cluster (mydata); -if (ret <0 ) { -printf ("Error: finding empty cluster\n" ); - ret = -ENOSPC ; - goto exit; - } - - ret =check_overflow (mydata, start_cluster, size); -if (ret) { -printf ("Error: %llu overflow\n" , size); - ret = -ENOSPC ; - goto exit; - } - }else { - start_cluster =0 ; - } -/* Set attribute as archieve for regular file */ -fill_dentry (itr->fsdata, itr->dent, filename, - start_cluster, size,0x20 ); +fill_dentry (itr->fsdata, itr->dent, filename,0 , size,0x20 ); retdent = itr->dent; } - ret =set_contents (mydata, retdent, buffer, size, actwrite); + ret =set_contents (mydata, retdent, pos, buffer, size, actwrite);if (ret <0 ) {printf ("Error: writing contents\n" ); ret = -EIO ;
@@ -973,6 +926,5 @@ int file_fat_write(const char *filename, void *buffer, loff_t offset,return -EINVAL ; } -printf ("writing %s\n" , filename); -return do_fat_write (filename, buffer, maxsize, actwrite); +return file_fat_write_at (filename, offset, buffer, maxsize, actwrite); }
Signature · 1 line
2.17.0
PATCH 9/17 fs: fat: support write with non-zero offset
In reply to AKASHI TakahiroIn this patch, all the necessary code for allowing for a file offset at write is implemented. What plays a major roll here is get_set_cluster(), which, in contrast to its counterpart, set_cluster(), only operates on already-allocated clusters, overwriting with data.
So, with a file offset specified, set_contents() seeks and writes data with set_get_cluster() until the end of a file, and, once it reaches there, continues writing with set_cluster() for the rest.
Please note that a file will be trimmed as a result of write operation if write ends before reaching file's end. This is an intended behavior in order to maitain compatibility with the current interface.
--- fs/fat/fat_write.c | 287 ++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 272 insertions(+), 15 deletions(-)
fs/fat/fat_write.c +272 -15
@@ -450,6 +450,120 @@ set_cluster(fsdata *mydata, __u32 clustnum, __u8 *buffer,return 0 ; } +static __u8 tmpbuf_cluster[MAX_CLUSTSIZE ]__aligned(ARCH_DMA_MINALIGN) ; + +/* +* Read and modify data on existing and consecutive cluster blocks +*/ +static int +get_set_cluster (fsdata *mydata,__u32 clustnum,loff_t pos,__u8 *buffer, +loff_t size,loff_t *gotsize) +{ +unsigned int bytesperclust = mydata->clust_size * mydata->sect_size; +__u32 startsect; +loff_t wsize; +int clustcount, i, ret; + + *gotsize =0 ; +if (!size) +return 0 ; + +assert (pos < bytesperclust); + startsect =clust_to_sect (mydata, clustnum); + +debug ("clustnum: %d, startsect: %d, pos: %lld\n" , clustnum, startsect, + pos); + +/* partial write@beginning */ +if (pos) { + wsize =min (bytesperclust - pos, size); + ret =disk_read (startsect, mydata->clust_size, tmpbuf_cluster); +if (ret != mydata->clust_size) { +debug ("Error reading data (got %d)\n" , ret); +return -1 ; + } + +memcpy (tmpbuf_cluster + pos, buffer, wsize); + ret =disk_write (startsect, mydata->clust_size, tmpbuf_cluster); +if (ret != mydata->clust_size) { +debug ("Error writing data (got %d)\n" , ret); +return -1 ; + } + + size -= wsize; + buffer += wsize; + *gotsize += wsize; + + startsect += mydata->clust_size; + +if (!size) +return 0 ; + } + +/* full-cluster write */ +if (size >= bytesperclust) { + clustcount =lldiv (size, bytesperclust); + +if (!((unsigned long )buffer & (ARCH_DMA_MINALIGN -1 ))) { + wsize = clustcount * bytesperclust; + ret =disk_write (startsect, + clustcount * mydata->clust_size, + buffer); +if (ret != clustcount * mydata->clust_size) { +debug ("Error writing data (got %d)\n" , ret); +return -1 ; + } + + size -= wsize; + buffer += wsize; + *gotsize += wsize; + + startsect += clustcount * mydata->clust_size; + }else { +for (i =0 ; i < clustcount; i++) { +memcpy (tmpbuf_cluster, buffer, bytesperclust); + ret =disk_write (startsect, mydata->clust_size, + tmpbuf_cluster); +if (ret != mydata->clust_size) { +debug ("Error writing data (got %d)\n" , + ret); +return -1 ; + } + + size -= bytesperclust; + buffer += bytesperclust; + *gotsize += bytesperclust; + + startsect += mydata->clust_size; + } + } + } + +/* partial write at end */ +if (size) { + wsize = size; + ret =disk_read (startsect, mydata->clust_size, tmpbuf_cluster); +if (ret != mydata->clust_size) { +debug ("Error reading data (got %d)\n" , ret); +return -1 ; + } +memcpy (tmpbuf_cluster, buffer, wsize); + ret =disk_write (startsect, mydata->clust_size, tmpbuf_cluster); +if (ret != mydata->clust_size) { +debug ("Error writing data (got %d)\n" , ret); +return -1 ; + } + + size -= wsize; + buffer += wsize; + *gotsize += wsize; + } + +assert (!size); + +return 0 ; +} +/* * Find the first empty cluster */
@@ -579,26 +693,158 @@ set_contents(fsdata *mydata, dir_entry *dentptr, loff_t pos, __u8 *buffer,unsigned int bytesperclust = mydata->clust_size * mydata->sect_size;__u32 curclust =START (dentptr);__u32 endclust =0 , newclust =0 ; -loff_t actsize; +loff_t cur_pos, offset, actsize, wsize; *gotsize =0 ; - filesize = maxsize; + filesize = pos + maxsize;debug ("%llu bytes\n" , filesize); -if (curclust) { -/* -* release already-allocated clusters anyway -*/ -if (clear_fatent (mydata, curclust)) { -printf ("Error: clearing FAT entries\n" ); +if (!filesize) { +if (!curclust) +return 0 ; +if (!CHECK_CLUST (curclust, mydata->fatsize) || +IS_LAST_CLUST (curclust, mydata->fatsize)) { +clear_fatent (mydata, curclust); +set_start_cluster (mydata, dentptr,0 ); +return 0 ; + } +debug ("curclust: 0x%x\n" , curclust); +debug ("Invalid FAT entry\n" ); +return -1 ; + } + +if (!curclust) { +assert (pos ==0 ); + goto set_clusters; + } + +/* go to cluster at pos */ + cur_pos = bytesperclust; +while (1 ) { +if (pos <= cur_pos) +break ; +if (IS_LAST_CLUST (curclust, mydata->fatsize)) +break ; + + newclust =get_fatent (mydata, curclust); +if (!IS_LAST_CLUST (newclust, mydata->fatsize) && +CHECK_CLUST (newclust, mydata->fatsize)) { +debug ("curclust: 0x%x\n" , curclust); +debug ("Invalid FAT entry\n" );return -1 ; } + + cur_pos += bytesperclust; + curclust = newclust; + } +if (IS_LAST_CLUST (curclust, mydata->fatsize)) { +assert (pos == cur_pos); + goto set_clusters; } - curclust =find_empty_cluster (mydata); -set_start_cluster (mydata, dentptr, curclust); +assert (pos < cur_pos); + cur_pos -= bytesperclust; +/* overwrite */ +assert (IS_LAST_CLUST (curclust, mydata->fatsize) || + !CHECK_CLUST (curclust, mydata->fatsize)); + +while (1 ) { +/* search for allocated consecutive clusters */ + actsize = bytesperclust; + endclust = curclust; +while (1 ) { +if (filesize <= (cur_pos + actsize)) +break ; + + newclust =get_fatent (mydata, endclust); + +if (IS_LAST_CLUST (newclust, mydata->fatsize)) +break ; +if (CHECK_CLUST (newclust, mydata->fatsize)) { +debug ("curclust: 0x%x\n" , curclust); +debug ("Invalid FAT entry\n" ); +return -1 ; + } + + actsize += bytesperclust; + endclust = newclust; + } + +/* overwrite to <curclust..endclust> */ +if (pos < cur_pos) + offset =0 ; +else + offset = pos - cur_pos; + wsize =min (cur_pos + actsize, filesize) - pos; +if (get_set_cluster (mydata, curclust, offset, buffer, wsize, + &actsize)) { +printf ("Error get-and-setting cluster\n" ); +return -1 ; + } + buffer += wsize; + *gotsize += wsize; + cur_pos += offset + wsize; + +if (filesize <= cur_pos) +break ; + +/* CHECK: newclust = get_fatent(mydata, endclust); */ + +if (IS_LAST_CLUST (newclust, mydata->fatsize)) +/* no more clusters */ +break ; + + curclust = newclust; + } + +if (filesize <= cur_pos) { +/* no more write */ + newclust =get_fatent (mydata, endclust); +if (!IS_LAST_CLUST (newclust, mydata->fatsize)) { +/* truncate the rest */ +clear_fatent (mydata, newclust); + +/* Mark end of file in FAT */ +if (mydata->fatsize ==12 ) + newclust =0xfff ; +else if (mydata->fatsize ==16 ) + newclust =0xffff ; +else if (mydata->fatsize ==32 ) + newclust =0xfffffff ; +set_fatent_value (mydata, endclust, newclust); + } + +return 0 ; + } + + curclust = endclust; + filesize -= cur_pos; +assert (!(cur_pos % bytesperclust)); + +set_clusters: +/* allocate and write */ +assert (!pos); + +/* Assure that curclust is valid */ +if (!curclust) { + curclust =find_empty_cluster (mydata); +set_start_cluster (mydata, dentptr, curclust); + }else { + newclust =get_fatent (mydata, curclust); + +if (IS_LAST_CLUST (newclust, mydata->fatsize)) { + newclust =determine_fatent (mydata, curclust); +set_fatent_value (mydata, curclust, newclust); + curclust = newclust; + }else { +debug ("error: something wrong\n" ); +return -1 ; + } + } + +/* TODO: already partially written */ if (check_overflow (mydata, curclust, filesize)) {printf ("Error: no space left: %llu\n" , filesize);return -1 ;
@@ -852,6 +1098,16 @@ int file_fat_write_at(const char *filename, loff_t pos, void *buffer, goto exit; } +/* A file exists */ +if (pos ==-1 ) +/* Append to the end */ + pos =FAT2CPU32 (retdent->size); +if (pos > retdent->size) { +/* No hole allowed */ + ret = -EINVAL ; + goto exit; + } +/* Update file size in a directory entry */ retdent->size =cpu_to_le32 (pos + size); }else {
@@ -872,6 +1128,12 @@ int file_fat_write_at(const char *filename, loff_t pos, void *buffer, goto exit; } +if (pos) { +/* No hole allowed */ + ret = -EINVAL ; + goto exit; + } +memset (itr->dent,0 ,sizeof (*itr->dent));/* Set short name to set alias checksum field in dir_slot */
@@ -921,10 +1183,5 @@ exit:int file_fat_write (const char *filename,void *buffer,loff_t offset,loff_t maxsize,loff_t *actwrite) { -if (offset !=0 ) { -printf ("Error: non zero offset is currently not supported.\n" ); -return -EINVAL ; - } -return file_fat_write_at (filename, offset, buffer, maxsize, actwrite); }
Signature · 1 line
2.17.0
PATCH 9/17 fs: fat: support write with non-zero offset
Quoted 5 lines · AKASHI Takahiro
In this patch, all the necessary code for allowing for a file offset at write is implemented. What plays a major roll here is
get_set_cluster(), which, in contrast to its counterpart,set_cluster(), only operates on already-allocated clusters, overwriting with data.
Quoted 7 lines
So, with a file offset specified,
set_contents()seeks and writes data withset_get_cluster()until the end of a file, and, once it reaches there, continues writing withset_cluster()for the rest.Please note that a file will be trimmed as a result of write operation if write ends before reaching file's end. This is an intended behavior in order to maitain compatibility with the current interface.
This does not match the EFI spec.
Quoted 2 lines
Signed-off-by AKASHI Takahiro <[email protected]>
When testing I observed that I could not write at an offset larger than the file size. This does not match the EFI spec:
EFI_FILE_PROTOCOL.SetPosition():
seeking past the end of the file is allowed (a subsequent write would grow the file).
Best regards
Heinrich
Quoted 340 lines
--- fs/fat/fat_write.c | 287 ++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 272 insertions(+), 15 deletions(-)fs/fat/fat_write.c +272
-15@@ -450,6 +450,120 @@ set_cluster(fsdata *mydata, __u32 clustnum, __u8 *buffer,return 0 ; } +static __u8 tmpbuf_cluster[MAX_CLUSTSIZE ]__aligned(ARCH_DMA_MINALIGN) ; + +/* +* Read and modify data on existing and consecutive cluster blocks +*/ +static int +get_set_cluster (fsdata *mydata,__u32 clustnum,loff_t pos,__u8 *buffer, +loff_t size,loff_t *gotsize) +{ +unsigned int bytesperclust = mydata->clust_size * mydata->sect_size; +__u32 startsect; +loff_t wsize; +int clustcount, i, ret; + + *gotsize =0 ; +if (!size) +return 0 ; + +assert (pos < bytesperclust); + startsect =clust_to_sect (mydata, clustnum); + +debug ("clustnum: %d, startsect: %d, pos: %lld\n" , clustnum, startsect, + pos); + +/* partial write at beginning */ +if (pos) { + wsize =min (bytesperclust - pos, size); + ret =disk_read (startsect, mydata->clust_size, tmpbuf_cluster); +if (ret != mydata->clust_size) { +debug ("Error reading data (got %d)\n" , ret); +return -1 ; + } + +memcpy (tmpbuf_cluster + pos, buffer, wsize); + ret =disk_write (startsect, mydata->clust_size, tmpbuf_cluster); +if (ret != mydata->clust_size) { +debug ("Error writing data (got %d)\n" , ret); +return -1 ; + } + + size -= wsize; + buffer += wsize; + *gotsize += wsize; + + startsect += mydata->clust_size; + +if (!size) +return 0 ; + } + +/* full-cluster write */ +if (size >= bytesperclust) { + clustcount =lldiv (size, bytesperclust); + +if (!((unsigned long )buffer & (ARCH_DMA_MINALIGN -1 ))) { + wsize = clustcount * bytesperclust; + ret =disk_write (startsect, + clustcount * mydata->clust_size, + buffer); +if (ret != clustcount * mydata->clust_size) { +debug ("Error writing data (got %d)\n" , ret); +return -1 ; + } + + size -= wsize; + buffer += wsize; + *gotsize += wsize; + + startsect += clustcount * mydata->clust_size; + }else { +for (i =0 ; i < clustcount; i++) { +memcpy (tmpbuf_cluster, buffer, bytesperclust); + ret =disk_write (startsect, mydata->clust_size, + tmpbuf_cluster); +if (ret != mydata->clust_size) { +debug ("Error writing data (got %d)\n" , + ret); +return -1 ; + } + + size -= bytesperclust; + buffer += bytesperclust; + *gotsize += bytesperclust; + + startsect += mydata->clust_size; + } + } + } + +/* partial write at end */ +if (size) { + wsize = size; + ret =disk_read (startsect, mydata->clust_size, tmpbuf_cluster); +if (ret != mydata->clust_size) { +debug ("Error reading data (got %d)\n" , ret); +return -1 ; + } +memcpy (tmpbuf_cluster, buffer, wsize); + ret =disk_write (startsect, mydata->clust_size, tmpbuf_cluster); +if (ret != mydata->clust_size) { +debug ("Error writing data (got %d)\n" , ret); +return -1 ; + } + + size -= wsize; + buffer += wsize; + *gotsize += wsize; + } + +assert (!size); + +return 0 ; +} +/* * Find the first empty cluster */ @@ -579,26 +693,158 @@ set_contents(fsdata *mydata, dir_entry *dentptr, loff_t pos, __u8 *buffer,unsigned int bytesperclust = mydata->clust_size * mydata->sect_size;__u32 curclust =START (dentptr);__u32 endclust =0 , newclust =0 ; -loff_t actsize; +loff_t cur_pos, offset, actsize, wsize; *gotsize =0 ; - filesize = maxsize; + filesize = pos + maxsize;debug ("%llu bytes\n" , filesize); -if (curclust) { -/* -* release already-allocated clusters anyway -*/ -if (clear_fatent (mydata, curclust)) { -printf ("Error: clearing FAT entries\n" ); +if (!filesize) { +if (!curclust) +return 0 ; +if (!CHECK_CLUST (curclust, mydata->fatsize) || +IS_LAST_CLUST (curclust, mydata->fatsize)) { +clear_fatent (mydata, curclust); +set_start_cluster (mydata, dentptr,0 ); +return 0 ; + } +debug ("curclust: 0x%x\n" , curclust); +debug ("Invalid FAT entry\n" ); +return -1 ; + } + +if (!curclust) { +assert (pos ==0 ); + goto set_clusters; + } + +/* go to cluster at pos */ + cur_pos = bytesperclust; +while (1 ) { +if (pos <= cur_pos) +break ; +if (IS_LAST_CLUST (curclust, mydata->fatsize)) +break ; + + newclust =get_fatent (mydata, curclust); +if (!IS_LAST_CLUST (newclust, mydata->fatsize) && +CHECK_CLUST (newclust, mydata->fatsize)) { +debug ("curclust: 0x%x\n" , curclust); +debug ("Invalid FAT entry\n" );return -1 ; } + + cur_pos += bytesperclust; + curclust = newclust; + } +if (IS_LAST_CLUST (curclust, mydata->fatsize)) { +assert (pos == cur_pos); + goto set_clusters; } - curclust =find_empty_cluster (mydata); -set_start_cluster (mydata, dentptr, curclust); +assert (pos < cur_pos); + cur_pos -= bytesperclust; +/* overwrite */ +assert (IS_LAST_CLUST (curclust, mydata->fatsize) || + !CHECK_CLUST (curclust, mydata->fatsize)); + +while (1 ) { +/* search for allocated consecutive clusters */ + actsize = bytesperclust; + endclust = curclust; +while (1 ) { +if (filesize <= (cur_pos + actsize)) +break ; + + newclust =get_fatent (mydata, endclust); + +if (IS_LAST_CLUST (newclust, mydata->fatsize)) +break ; +if (CHECK_CLUST (newclust, mydata->fatsize)) { +debug ("curclust: 0x%x\n" , curclust); +debug ("Invalid FAT entry\n" ); +return -1 ; + } + + actsize += bytesperclust; + endclust = newclust; + } + +/* overwrite to <curclust..endclust> */ +if (pos < cur_pos) + offset =0 ; +else + offset = pos - cur_pos; + wsize =min (cur_pos + actsize, filesize) - pos; +if (get_set_cluster (mydata, curclust, offset, buffer, wsize, + &actsize)) { +printf ("Error get-and-setting cluster\n" ); +return -1 ; + } + buffer += wsize; + *gotsize += wsize; + cur_pos += offset + wsize; + +if (filesize <= cur_pos) +break ; + +/* CHECK: newclust = get_fatent(mydata, endclust); */ + +if (IS_LAST_CLUST (newclust, mydata->fatsize)) +/* no more clusters */ +break ; + + curclust = newclust; + } + +if (filesize <= cur_pos) { +/* no more write */ + newclust =get_fatent (mydata, endclust); +if (!IS_LAST_CLUST (newclust, mydata->fatsize)) { +/* truncate the rest */ +clear_fatent (mydata, newclust); + +/* Mark end of file in FAT */ +if (mydata->fatsize ==12 ) + newclust =0xfff ; +else if (mydata->fatsize ==16 ) + newclust =0xffff ; +else if (mydata->fatsize ==32 ) + newclust =0xfffffff ; +set_fatent_value (mydata, endclust, newclust); + } + +return 0 ; + } + + curclust = endclust; + filesize -= cur_pos; +assert (!(cur_pos % bytesperclust)); + +set_clusters: +/* allocate and write */ +assert (!pos); + +/* Assure that curclust is valid */ +if (!curclust) { + curclust =find_empty_cluster (mydata); +set_start_cluster (mydata, dentptr, curclust); + }else { + newclust =get_fatent (mydata, curclust); + +if (IS_LAST_CLUST (newclust, mydata->fatsize)) { + newclust =determine_fatent (mydata, curclust); +set_fatent_value (mydata, curclust, newclust); + curclust = newclust; + }else { +debug ("error: something wrong\n" ); +return -1 ; + } + } + +/* TODO: already partially written */ if (check_overflow (mydata, curclust, filesize)) {printf ("Error: no space left: %llu\n" , filesize);return -1 ;@@ -852,6 +1098,16 @@ int file_fat_write_at(const char *filename, loff_t pos, void *buffer, goto exit; } +/* A file exists */ +if (pos ==-1 ) +/* Append to the end */ + pos =FAT2CPU32 (retdent->size); +if (pos > retdent->size) { +/* No hole allowed */ + ret = -EINVAL ; + goto exit; + } +/* Update file size in a directory entry */ retdent->size =cpu_to_le32 (pos + size); }else {@@ -872,6 +1128,12 @@ int file_fat_write_at(const char *filename, loff_t pos, void *buffer, goto exit; } +if (pos) { +/* No hole allowed */ + ret = -EINVAL ; + goto exit; + } +memset (itr->dent,0 ,sizeof (*itr->dent));/* Set short name to set alias checksum field in dir_slot */ @@ -921,10 +1183,5 @@ exit:int file_fat_write (const char *filename,void *buffer,loff_t offset,loff_t maxsize,loff_t *actwrite) { -if (offset !=0 ) { -printf ("Error: non zero offset is currently not supported.\n" ); -return -EINVAL ; - } -return file_fat_write_at (filename, offset, buffer, maxsize, actwrite); }
PATCH 9/17 fs: fat: support write with non-zero offset
Quoted 10 lines · Heinrich Schuchardt
Quoted 9 lines · AKASHI Takahiro
In this patch, all the necessary code for allowing for a file offset at write is implemented. What plays a major roll here is
get_set_cluster(), which, in contrast to its counterpart,set_cluster(), only operates on already-allocated clusters, overwriting with data.So, with a file offset specified,
set_contents()seeks and writes data withset_get_cluster()until the end of a file, and, once it reaches there, continues writing withset_cluster()for the rest.
Quoted 5 lines
Quoted 3 lines
Please note that a file will be trimmed as a result of write operation if write ends before reaching file's end. This is an intended behavior in order to maitain compatibility with the current interface.
This does not match the EFI spec.
First, please understand my standpoint that I mentioned in a reply to your comment on my cover letter.
Quoted 5 lines
Quoted 2 lines
Signed-off-by AKASHI Takahiro <[email protected]>When testing I observed that I could not write at an offset larger than the file size. This does not match the EFI spec:
So this is an intended behavior.
Quoted 3 lines
EFI_FILE_PROTOCOL.SetPosition():
seeking past the end of the file is allowed (a subsequent write would grow the file).
Surely, this is a discussion point.
Any comment from other folks?
-Takahiro AKASHI
Quoted 346 lines
Best regards
Heinrich
Quoted 340 lines
--- fs/fat/fat_write.c | 287 ++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 272 insertions(+), 15 deletions(-)fs/fat/fat_write.c +272
-15@@ -450,6 +450,120 @@ set_cluster(fsdata *mydata, __u32 clustnum, __u8 *buffer,return 0 ; } +static __u8 tmpbuf_cluster[MAX_CLUSTSIZE ]__aligned(ARCH_DMA_MINALIGN) ; + +/* +* Read and modify data on existing and consecutive cluster blocks +*/ +static int +get_set_cluster (fsdata *mydata,__u32 clustnum,loff_t pos,__u8 *buffer, +loff_t size,loff_t *gotsize) +{ +unsigned int bytesperclust = mydata->clust_size * mydata->sect_size; +__u32 startsect; +loff_t wsize; +int clustcount, i, ret; + + *gotsize =0 ; +if (!size) +return 0 ; + +assert (pos < bytesperclust); + startsect =clust_to_sect (mydata, clustnum); + +debug ("clustnum: %d, startsect: %d, pos: %lld\n" , clustnum, startsect, + pos); + +/* partial write at beginning */ +if (pos) { + wsize =min (bytesperclust - pos, size); + ret =disk_read (startsect, mydata->clust_size, tmpbuf_cluster); +if (ret != mydata->clust_size) { +debug ("Error reading data (got %d)\n" , ret); +return -1 ; + } + +memcpy (tmpbuf_cluster + pos, buffer, wsize); + ret =disk_write (startsect, mydata->clust_size, tmpbuf_cluster); +if (ret != mydata->clust_size) { +debug ("Error writing data (got %d)\n" , ret); +return -1 ; + } + + size -= wsize; + buffer += wsize; + *gotsize += wsize; + + startsect += mydata->clust_size; + +if (!size) +return 0 ; + } + +/* full-cluster write */ +if (size >= bytesperclust) { + clustcount =lldiv (size, bytesperclust); + +if (!((unsigned long )buffer & (ARCH_DMA_MINALIGN -1 ))) { + wsize = clustcount * bytesperclust; + ret =disk_write (startsect, + clustcount * mydata->clust_size, + buffer); +if (ret != clustcount * mydata->clust_size) { +debug ("Error writing data (got %d)\n" , ret); +return -1 ; + } + + size -= wsize; + buffer += wsize; + *gotsize += wsize; + + startsect += clustcount * mydata->clust_size; + }else { +for (i =0 ; i < clustcount; i++) { +memcpy (tmpbuf_cluster, buffer, bytesperclust); + ret =disk_write (startsect, mydata->clust_size, + tmpbuf_cluster); +if (ret != mydata->clust_size) { +debug ("Error writing data (got %d)\n" , + ret); +return -1 ; + } + + size -= bytesperclust; + buffer += bytesperclust; + *gotsize += bytesperclust; + + startsect += mydata->clust_size; + } + } + } + +/* partial write at end */ +if (size) { + wsize = size; + ret =disk_read (startsect, mydata->clust_size, tmpbuf_cluster); +if (ret != mydata->clust_size) { +debug ("Error reading data (got %d)\n" , ret); +return -1 ; + } +memcpy (tmpbuf_cluster, buffer, wsize); + ret =disk_write (startsect, mydata->clust_size, tmpbuf_cluster); +if (ret != mydata->clust_size) { +debug ("Error writing data (got %d)\n" , ret); +return -1 ; + } + + size -= wsize; + buffer += wsize; + *gotsize += wsize; + } + +assert (!size); + +return 0 ; +} +/* * Find the first empty cluster */ @@ -579,26 +693,158 @@ set_contents(fsdata *mydata, dir_entry *dentptr, loff_t pos, __u8 *buffer,unsigned int bytesperclust = mydata->clust_size * mydata->sect_size;__u32 curclust =START (dentptr);__u32 endclust =0 , newclust =0 ; -loff_t actsize; +loff_t cur_pos, offset, actsize, wsize; *gotsize =0 ; - filesize = maxsize; + filesize = pos + maxsize;debug ("%llu bytes\n" , filesize); -if (curclust) { -/* -* release already-allocated clusters anyway -*/ -if (clear_fatent (mydata, curclust)) { -printf ("Error: clearing FAT entries\n" ); +if (!filesize) { +if (!curclust) +return 0 ; +if (!CHECK_CLUST (curclust, mydata->fatsize) || +IS_LAST_CLUST (curclust, mydata->fatsize)) { +clear_fatent (mydata, curclust); +set_start_cluster (mydata, dentptr,0 ); +return 0 ; + } +debug ("curclust: 0x%x\n" , curclust); +debug ("Invalid FAT entry\n" ); +return -1 ; + } + +if (!curclust) { +assert (pos ==0 ); + goto set_clusters; + } + +/* go to cluster at pos */ + cur_pos = bytesperclust; +while (1 ) { +if (pos <= cur_pos) +break ; +if (IS_LAST_CLUST (curclust, mydata->fatsize)) +break ; + + newclust =get_fatent (mydata, curclust); +if (!IS_LAST_CLUST (newclust, mydata->fatsize) && +CHECK_CLUST (newclust, mydata->fatsize)) { +debug ("curclust: 0x%x\n" , curclust); +debug ("Invalid FAT entry\n" );return -1 ; } + + cur_pos += bytesperclust; + curclust = newclust; + } +if (IS_LAST_CLUST (curclust, mydata->fatsize)) { +assert (pos == cur_pos); + goto set_clusters; } - curclust =find_empty_cluster (mydata); -set_start_cluster (mydata, dentptr, curclust); +assert (pos < cur_pos); + cur_pos -= bytesperclust; +/* overwrite */ +assert (IS_LAST_CLUST (curclust, mydata->fatsize) || + !CHECK_CLUST (curclust, mydata->fatsize)); + +while (1 ) { +/* search for allocated consecutive clusters */ + actsize = bytesperclust; + endclust = curclust; +while (1 ) { +if (filesize <= (cur_pos + actsize)) +break ; + + newclust =get_fatent (mydata, endclust); + +if (IS_LAST_CLUST (newclust, mydata->fatsize)) +break ; +if (CHECK_CLUST (newclust, mydata->fatsize)) { +debug ("curclust: 0x%x\n" , curclust); +debug ("Invalid FAT entry\n" ); +return -1 ; + } + + actsize += bytesperclust; + endclust = newclust; + } + +/* overwrite to <curclust..endclust> */ +if (pos < cur_pos) + offset =0 ; +else + offset = pos - cur_pos; + wsize =min (cur_pos + actsize, filesize) - pos; +if (get_set_cluster (mydata, curclust, offset, buffer, wsize, + &actsize)) { +printf ("Error get-and-setting cluster\n" ); +return -1 ; + } + buffer += wsize; + *gotsize += wsize; + cur_pos += offset + wsize; + +if (filesize <= cur_pos) +break ; + +/* CHECK: newclust = get_fatent(mydata, endclust); */ + +if (IS_LAST_CLUST (newclust, mydata->fatsize)) +/* no more clusters */ +break ; + + curclust = newclust; + } + +if (filesize <= cur_pos) { +/* no more write */ + newclust =get_fatent (mydata, endclust); +if (!IS_LAST_CLUST (newclust, mydata->fatsize)) { +/* truncate the rest */ +clear_fatent (mydata, newclust); + +/* Mark end of file in FAT */ +if (mydata->fatsize ==12 ) + newclust =0xfff ; +else if (mydata->fatsize ==16 ) + newclust =0xffff ; +else if (mydata->fatsize ==32 ) + newclust =0xfffffff ; +set_fatent_value (mydata, endclust, newclust); + } + +return 0 ; + } + + curclust = endclust; + filesize -= cur_pos; +assert (!(cur_pos % bytesperclust)); + +set_clusters: +/* allocate and write */ +assert (!pos); + +/* Assure that curclust is valid */ +if (!curclust) { + curclust =find_empty_cluster (mydata); +set_start_cluster (mydata, dentptr, curclust); + }else { + newclust =get_fatent (mydata, curclust); + +if (IS_LAST_CLUST (newclust, mydata->fatsize)) { + newclust =determine_fatent (mydata, curclust); +set_fatent_value (mydata, curclust, newclust); + curclust = newclust; + }else { +debug ("error: something wrong\n" ); +return -1 ; + } + } + +/* TODO: already partially written */ if (check_overflow (mydata, curclust, filesize)) {printf ("Error: no space left: %llu\n" , filesize);return -1 ;@@ -852,6 +1098,16 @@ int file_fat_write_at(const char *filename, loff_t pos, void *buffer, goto exit; } +/* A file exists */ +if (pos ==-1 ) +/* Append to the end */ + pos =FAT2CPU32 (retdent->size); +if (pos > retdent->size) { +/* No hole allowed */ + ret = -EINVAL ; + goto exit; + } +/* Update file size in a directory entry */ retdent->size =cpu_to_le32 (pos + size); }else {@@ -872,6 +1128,12 @@ int file_fat_write_at(const char *filename, loff_t pos, void *buffer, goto exit; } +if (pos) { +/* No hole allowed */ + ret = -EINVAL ; + goto exit; + } +memset (itr->dent,0 ,sizeof (*itr->dent));/* Set short name to set alias checksum field in dir_slot */ @@ -921,10 +1183,5 @@ exit:int file_fat_write (const char *filename,void *buffer,loff_t offset,loff_t maxsize,loff_t *actwrite) { -if (offset !=0 ) { -printf ("Error: non zero offset is currently not supported.\n" ); -return -EINVAL ; - } -return file_fat_write_at (filename, offset, buffer, maxsize, actwrite); }
PATCH 10/17 cmd: fat: add offset parameter to fatwrite
In reply to AKASHI TakahiroIn this patch, fatwrite command is extended so as to accept an additional parameter of file offset.
--- cmd/fat.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-)
cmd/fat.c +6 -3
@@ -104,6 +104,7 @@ static int do_fat_fswrite(cmd_tbl_t *cmdtp, int flag,int ret;unsigned long addr;unsigned long count; +long offset;struct blk_desc *dev_desc =NULL ;disk_partition_t info;int dev =0 ;
@@ -126,9 +127,11 @@ static int do_fat_fswrite(cmd_tbl_t *cmdtp, int flag, } addr =simple_strtoul (argv[3 ],NULL ,16 ); count = (argc <=5 ) ?0 :simple_strtoul (argv[5 ],NULL ,16 ); +/* offset should be a hex, but "-1" is allowed */ + offset = (argc <=6 ) ?0 :simple_strtol (argv[6 ],NULL ,16 ); buf =map_sysmem (addr, count); - ret =file_fat_write (argv[4 ], buf,0 , count, &size); + ret =file_fat_write (argv[4 ], buf, offset, count, &size);unmap_sysmem (buf);if (ret <0 ) { printf("\n** Unable to write \"%s\" from %s %d:%d **\n",
@@ -142,9 +145,9 @@ static int do_fat_fswrite(cmd_tbl_t *cmdtp, int flag, }U_BOOT_CMD ( - fatwrite,6 ,0 , do_fat_fswrite, + fatwrite,7 ,0 , do_fat_fswrite,"write file into a dos filesystem" , -"<interface> <dev[:part]> <addr> <filename> [<bytes>]\n" +"<interface> <dev[:part]> <addr> <filename> [<bytes> [<offset>]]\n" " - write file 'filename' from the address 'addr' in RAM\n" " to 'dev' on 'interface'" );
Signature · 1 line
2.17.0
PATCH 11/17 fs: add mkdir interface
In reply to AKASHI Takahiro"mkdir" interface is added to file operations.
This is a preparatory change as mkdir support for FAT file system will be added in next patch.
--- fs/fs.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ include/fs.h | 10 ++++++++++ 2 files changed, 55 insertions(+)
fs/fs.c +45 -0
@@ -105,6 +105,11 @@ static inline int fs_opendir_unsupported(const char *filename,return -EACCES ; } +static inline int fs_mkdir_unsupported (const char *dirname) +{ +return -1 ; +} +struct fstype_info {int fstype;char *name;
@@ -142,6 +147,7 @@ struct fstype_info {int (*readdir)(struct fs_dir_stream *dirs,struct fs_dirent **dentp);/* see fs_closedir() */ void (*closedir)(struct fs_dir_stream *dirs); +int (*mkdir)(const char *dirname); };static struct fstype_info fstypes[] = {
@@ -165,6 +171,7 @@ static struct fstype_info fstypes[] = { .opendir = fat_opendir, .readdir = fat_readdir, .closedir = fat_closedir, + .mkdir = fs_mkdir_unsupported, },#endif #ifdef CONFIG_FS_EXT4
@@ -185,6 +192,7 @@ static struct fstype_info fstypes[] = {#endif .uuid = ext4fs_uuid, .opendir = fs_opendir_unsupported, + .mkdir = fs_mkdir_unsupported, },#endif #ifdef CONFIG_SANDBOX
@@ -201,6 +209,7 @@ static struct fstype_info fstypes[] = { .write = fs_write_sandbox, .uuid = fs_uuid_unsupported, .opendir = fs_opendir_unsupported, + .mkdir = fs_mkdir_unsupported, },#endif #ifdef CONFIG_CMD_UBIFS
@@ -217,6 +226,7 @@ static struct fstype_info fstypes[] = { .write = fs_write_unsupported, .uuid = fs_uuid_unsupported, .opendir = fs_opendir_unsupported, + .mkdir = fs_mkdir_unsupported, },#endif #ifdef CONFIG_FS_BTRFS
@@ -233,6 +243,7 @@ static struct fstype_info fstypes[] = { .write = fs_write_unsupported, .uuid = btrfs_uuid, .opendir = fs_opendir_unsupported, + .mkdir = fs_mkdir_unsupported, },#endif {
@@ -248,6 +259,7 @@ static struct fstype_info fstypes[] = { .write = fs_write_unsupported, .uuid = fs_uuid_unsupported, .opendir = fs_opendir_unsupported, + .mkdir = fs_mkdir_unsupported, }, };
@@ -498,6 +510,20 @@ void fs_closedir(struct fs_dir_stream *dirs) } +int fs_mkdir (const char *dirname) +{ +int ret; + +struct fstype_info *info =fs_get_info (fs_type); + + ret = info->mkdir (dirname); + + fs_type =FS_TYPE_ANY ; +fs_close (); + +return ret; +} +int do_size (cmd_tbl_t *cmdtp,int flag,int argc,char *const argv[],int fstype) {
@@ -700,3 +726,22 @@ int do_fs_type(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])return CMD_RET_SUCCESS ; } +int do_mkdir (cmd_tbl_t *cmdtp,int flag,int argc,char *const argv[], +int fstype) +{ +int ret; + +if (argc !=4 ) +return CMD_RET_USAGE ; + +if (fs_set_blk_dev (argv[1 ], argv[2 ], fstype)) +return 1 ; + + ret =fs_mkdir (argv[3 ]); +if (ret) { +printf ("** Unable to create a directory \"%s\" **\n" , argv[3 ]); +return 1 ; + } + +return 0 ; +}
include/fs.h +10 -0
@@ -155,6 +155,14 @@ struct fs_dirent *fs_readdir(struct fs_dir_stream *dirs);*/ void fs_closedir (struct fs_dir_stream *dirs); +/* +* fs_mkdir - Create a directory +* +* @filename: Name of directory to create +* @return 0 on success, -1 on error conditions +*/ +int fs_mkdir (const char *filename); +/* * Common implementation for various filesystem commands, optionally limited * to a specific filesystem type via the fstype parameter.
@@ -169,6 +177,8 @@ int file_exists(const char *dev_type, const char *dev_part, const char *file, int fstype);int do_save (cmd_tbl_t *cmdtp,int flag,int argc,char *const argv[],int fstype); +int do_mkdir (cmd_tbl_t *cmdtp,int flag,int argc,char *const argv[], +int fstype);/* * Determine the UUID of the specified filesystem and print it. Optionally it is
Signature · 1 line
2.17.0
PATCH 11/17 fs: add mkdir interface
Quoted 35 lines · AKASHI Takahiro
"mkdir" interface is added to file operations.
This is a preparatory change as mkdir support for FAT file system will be added in next patch.Signed-off-by AKASHI Takahiro <[email protected]>--- fs/fs.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ include/fs.h | 10 ++++++++++ 2 files changed, 55 insertions(+)fs/fs.c +6
-0@@ -105,6 +105,11 @@ static inline int fs_opendir_unsupported(const char *filename,return -EACCES ; } +static inline int fs_mkdir_unsupported (const char *dirname) +{ +return -1 ; +} +struct fstype_info {int fstype;char *name;@@ -142,6 +147,7 @@ struct fstype_info {int (*readdir)(struct fs_dir_stream *dirs,struct fs_dirent **dentp);/* see fs_closedir() */ void (*closedir)(struct fs_dir_stream *dirs); +int (*mkdir)(const char *dirname); };static struct fstype_info fstypes[] = {
fs/fs.c static struct fstype_info fstypes[] = { · line 174
Quoted 4 lines
fs/fs.c +1
-0@@ -165,6 +171,7 @@ static struct fstype_info fstypes[] = { .opendir = fat_opendir, .readdir = fat_readdir, .closedir = fat_closedir, + .mkdir = fs_mkdir_unsupported,
Why should we create a dummy function? Just use NULL as an indicator that the interface method is not implemented. See the use of structures for the driver model.
@Simon
The array fstypes[] should be replaced by a linker list to match the driver model.
Quoted 44 lines
fs/fs.c +5
-0},#endif #ifdef CONFIG_FS_EXT4 @@ -185,6 +192,7 @@ static struct fstype_info fstypes[] = {#endif .uuid = ext4fs_uuid, .opendir = fs_opendir_unsupported, + .mkdir = fs_mkdir_unsupported, },#endif #ifdef CONFIG_SANDBOX @@ -201,6 +209,7 @@ static struct fstype_info fstypes[] = { .write = fs_write_sandbox, .uuid = fs_uuid_unsupported, .opendir = fs_opendir_unsupported, + .mkdir = fs_mkdir_unsupported, },#endif #ifdef CONFIG_CMD_UBIFS @@ -217,6 +226,7 @@ static struct fstype_info fstypes[] = { .write = fs_write_unsupported, .uuid = fs_uuid_unsupported, .opendir = fs_opendir_unsupported, + .mkdir = fs_mkdir_unsupported, },#endif #ifdef CONFIG_FS_BTRFS @@ -233,6 +243,7 @@ static struct fstype_info fstypes[] = { .write = fs_write_unsupported, .uuid = btrfs_uuid, .opendir = fs_opendir_unsupported, + .mkdir = fs_mkdir_unsupported, },#endif {@@ -248,6 +259,7 @@ static struct fstype_info fstypes[] = { .write = fs_write_unsupported, .uuid = fs_uuid_unsupported, .opendir = fs_opendir_unsupported, + .mkdir = fs_mkdir_unsupported, }, };
fs/fs.c void fs_closedir(struct fs_dir_stream *dirs) · line 519
Quoted 10 lines
fs/fs.c +7
-0@@ -498,6 +510,20 @@ void fs_closedir(struct fs_dir_stream *dirs) } +int fs_mkdir (const char *dirname) +{ +int ret; + +struct fstype_info *info =fs_get_info (fs_type); + + ret = info->mkdir (dirname);
Please, check if mkdir is NULL before calling.
fs/fs.c void fs_closedir(struct fs_dir_stream *dirs) · line 522
Quoted 3 lines
fs/fs.c +3
-0+ + fs_type =FS_TYPE_ANY ; +fs_close ();
What do you want to close here if mkdir() is not implemented by the file system?
Best regards
Heinrich
Quoted 59 lines
fs/fs.c +23
-0+ +return ret; +} +int do_size (cmd_tbl_t *cmdtp,int flag,int argc,char *const argv[],int fstype) {@@ -700,3 +726,22 @@ int do_fs_type(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])return CMD_RET_SUCCESS ; } +int do_mkdir (cmd_tbl_t *cmdtp,int flag,int argc,char *const argv[], +int fstype) +{ +int ret; + +if (argc !=4 ) +return CMD_RET_USAGE ; + +if (fs_set_blk_dev (argv[1 ], argv[2 ], fstype)) +return 1 ; + + ret =fs_mkdir (argv[3 ]); +if (ret) { +printf ("** Unable to create a directory \"%s\" **\n" , argv[3 ]); +return 1 ; + } + +return 0 ; +}include/fs.h +10
-0@@ -155,6 +155,14 @@ struct fs_dirent *fs_readdir(struct fs_dir_stream *dirs);*/ void fs_closedir (struct fs_dir_stream *dirs); +/* +* fs_mkdir - Create a directory +* +* @filename: Name of directory to create +* @return 0 on success, -1 on error conditions +*/ +int fs_mkdir (const char *filename); +/* * Common implementation for various filesystem commands, optionally limited * to a specific filesystem type via the fstype parameter. @@ -169,6 +177,8 @@ int file_exists(const char *dev_type, const char *dev_part, const char *file, int fstype);int do_save (cmd_tbl_t *cmdtp,int flag,int argc,char *const argv[],int fstype); +int do_mkdir (cmd_tbl_t *cmdtp,int flag,int argc,char *const argv[], +int fstype);/* * Determine the UUID of the specified filesystem and print it. Optionally it is
PATCH 11/17 fs: add mkdir interface
Hi,
Quoted 11 lines · Heinrich Schuchardt
Quoted 10 lines · AKASHI Takahiro
"mkdir" interface is added to file operations.
This is a preparatory change as mkdir support for FAT file system will be added in next patch.Signed-off-by AKASHI Takahiro <[email protected]>--- fs/fs.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ include/fs.h | 10 ++++++++++ 2 files changed, 55 insertions(+)
We need to get a proper fs test in place before we add any more stuff.
Does someone waent to try converting fs-test.sh to pytest in test/py/tests ?
Regards,
Simon
PATCH 11/17 fs: add mkdir interface
Quoted 8 lines · Simon Glass
Hi,
Quoted 5 lines · Heinrich Schuchardt
Quoted 4 lines · AKASHI Takahiro
"mkdir" interface is added to file operations.
This is a preparatory change as mkdir support for FAT file system will be added in next patch.
Quoted 8 lines
Quoted 6 lines
Quoted 6 lines
Signed-off-by AKASHI Takahiro <[email protected]>--- fs/fs.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ include/fs.h | 10 ++++++++++ 2 files changed, 55 insertions(+)We need to get a proper fs test in place before we add any more stuff.
Agreed that we need more tests as part of this series.
Quoted 1 line
Does someone waent to try converting
fs-test.shto pytest in test/py/tests ?
I thought there was at least a first pass at that?
Signature · 8 lines
Tom -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: not available URL: <http://lists.denx.de/pipermail/u-boot/attachments/20180723/4918f93a/attachment.sig>
PATCH 11/17 fs: add mkdir interface
Quoted 16 lines · Tom Rini
Quoted 15 lines · Simon Glass
Hi,
Quoted 11 lines · Heinrich Schuchardt
Quoted 10 lines · AKASHI Takahiro
"mkdir" interface is added to file operations.
This is a preparatory change as mkdir support for FAT file system will be added in next patch.Signed-off-by AKASHI Takahiro <[email protected]>--- fs/fs.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ include/fs.h | 10 ++++++++++ 2 files changed, 55 insertions(+)
Quoted 3 lines
Quoted 1 line
We need to get a proper fs test in place before we add any more stuff.
Agreed that we need more tests as part of this series.
Is this a new standard rule for new features?
Just kidding, but testing was definitely one of my concerns partly because fs-test.sh is anyhow in an old fashion and partly because I can't find any criteria for test coverage:
- white-box test or black-box test
- coverage for corner (or edge) cases
- some sort of stress test, etc.
Quoted 3 lines
Quoted 1 line
Does someone waent to try converting
fs-test.shto pytest in test/py/tests ?I thought there was at least a first pass at that?
Well, I don't see any file system related scripts under test/py/tests.
Please advise me.
Thanks,
-Takahiro AKASHI
Quoted 2 lines
Signature · 1 line
Tom
PATCH 11/17 fs: add mkdir interface
Hi,
Quoted 29 lines · AKASHI Takahiro
Quoted 16 lines · Tom Rini
Quoted 15 lines · Simon Glass
Hi,
Quoted 11 lines · Heinrich Schuchardt
Quoted 10 lines · AKASHI Takahiro
"mkdir" interface is added to file operations.
This is a preparatory change as mkdir support for FAT file system will be added in next patch.Signed-off-by AKASHI Takahiro <[email protected]>--- fs/fs.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ include/fs.h | 10 ++++++++++ 2 files changed, 55 insertions(+)Quoted 3 lines
Quoted 1 line
We need to get a proper fs test in place before we add any more stuff.
Agreed that we need more tests as part of this series.
Is this a new standard rule for new features?
Just kidding, but testing was definitely one of my concerns partly becausefs-test.shis anyhow in an old fashion and partly because I can't find any criteria for test coverage:
- white-box test or black-box test
- coverage for corner (or edge) cases
- some sort of stress test, etc.
Quoted 7 lines
Quoted 3 lines
Quoted 1 line
Does someone waent to try converting
fs-test.shto pytest in test/py/tests ?I thought there was at least a first pass at that?
Well, I don't see any file system related scripts under test/py/tests.
Please advise me.
It should be possible to translate it from shell to Python without too much trouble if you able able to give it a crack. See for example:
8729d58259 test: Convert the vboot test to test/py
Re testing in general, my view is:
- Unit tests / smaller tests are better than large ones
- We don't need stress tests for functionality (e.g. the current FS test uses filesystems that are quite large, and I think they could just be very very small and still get good test coverage and run faster)
- Corner cases are an important part of tests (and easy to test with unit tests)
- Use the pytest framework
One day we'll enable code coverage for U-Boot sandbox and get a feel for the missing test coverage.
Regards,
Simon
PATCH 11/17 fs: add mkdir interface
In reply to Heinrich SchuchardtQuoted 34 lines · Heinrich Schuchardt
Quoted 33 lines · AKASHI Takahiro
"mkdir" interface is added to file operations.
This is a preparatory change as mkdir support for FAT file system will be added in next patch.Signed-off-by AKASHI Takahiro <[email protected]>--- fs/fs.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ include/fs.h | 10 ++++++++++ 2 files changed, 55 insertions(+)fs/fs.c +6
-0@@ -105,6 +105,11 @@ static inline int fs_opendir_unsupported(const char *filename,return -EACCES ; } +static inline int fs_mkdir_unsupported (const char *dirname) +{ +return -1 ; +} +struct fstype_info {int fstype;char *name;@@ -142,6 +147,7 @@ struct fstype_info {int (*readdir)(struct fs_dir_stream *dirs,struct fs_dirent **dentp);/* see fs_closedir() */ void (*closedir)(struct fs_dir_stream *dirs); +int (*mkdir)(const char *dirname); };
Quoted 8 lines
fs/fs.c static struct fstype_info fstypes[] = { · line 174
Quoted 6 lines
fs/fs.c +1
-0static struct fstype_info fstypes[] = {@@ -165,6 +171,7 @@ static struct fstype_info fstypes[] = { .opendir = fat_opendir, .readdir = fat_readdir, .closedir = fat_closedir, + .mkdir = fs_mkdir_unsupported,Why should we create a dummy function? Just use NULL as an indicator
because I followed coding style of the existing code here.
Quoted 2 lines
that the interface method is not implemented. See the use of structures for the driver model.
Can any file system ever be based on driver model?
Quoted 51 lines
@Simon
The array fstypes[] should be replaced by a linker list to match the driver model.Quoted 47 lines
fs/fs.c +5
-0},#endif #ifdef CONFIG_FS_EXT4 @@ -185,6 +192,7 @@ static struct fstype_info fstypes[] = {#endif .uuid = ext4fs_uuid, .opendir = fs_opendir_unsupported, + .mkdir = fs_mkdir_unsupported, },#endif #ifdef CONFIG_SANDBOX @@ -201,6 +209,7 @@ static struct fstype_info fstypes[] = { .write = fs_write_sandbox, .uuid = fs_uuid_unsupported, .opendir = fs_opendir_unsupported, + .mkdir = fs_mkdir_unsupported, },#endif #ifdef CONFIG_CMD_UBIFS @@ -217,6 +226,7 @@ static struct fstype_info fstypes[] = { .write = fs_write_unsupported, .uuid = fs_uuid_unsupported, .opendir = fs_opendir_unsupported, + .mkdir = fs_mkdir_unsupported, },#endif #ifdef CONFIG_FS_BTRFS @@ -233,6 +243,7 @@ static struct fstype_info fstypes[] = { .write = fs_write_unsupported, .uuid = btrfs_uuid, .opendir = fs_opendir_unsupported, + .mkdir = fs_mkdir_unsupported, },#endif {@@ -248,6 +259,7 @@ static struct fstype_info fstypes[] = { .write = fs_write_unsupported, .uuid = fs_uuid_unsupported, .opendir = fs_opendir_unsupported, + .mkdir = fs_mkdir_unsupported, }, };@@ -498,6 +510,20 @@ void fs_closedir(struct fs_dir_stream *dirs) }
Quoted 9 lines
fs/fs.c void fs_closedir(struct fs_dir_stream *dirs) · line 519
Quoted 7 lines
fs/fs.c +7
-0+int fs_mkdir (const char *dirname) +{ +int ret; + +struct fstype_info *info =fs_get_info (fs_type); + + ret = info->mkdir (dirname);Please, check if mkdir is NULL before calling.
No other place checks for NULL. Is this really required?
Quoted 6 lines
fs/fs.c void fs_closedir(struct fs_dir_stream *dirs) · line 522
Quoted 3 lines
fs/fs.c +3
-0+ + fs_type =FS_TYPE_ANY ; +fs_close ();What do you want to close here if
mkdir()is not implemented by the file system?
I'm not quite confident here but ->close() be paired with ->probe(), which is set to be called in fs_set_blk_dev().
Thanks,
-Takahiro AKASHI
Quoted 64 lines
Best regards
Heinrich
Quoted 59 lines
fs/fs.c +23
-0+ +return ret; +} +int do_size (cmd_tbl_t *cmdtp,int flag,int argc,char *const argv[],int fstype) {@@ -700,3 +726,22 @@ int do_fs_type(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])return CMD_RET_SUCCESS ; } +int do_mkdir (cmd_tbl_t *cmdtp,int flag,int argc,char *const argv[], +int fstype) +{ +int ret; + +if (argc !=4 ) +return CMD_RET_USAGE ; + +if (fs_set_blk_dev (argv[1 ], argv[2 ], fstype)) +return 1 ; + + ret =fs_mkdir (argv[3 ]); +if (ret) { +printf ("** Unable to create a directory \"%s\" **\n" , argv[3 ]); +return 1 ; + } + +return 0 ; +}include/fs.h +10
-0@@ -155,6 +155,14 @@ struct fs_dirent *fs_readdir(struct fs_dir_stream *dirs);*/ void fs_closedir (struct fs_dir_stream *dirs); +/* +* fs_mkdir - Create a directory +* +* @filename: Name of directory to create +* @return 0 on success, -1 on error conditions +*/ +int fs_mkdir (const char *filename); +/* * Common implementation for various filesystem commands, optionally limited * to a specific filesystem type via the fstype parameter. @@ -169,6 +177,8 @@ int file_exists(const char *dev_type, const char *dev_part, const char *file, int fstype);int do_save (cmd_tbl_t *cmdtp,int flag,int argc,char *const argv[],int fstype); +int do_mkdir (cmd_tbl_t *cmdtp,int flag,int argc,char *const argv[], +int fstype);/* * Determine the UUID of the specified filesystem and print it. Optionally it is
PATCH 12/17 fs: fat: remember the starting cluster number of directory
In reply to AKASHI TakahiroThe starting cluster number of directory is needed to initialize ".." (parent directory) entry when creating a new directory.
--- fs/fat/fat.c | 2 ++ include/fat.h | 1 + 2 files changed, 3 insertions(+)
fs/fat/fat.c +2 -0
@@ -639,6 +639,7 @@ int fat_itr_root(fat_itr *itr, fsdata *fsdata)return -ENXIO ; itr->fsdata = fsdata; + itr->start_clust =0 ; itr->clust = fsdata->root_cluster; itr->next_clust = fsdata->root_cluster; itr->dent =NULL ;
@@ -674,6 +675,7 @@ void fat_itr_child(fat_itr *itr, fat_itr *parent)assert (fat_itr_isdir (parent)); itr->fsdata = parent->fsdata; + itr->start_clust = clustnum;if (clustnum >0 ) { itr->clust = clustnum; itr->next_clust = clustnum;
include/fat.h +1 -0
@@ -197,6 +197,7 @@ static inline u32 sect_to_clust(fsdata *fsdata, int sect) typedef struct { fsdata *fsdata; /* filesystem parameters */ + unsigned start_clust; /* first cluster */ unsigned clust; /* current cluster */ unsigned next_clust; /* next cluster if remaining == 0 */ int last_cluster; /* set once we've read last cluster */
Signature · 1 line
2.17.0
PATCH 13/17 fs: fat: support mkdir
In reply to AKASHI TakahiroIn this patch, mkdir support is added to FAT file system. A newly created directory contains only "." and ".." entries.
--- fs/fat/fat_write.c | 138 +++++++++++++++++++++++++++++++++++++++++++++ fs/fs.c | 3 +- include/fat.h | 1 + 3 files changed, 141 insertions(+), 1 deletion(-)
fs/fat/fat_write.c +138 -0
@@ -1185,3 +1185,141 @@ int file_fat_write(const char *filename, void *buffer, loff_t offset, {return file_fat_write_at (filename, offset, buffer, maxsize, actwrite); } + +int fat_mkdir (const char *new_dirname) +{ +dir_entry *retdent; +fsdata datablock = { .fatbuf =NULL , }; +fsdata *mydata = &datablock; +fat_itr *itr =NULL ; +char *dirname_copy, *parent, *dirname; +char l_dirname[VFAT_MAXLEN_BYTES ]; +int ret =-1 ; +loff_t actwrite; +unsigned int bytesperclust; +dir_entry *dotdent =NULL ; + + dirname_copy =strdup (new_dirname); +if (!dirname_copy) + goto exit; + +split_filename (dirname_copy, &parent, &dirname); +if (!strlen (dirname)) { + ret = -EINVAL ; + goto exit; + } + +if (normalize_longname (l_dirname, dirname)) { +printf ("FAT: illegal filename (%s)\n" , dirname); + ret = -EINVAL ; + goto exit; + } + + itr =malloc_cache_aligned (sizeof (fat_itr)); +if (!itr) { + ret = -ENOMEM ; + goto exit; + } + + ret =fat_itr_root (itr, &datablock); +if (ret) + goto exit; + + total_sector = datablock.bs_total_sect; +if (total_sector ==0 ) + total_sector = (int )cur_part_info.size;/* cast of lbaint_t */ + + ret =fat_itr_resolve (itr, parent,TYPE_DIR ); +if (ret) { +printf ("%s: doesn't exist (%d)\n" , parent, ret); + goto exit; + } + + retdent =find_directory_entry (itr, l_dirname); + +if (retdent) { +printf ("%s: already exists\n" , l_dirname); + ret = -EEXIST ; + goto exit; + }else { +if (itr->is_root) { +/* root dir cannot have "." or ".." */ +if (!strcmp (l_dirname,"." ) || + !strcmp (l_dirname,".." )) { + ret = -EINVAL ; + goto exit; + } + } + +if (!itr->dent) { +printf ("Error: allocating new dir entry\n" ); + ret = -EIO ; + goto exit; + } + +memset (itr->dent,0 ,sizeof (*itr->dent)); + +/* Set short name to set alias checksum field in dir_slot */ +set_name (itr->dent, dirname); +fill_dir_slot (itr, dirname); + +/* Set attribute as archieve for regular file */ +fill_dentry (itr->fsdata, itr->dent, dirname,0 ,0 , +ATTR_DIR |ATTR_ARCH ); + + retdent = itr->dent; + } + +/* Default entries */ + bytesperclust = mydata->clust_size * mydata->sect_size; + dotdent =malloc_cache_aligned (bytesperclust); +if (!dotdent) { + ret = -ENOMEM ; + goto exit; + } +memset (dotdent,0 , bytesperclust); + +memcpy (dotdent[0 ].name,". " ,8 ); +memcpy (dotdent[0 ].ext," " ,3 ); + dotdent[0 ].attr =ATTR_DIR |ATTR_ARCH ; + +memcpy (dotdent[1 ].name,".. " ,8 ); +memcpy (dotdent[1 ].ext," " ,3 ); + dotdent[1 ].attr =ATTR_DIR |ATTR_ARCH ; +set_start_cluster (mydata, &dotdent[1 ], itr->start_clust); + + ret =set_contents (mydata, retdent,0 , (__u8 *)dotdent, bytesperclust, + &actwrite); +if (ret <0 ) { +printf ("Error: writing contents\n" ); + goto exit; + } +/* Write twice for "." */ +set_start_cluster (mydata, &dotdent[0 ],START (retdent)); + ret =set_contents (mydata, retdent,0 , (__u8 *)dotdent, bytesperclust, + &actwrite); +if (ret <0 ) { +printf ("Error: writing contents\n" ); + goto exit; + } + +/* Flush fat buffer */ + ret =flush_dirty_fat_buffer (mydata); +if (ret) { +printf ("Error: flush fat buffer\n" ); + goto exit; + } + +/* Write directory table to device */ + ret =set_cluster (mydata, itr->clust, itr->block, + mydata->clust_size * mydata->sect_size); +if (ret) +printf ("Error: writing directory entry\n" ); + +exit: +free (dirname_copy); +free (mydata->fatbuf); +free (itr); +free (dotdent); +return ret; +}
fs/fs.c +2 -1
@@ -164,14 +164,15 @@ static struct fstype_info fstypes[] = { .read = fat_read_file, #ifdef CONFIG_FAT_WRITE .write = file_fat_write, + .mkdir = fat_mkdir, #else .write = fs_write_unsupported, + .mkdir = fs_mkdir_unsupported, #endif .uuid = fs_uuid_unsupported, .opendir = fat_opendir, .readdir = fat_readdir, .closedir = fat_closedir, - .mkdir = fs_mkdir_unsupported, }, #endif #ifdef CONFIG_FS_EXT4
include/fat.h +1 -0
@@ -237,5 +237,6 @@ int fat_read_file(const char *filename, void *buf, loff_t offset, loff_t len,int fat_opendir (const char *filename,struct fs_dir_stream **dirsp);int fat_readdir (struct fs_dir_stream *dirs,struct fs_dirent **dentp);void fat_closedir (struct fs_dir_stream *dirs); +int fat_mkdir (const char *dirname);void fat_close (void );#endif /* _FAT_H_ */
Signature · 1 line
2.17.0
PATCH 13/17 fs: fat: support mkdir
Quoted 4 lines · AKASHI Takahiro
In this patch, mkdir support is added to FAT file system. A newly created directory contains only "." and ".." entries.
Signed-off-by AKASHI Takahiro <[email protected]>
The patch does set the creation date of the directory according to the real time clock but to 1980-01-01T00:00:00Z.
$ ls /mnt/dir1/ -la --full-time drwxr-xr-x 2 root root 2048 1980-01-01 01:00:00.000000000 +0100 dir3
Please, set the time correctly if the real time clock is available.
Best regards
Heinrich
Quoted 185 lines
--- fs/fat/fat_write.c | 138 +++++++++++++++++++++++++++++++++++++++++++++ fs/fs.c | 3 +- include/fat.h | 1 + 3 files changed, 141 insertions(+), 1 deletion(-)fs/fat/fat_write.c +138
-0@@ -1185,3 +1185,141 @@ int file_fat_write(const char *filename, void *buffer, loff_t offset, {return file_fat_write_at (filename, offset, buffer, maxsize, actwrite); } + +int fat_mkdir (const char *new_dirname) +{ +dir_entry *retdent; +fsdata datablock = { .fatbuf =NULL , }; +fsdata *mydata = &datablock; +fat_itr *itr =NULL ; +char *dirname_copy, *parent, *dirname; +char l_dirname[VFAT_MAXLEN_BYTES ]; +int ret =-1 ; +loff_t actwrite; +unsigned int bytesperclust; +dir_entry *dotdent =NULL ; + + dirname_copy =strdup (new_dirname); +if (!dirname_copy) + goto exit; + +split_filename (dirname_copy, &parent, &dirname); +if (!strlen (dirname)) { + ret = -EINVAL ; + goto exit; + } + +if (normalize_longname (l_dirname, dirname)) { +printf ("FAT: illegal filename (%s)\n" , dirname); + ret = -EINVAL ; + goto exit; + } + + itr =malloc_cache_aligned (sizeof (fat_itr)); +if (!itr) { + ret = -ENOMEM ; + goto exit; + } + + ret =fat_itr_root (itr, &datablock); +if (ret) + goto exit; + + total_sector = datablock.bs_total_sect; +if (total_sector ==0 ) + total_sector = (int )cur_part_info.size;/* cast of lbaint_t */ + + ret =fat_itr_resolve (itr, parent,TYPE_DIR ); +if (ret) { +printf ("%s: doesn't exist (%d)\n" , parent, ret); + goto exit; + } + + retdent =find_directory_entry (itr, l_dirname); + +if (retdent) { +printf ("%s: already exists\n" , l_dirname); + ret = -EEXIST ; + goto exit; + }else { +if (itr->is_root) { +/* root dir cannot have "." or ".." */ +if (!strcmp (l_dirname,"." ) || + !strcmp (l_dirname,".." )) { + ret = -EINVAL ; + goto exit; + } + } + +if (!itr->dent) { +printf ("Error: allocating new dir entry\n" ); + ret = -EIO ; + goto exit; + } + +memset (itr->dent,0 ,sizeof (*itr->dent)); + +/* Set short name to set alias checksum field in dir_slot */ +set_name (itr->dent, dirname); +fill_dir_slot (itr, dirname); + +/* Set attribute as archieve for regular file */ +fill_dentry (itr->fsdata, itr->dent, dirname,0 ,0 , +ATTR_DIR |ATTR_ARCH ); + + retdent = itr->dent; + } + +/* Default entries */ + bytesperclust = mydata->clust_size * mydata->sect_size; + dotdent =malloc_cache_aligned (bytesperclust); +if (!dotdent) { + ret = -ENOMEM ; + goto exit; + } +memset (dotdent,0 , bytesperclust); + +memcpy (dotdent[0 ].name,". " ,8 ); +memcpy (dotdent[0 ].ext," " ,3 ); + dotdent[0 ].attr =ATTR_DIR |ATTR_ARCH ; + +memcpy (dotdent[1 ].name,".. " ,8 ); +memcpy (dotdent[1 ].ext," " ,3 ); + dotdent[1 ].attr =ATTR_DIR |ATTR_ARCH ; +set_start_cluster (mydata, &dotdent[1 ], itr->start_clust); + + ret =set_contents (mydata, retdent,0 , (__u8 *)dotdent, bytesperclust, + &actwrite); +if (ret <0 ) { +printf ("Error: writing contents\n" ); + goto exit; + } +/* Write twice for "." */ +set_start_cluster (mydata, &dotdent[0 ],START (retdent)); + ret =set_contents (mydata, retdent,0 , (__u8 *)dotdent, bytesperclust, + &actwrite); +if (ret <0 ) { +printf ("Error: writing contents\n" ); + goto exit; + } + +/* Flush fat buffer */ + ret =flush_dirty_fat_buffer (mydata); +if (ret) { +printf ("Error: flush fat buffer\n" ); + goto exit; + } + +/* Write directory table to device */ + ret =set_cluster (mydata, itr->clust, itr->block, + mydata->clust_size * mydata->sect_size); +if (ret) +printf ("Error: writing directory entry\n" ); + +exit: +free (dirname_copy); +free (mydata->fatbuf); +free (itr); +free (dotdent); +return ret; +}fs/fs.c +2
-1@@ -164,14 +164,15 @@ static struct fstype_info fstypes[] = { .read = fat_read_file, #ifdef CONFIG_FAT_WRITE .write = file_fat_write, + .mkdir = fat_mkdir, #else .write = fs_write_unsupported, + .mkdir = fs_mkdir_unsupported, #endif .uuid = fs_uuid_unsupported, .opendir = fat_opendir, .readdir = fat_readdir, .closedir = fat_closedir, - .mkdir = fs_mkdir_unsupported, }, #endif #ifdef CONFIG_FS_EXT4include/fat.h +1
-0@@ -237,5 +237,6 @@ int fat_read_file(const char *filename, void *buf, loff_t offset, loff_t len,int fat_opendir (const char *filename,struct fs_dir_stream **dirsp);int fat_readdir (struct fs_dir_stream *dirs,struct fs_dirent **dentp);void fat_closedir (struct fs_dir_stream *dirs); +int fat_mkdir (const char *dirname);void fat_close (void );#endif /* _FAT_H_ */
PATCH 13/17 fs: fat: support mkdir
Quoted 6 lines · Heinrich Schuchardt
Quoted 4 lines · AKASHI Takahiro
In this patch, mkdir support is added to FAT file system. A newly created directory contains only "." and ".." entries.
Signed-off-by AKASHI Takahiro <[email protected]>
Quoted 7 lines
The patch does set the creation date of the directory according to the real time clock but to 1980-01-01T00:00:00Z.
$ ls /mnt/dir1/ -la --full-time drwxr-xr-x 2 root root 2048 1980-01-01 01:00:00.000000000 +0100 dir3Please, set the time correctly if the real time clock is available.
Good point, but I'd like to put this issue into future TODO list as it will end up introducing a new API, such as gettimeofday()?
(and this is not a FAT-specific issue.)
Thanks,
-Takahiro AKASHI
Quoted 190 lines
Best regards
Heinrich
Quoted 185 lines
--- fs/fat/fat_write.c | 138 +++++++++++++++++++++++++++++++++++++++++++++ fs/fs.c | 3 +- include/fat.h | 1 + 3 files changed, 141 insertions(+), 1 deletion(-)fs/fat/fat_write.c +138
-0@@ -1185,3 +1185,141 @@ int file_fat_write(const char *filename, void *buffer, loff_t offset, {return file_fat_write_at (filename, offset, buffer, maxsize, actwrite); } + +int fat_mkdir (const char *new_dirname) +{ +dir_entry *retdent; +fsdata datablock = { .fatbuf =NULL , }; +fsdata *mydata = &datablock; +fat_itr *itr =NULL ; +char *dirname_copy, *parent, *dirname; +char l_dirname[VFAT_MAXLEN_BYTES ]; +int ret =-1 ; +loff_t actwrite; +unsigned int bytesperclust; +dir_entry *dotdent =NULL ; + + dirname_copy =strdup (new_dirname); +if (!dirname_copy) + goto exit; + +split_filename (dirname_copy, &parent, &dirname); +if (!strlen (dirname)) { + ret = -EINVAL ; + goto exit; + } + +if (normalize_longname (l_dirname, dirname)) { +printf ("FAT: illegal filename (%s)\n" , dirname); + ret = -EINVAL ; + goto exit; + } + + itr =malloc_cache_aligned (sizeof (fat_itr)); +if (!itr) { + ret = -ENOMEM ; + goto exit; + } + + ret =fat_itr_root (itr, &datablock); +if (ret) + goto exit; + + total_sector = datablock.bs_total_sect; +if (total_sector ==0 ) + total_sector = (int )cur_part_info.size;/* cast of lbaint_t */ + + ret =fat_itr_resolve (itr, parent,TYPE_DIR ); +if (ret) { +printf ("%s: doesn't exist (%d)\n" , parent, ret); + goto exit; + } + + retdent =find_directory_entry (itr, l_dirname); + +if (retdent) { +printf ("%s: already exists\n" , l_dirname); + ret = -EEXIST ; + goto exit; + }else { +if (itr->is_root) { +/* root dir cannot have "." or ".." */ +if (!strcmp (l_dirname,"." ) || + !strcmp (l_dirname,".." )) { + ret = -EINVAL ; + goto exit; + } + } + +if (!itr->dent) { +printf ("Error: allocating new dir entry\n" ); + ret = -EIO ; + goto exit; + } + +memset (itr->dent,0 ,sizeof (*itr->dent)); + +/* Set short name to set alias checksum field in dir_slot */ +set_name (itr->dent, dirname); +fill_dir_slot (itr, dirname); + +/* Set attribute as archieve for regular file */ +fill_dentry (itr->fsdata, itr->dent, dirname,0 ,0 , +ATTR_DIR |ATTR_ARCH ); + + retdent = itr->dent; + } + +/* Default entries */ + bytesperclust = mydata->clust_size * mydata->sect_size; + dotdent =malloc_cache_aligned (bytesperclust); +if (!dotdent) { + ret = -ENOMEM ; + goto exit; + } +memset (dotdent,0 , bytesperclust); + +memcpy (dotdent[0 ].name,". " ,8 ); +memcpy (dotdent[0 ].ext," " ,3 ); + dotdent[0 ].attr =ATTR_DIR |ATTR_ARCH ; + +memcpy (dotdent[1 ].name,".. " ,8 ); +memcpy (dotdent[1 ].ext," " ,3 ); + dotdent[1 ].attr =ATTR_DIR |ATTR_ARCH ; +set_start_cluster (mydata, &dotdent[1 ], itr->start_clust); + + ret =set_contents (mydata, retdent,0 , (__u8 *)dotdent, bytesperclust, + &actwrite); +if (ret <0 ) { +printf ("Error: writing contents\n" ); + goto exit; + } +/* Write twice for "." */ +set_start_cluster (mydata, &dotdent[0 ],START (retdent)); + ret =set_contents (mydata, retdent,0 , (__u8 *)dotdent, bytesperclust, + &actwrite); +if (ret <0 ) { +printf ("Error: writing contents\n" ); + goto exit; + } + +/* Flush fat buffer */ + ret =flush_dirty_fat_buffer (mydata); +if (ret) { +printf ("Error: flush fat buffer\n" ); + goto exit; + } + +/* Write directory table to device */ + ret =set_cluster (mydata, itr->clust, itr->block, + mydata->clust_size * mydata->sect_size); +if (ret) +printf ("Error: writing directory entry\n" ); + +exit: +free (dirname_copy); +free (mydata->fatbuf); +free (itr); +free (dotdent); +return ret; +}fs/fs.c +2
-1@@ -164,14 +164,15 @@ static struct fstype_info fstypes[] = { .read = fat_read_file, #ifdef CONFIG_FAT_WRITE .write = file_fat_write, + .mkdir = fat_mkdir, #else .write = fs_write_unsupported, + .mkdir = fs_mkdir_unsupported, #endif .uuid = fs_uuid_unsupported, .opendir = fat_opendir, .readdir = fat_readdir, .closedir = fat_closedir, - .mkdir = fs_mkdir_unsupported, }, #endif #ifdef CONFIG_FS_EXT4include/fat.h +1
-0@@ -237,5 +237,6 @@ int fat_read_file(const char *filename, void *buf, loff_t offset, loff_t len,int fat_opendir (const char *filename,struct fs_dir_stream **dirsp);int fat_readdir (struct fs_dir_stream *dirs,struct fs_dirent **dentp);void fat_closedir (struct fs_dir_stream *dirs); +int fat_mkdir (const char *dirname);void fat_close (void );#endif /* _FAT_H_ */
PATCH 14/17 cmd: fat: add fatmkdir command
In reply to AKASHI TakahiroIn this patch, a new command, fatmkdir, is added.
Please note that, as there is no notion of "current directory" on u-boot, a directory name specified must contains an absolute directory path as a parent directory. Otherwise, "/" (root directory) is assumed.
--- cmd/fat.c | 13 +++++++++++++ 1 file changed, 13 insertions(+)
cmd/fat.c +13 -0
@@ -151,4 +151,17 @@ U_BOOT_CMD(" - write file 'filename' from the address 'addr' in RAM\n" " to 'dev' on 'interface'" ); + +static int do_fat_mkdir (cmd_tbl_t *cmdtp,int flag,int argc, +char *const argv[]) +{ +return do_mkdir (cmdtp, flag, argc, argv,FS_TYPE_FAT ); +} + +U_BOOT_CMD ( + fatmkdir,4 ,1 , do_fat_mkdir, +"create a directory" , +"<interface> [<dev[:part]>] <directory>\n" +" - create a directory in 'dev' on 'interface'" +);#endif
Signature · 1 line
2.17.0
PATCH 14/17 cmd: fat: add fatmkdir command
Quoted 8 lines · AKASHI Takahiro
In this patch, a new command, fatmkdir, is added.
Please note that, as there is no notion of "current directory" on u-boot, a directory name specified must contains an absolute directory path as a parent directory. Otherwise, "/" (root directory) is assumed.
Signed-off-by AKASHI Takahiro <[email protected]>---
Please, provide a Python test with an additional patch.
PATCH 14/17 cmd: fat: add fatmkdir command
Quoted 11 lines · Heinrich Schuchardt
Quoted 8 lines · AKASHI Takahiro
In this patch, a new command, fatmkdir, is added.
Please note that, as there is no notion of "current directory" on u-boot, a directory name specified must contains an absolute directory path as a parent directory. Otherwise, "/" (root directory) is assumed.
Signed-off-by AKASHI Takahiro <[email protected]>---
Please, provide a Python test with an additional patch.
Please see my reply to Simon's/Tom's comments.
Quoted 1 line
Reviewed-by Heinrich Schuchardt <[email protected]>
Thanks a lot for your review.
-Takahiro AKASHI
PATCH 15/17 efi_loader: file: support creating a directory
In reply to AKASHI TakahiroIn efi world, there is no obvious "mkdir" interface, instead, Open() with EFI_FILE_MODE_CREATE in mode parameter and EFI_FILE_DIRECTORY in attributes parameter creates a directory.
In this patch, efi_file_open() is extended so as to accept such a combination of parameters and call u-boot's mkdir interface for expected action.
--- lib/efi_loader/efi_file.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-)
lib/efi_loader/efi_file.c +10 -4
@@ -130,7 +130,8 @@ static int sanitize_path(char *path)* With windoze style backlashes, ofc. */ static struct efi_file_handle *file_open (struct file_system *fs, -struct file_handle *parent,s16 *file_name,u64 mode) +struct file_handle *parent,s16 *file_name,u64 mode, +u64 attributes) {struct file_handle *fh;char f0[MAX_UTF8_PER_UTF16 ] = {0 };
@@ -173,7 +174,12 @@ static struct efi_file_handle *file_open(struct file_system *fs,if (set_blk_dev (fh)) goto error; -if (!((mode &EFI_FILE_MODE_CREATE ) ||fs_exists (fh->path))) +if ((mode &EFI_FILE_MODE_CREATE ) && + (attributes &EFI_FILE_DIRECTORY )) { +if (fs_mkdir (fh->path)) + goto error; + }else if (!((mode &EFI_FILE_MODE_CREATE ) || +fs_exists (fh->path))) goto error;/* figure out if file is a directory: */
@@ -199,7 +205,7 @@ static efi_status_t EFIAPI efi_file_open(struct efi_file_handle *file,EFI_ENTRY ("%p, %p, \"%ls\", %llx, %llu" , file, new_handle, file_name, open_mode, attributes); - *new_handle =file_open (fh->fs, fh, file_name, open_mode); + *new_handle =file_open (fh->fs, fh, file_name, open_mode, attributes);if (!*new_handle)return EFI_EXIT (EFI_NOT_FOUND );
@@ -598,7 +604,7 @@ efi_open_volume(struct efi_simple_file_system_protocol *this,EFI_ENTRY ("%p, %p" , this, root); - *root =file_open (fs,NULL ,NULL ,0 ); + *root =file_open (fs,NULL ,NULL ,0 ,0 );return EFI_EXIT (EFI_SUCCESS ); }
Signature · 1 line
2.17.0
PATCH 16/17 efi_loader: implement a pseudo "file delete"
In reply to AKASHI TakahiroThis patch is necessary to run SCT.efi (UEFI Self-Certification Test). Returning EFI_SUCCESS can cheat SCT execution.
--- lib/efi_loader/efi_file.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-)
lib/efi_loader/efi_file.c +9 -1
@@ -226,12 +226,20 @@ static efi_status_t EFIAPI efi_file_close(struct efi_file_handle *file)return EFI_EXIT (file_close (fh)); } +static efi_status_t EFIAPI efi_file_write(struct efi_file_handle *file, +efi_uintn_t *buffer_size, +void *buffer); + static efi_status_t EFIAPI efi_file_delete(struct efi_file_handle *file) {struct file_handle *fh =to_fh (file); +efi_uintn_t size =0 ;EFI_ENTRY ("%p" , file); + +/* TODO: implement real 'delete' */ +efi_file_write (file, &size,NULL );file_close (fh); -return EFI_EXIT (EFI_WARN_DELETE_FAILURE ); +return EFI_SUCCESS ; } static efi_status_t file_read(struct file_handle *fh, u64 *buffer_size,
Signature · 1 line
2.17.0
PATCH 17/17 fs-test: fix false positive error at Test Case 12
In reply to AKASHI TakahiroThe error message to be matched is wrong. Fix it.
--- test/fs/fs-test.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
test/fs/fs-test.sh +1 -1
@@ -522,7 +522,7 @@ function check_results() { "TC11: 1MB write to $3.w - content verified" # Check lookup of 'dot' directory - grep -A4 "Test Case 12 " "$1" | grep -q 'Unable to write file' + grep -A4 "Test Case 12 " "$1" | grep -q 'Unable to write' pass_fail "TC12: 1MB write to . - write denied" # Check directory traversal
Signature · 1 line
2.17.0
PATCH 17/17 fs-test: fix false positive error at Test Case 12
Quoted 13 lines · AKASHI Takahiro
The error message to be matched is wrong. Fix it.
Signed-off-by AKASHI Takahiro <[email protected]>--- test/fs/fs-test.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)test/fs/fs-test.sh +0
-0
test/fs/fs-test.sh function check_results() { · line 528
Quoted 8 lines
test/fs/fs-test.sh +1
-1@@ -522,7 +522,7 @@ function check_results() { "TC11: 1MB write to $3.w - content verified" # Check lookup of 'dot' directory - grep -A4 "Test Case 12 " "$1" | grep -q 'Unable to write file' + grep -A4 "Test Case 12 " "$1" | grep -q 'Unable to write' pass_fail "TC12: 1MB write to . - write denied" # Check directory traversal
Tom suggested in
https://lists.denx.de/pipermail/u-boot/2018-July/336378.html that the comment headers in test/fs/fs-test.sh should be updated to reflect the total number of passes and fails.
Best regards
Heinrich
PATCH 17/17 fs-test: fix false positive error at Test Case 12
Quoted 20 lines · Heinrich Schuchardt
Quoted 19 lines · AKASHI Takahiro
The error message to be matched is wrong. Fix it.
Signed-off-by AKASHI Takahiro <[email protected]>--- test/fs/fs-test.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)test/fs/fs-test.sh +1
-1@@ -522,7 +522,7 @@ function check_results() { "TC11: 1MB write to $3.w - content verified" # Check lookup of 'dot' directory - grep -A4 "Test Case 12 " "$1" | grep -q 'Unable to write file' + grep -A4 "Test Case 12 " "$1" | grep -q 'Unable to write' pass_fail "TC12: 1MB write to . - write denied"
Quoted 7 lines
test/fs/fs-test.sh function check_results() { · line 528
Quoted 2 lines
test/fs/fs-test.sh +0
-0# Check directory traversalTom suggested in
https://lists.denx.de/pipermail/u-boot/2018-July/336378.html that the comment headers intest/fs/fs-test.shshould be updated to reflect the total number of passes and fails.
Thank you for this heads-up.
I'm now trying to rewrite fs-test.sh (at least part of it) on top of py.test framework.
It will take some time as I'm still learning how to write tests for py.test.
-Takahiro AKASHI
Quoted 3 lines
Best regards
Heinrich
cover fs: fat: extend FAT write operations
In reply to AKASHI TakahiroQuoted 24 lines · AKASHI Takahiro
This patch series is an attempt to address FAT write related issues in an effort of running UEFI SCT (Self-Certification Test) to verify UEFI support on u-boot.
SCT is a test platform as well as an extentisive collection of test cases for UEFI specification. It can run all the tests automatically and save test results to dedicated log files.
AFAIK, what's missing in the current fat file system to safely run SCT without errors (I don't mean test case failures) are:
* write a file located under sub-directories
* write a file with non-zero offset
* delete a file
* create a directoryPatch#1 to patch#6 are some sort of preparatory ones. Patch#7 implements write with sub-directories path. Patch#8 to patch#10 implement write with non-zero offset. Patch#11 to patch#15 are related to creating a directory. Patch#16 provides delete, but it doesn't actually delete a file but instead return 0 with purging a file content, which is good enough to run SCT for now.
Finally, patch#17 fixes a minor bug infs-test.sh.
Quoted 5 lines
I applied this patch set on top of v2018.07 along with a couple of yet-to--be-upstreamed UEFI-related patches, and could successfully run unmodified SCT[1] on qemu-arm.
Thanks Takahiro for getting this all implemented.
I have some questions concerning code pages:
The FAT file system contains a short name and a long name. The short name is in the 8-bit code page of the system. The long name is 16bit Unicode.
Which local code page do you assume? I would suggest to use 437 as we do in some other drivers.
With your patch fat_mkdir() and fat_file_write() do not yet support UTF-8 as file names and convert this to the 437 local page for the short name and to UTF-16 for the long name.
Without this conversoin we will not be able to implement the EFI specification.
normalize_longname() simply ignores codes 0x80-0xFF. Please, have a look at
https://www.win.tue.nl/~aeb/linux/fs/fat/fatgen103.pdf
Microsoft Extensible Firmware Initiative FAT32 File System Specification
FAT: General Overview of On-Disk Format
Version 1.03, December 6, 2000
Shouldn't we implement the base-name algorithm as described in the paper?
Best regards
Heinrich
cover fs: fat: extend FAT write operations
Hello Tom, hello Alex,
I have been testing the patches. They are working fine for ASCII file names. To support Unicode file names extra work will be needed. But probably we should postpone this to a later patch series.
There are some dependencies with my work for correcting errors in Unicode handling for the EFI branch. Should the patches be passed via efi-next?
Best regards
Heinrich
cover fs: fat: extend FAT write operations
Quoted 5 lines · Heinrich Schuchardt
Hello Tom, hello Alex,
I have been testing the patches. They are working fine for ASCII file names. To support Unicode file names extra work will be needed. But probably we should postpone this to a later patch series.
I absolutely agree.
To be clear, the aim of my FAT write patchset is to successfully run SCT to evaluate and verify UEFI-related features rather than to make the implementation comply with UEFI specification.
For the latter purpose, separate patches would be compiled as it might require time-consuming efforts.
(I'm sure that SCT's file (media access) protocol test causes lots of test case failures.)
Thanks,
-Takahiro AKASHI
Quoted 7 lines
There are some dependencies with my work for correcting errors in Unicode handling for the EFI branch. Should the patches be passed via efi-next?
Best regards
Heinrich
cover fs: fat: extend FAT write operations
In reply to Heinrich SchuchardtQuoted 9 lines · Heinrich Schuchardt
Hello Tom, hello Alex,
I have been testing the patches. They are working fine for ASCII file names. To support Unicode file names extra work will be needed. But probably we should postpone this to a later patch series.
There are some dependencies with my work for correcting errors in Unicode handling for the EFI branch. Should the patches be passed via efi-next?
Yes, a follow-up series makes sense, and yes, efi-next for the patches themselves sounds fine, thanks!
Signature · 8 lines
Tom -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: not available URL: <http://lists.denx.de/pipermail/u-boot/attachments/20180723/cd0cef29/attachment.sig>
cover fs: fat: extend FAT write operations
Quoted 7 lines · Tom Rini
Quoted 6 lines · Heinrich Schuchardt
Hello Tom, hello Alex,
I have been testing the patches. They are working fine for ASCII file names. To support Unicode file names extra work will be needed. But probably we should postpone this to a later patch series.
Quoted 7 lines
Quoted 3 lines
There are some dependencies with my work for correcting errors in Unicode handling for the EFI branch. Should the patches be passed via efi-next?
Yes, a follow-up series makes sense, and yes, efi-next for the patches themselves sounds fine, thanks!
Hello Takahiro,
could you, please, resubmit the series with the few changes needed so that Alex can consider them for efi-next.
Cheers
Heinrich
cover fs: fat: extend FAT write operations
Quoted 12 lines · Heinrich Schuchardt
Quoted 11 lines · Tom Rini
Quoted 9 lines · Heinrich Schuchardt
Hello Tom, hello Alex,
I have been testing the patches. They are working fine for ASCII file names. To support Unicode file names extra work will be needed. But probably we should postpone this to a later patch series.
There are some dependencies with my work for correcting errors in Unicode handling for the EFI branch. Should the patches be passed via efi-next?
Quoted 8 lines
Quoted 3 lines
Yes, a follow-up series makes sense, and yes, efi-next for the patches themselves sounds fine, thanks!
Hello Takahiro,
could you, please, resubmit the series with the few changes needed so that Alex can consider them for efi-next.
Well, I'm sure that my patch set can be applied to v2018.09-rc1 w/o any changes if your patch (0dc1bfb7302 "fs: fat: cannot write to subdirectories") is reverted beforehand. As I said, my patch(#5/17) superseded it in terms of its function.
What's more, I ran fs-test.sh again, and all tests passed, either against fat16 or fat32. Do we still want to update a test result in fs-test.sh? (removing it would be the easiest.)
Thanks,
-Takahiro AKASHI
Quoted 3 lines
Cheers
Heinrich
cover fs: fat: extend FAT write operations
Quoted 19 lines · AKASHI Takahiro
Quoted 18 lines · Heinrich Schuchardt
Quoted 7 lines · Tom Rini
Quoted 6 lines · Heinrich Schuchardt
Hello Tom, hello Alex,
I have been testing the patches. They are working fine for ASCII file names. To support Unicode file names extra work will be needed. But probably we should postpone this to a later patch series.
Quoted 7 lines
Quoted 3 lines
There are some dependencies with my work for correcting errors in Unicode handling for the EFI branch. Should the patches be passed via efi-next?
Yes, a follow-up series makes sense, and yes, efi-next for the patches themselves sounds fine, thanks!
Hello Takahiro,
Quoted 7 lines
Quoted 2 lines
could you, please, resubmit the series with the few changes needed so that Alex can consider them for efi-next.
Well, I'm sure that my patch set can be applied to v2018.09-rc1 w/o any changes if your patch (
0dc1bfb7302"fs: fat: cannot write to subdirectories") is reverted beforehand. As I said, my patch(#5/17) superseded it in terms of its function.
See:
https://git.linaro.org/people/takahiro.akashi/u-boot.git fat_write
Quoted 3 lines
What's more, I ran
fs-test.shagain, and all tests passed, either against fat16 or fat32. Do we still want to update a test result infs-test.sh? (removing it would be the easiest.)
I've almost finished to convert fs-test.sh to a Python script, but it will take some time to add more tests against my patch set as my priority right now is on examining a test result from SCT.
-Takahiro AKASHI
Quoted 7 lines
Thanks,
-Takahiro AKASHIQuoted 3 lines
Cheers
Heinrich
cover fs: fat: extend FAT write operations
In reply to AKASHI TakahiroQuoted 19 lines · AKASHI Takahiro
Quoted 18 lines · Heinrich Schuchardt
Quoted 7 lines · Tom Rini
Quoted 6 lines · Heinrich Schuchardt
Hello Tom, hello Alex,
I have been testing the patches. They are working fine for ASCII file names. To support Unicode file names extra work will be needed. But probably we should postpone this to a later patch series.
Quoted 7 lines
Quoted 3 lines
There are some dependencies with my work for correcting errors in Unicode handling for the EFI branch. Should the patches be passed via efi-next?
Yes, a follow-up series makes sense, and yes, efi-next for the patches themselves sounds fine, thanks!
Hello Takahiro,
Quoted 7 lines
Quoted 2 lines
could you, please, resubmit the series with the few changes needed so that Alex can consider them for efi-next.
Well, I'm sure that my patch set can be applied to v2018.09-rc1 w/o any changes if your patch (
0dc1bfb7302"fs: fat: cannot write to subdirectories") is reverted beforehand. As I said, my patch(#5/17) superseded it in terms of its function.
Please, add a patch doing the reverting or rebase patch 5.
Quoted 4 lines
What's more, I ran
fs-test.shagain, and all tests passed, either against fat16 or fat32. Do we still want to update a test result infs-test.sh? (removing it would be the easiest.)
As long as we have no better tests in place updating those comments is appropriate.
In my review of patch 01/17 I indicated an error in evaluating the sector number.
Best regards
Heinrich