@@ -3877,6 +3877,23 @@ static int lfs_stat_(lfs_t *lfs, const char *path, struct lfs_info *info) {
38773877 return lfs_dir_getinfo (lfs , & cwd , lfs_tag_id (tag ), info );
38783878}
38793879
3880+ #ifndef LFS_READONLY
3881+ struct lfs_remove_state
3882+ {
3883+ // File to be removed pointer (cwd and tag)
3884+ lfs_mdir_t cwd ;
3885+ lfs_stag_t tag ;
3886+
3887+ // Directory that needs to be removed from linked list pointer
3888+ struct lfs_mlist dir ;
3889+
3890+ // First block-pair in the directory to be removed; this gets
3891+ // destroyed in lfs_mlist below as it traverses the splits in
3892+ // the directory.
3893+ lfs_block_t dir_head [2 ];
3894+ };
3895+ #endif
3896+
38803897#ifndef LFS_READONLY
38813898static int lfs_remove_ (lfs_t * lfs , const char * path ) {
38823899 // deorphan if we haven't yet, needed at most once after poweron
@@ -3885,30 +3902,28 @@ static int lfs_remove_(lfs_t *lfs, const char *path) {
38853902 return err ;
38863903 }
38873904
3888- lfs_mdir_t cwd ;
3889- lfs_stag_t tag = lfs_dir_find (lfs , & cwd , & path , NULL );
3890- if (tag < 0 || lfs_tag_id (tag ) == 0x3ff ) {
3891- return (tag < 0 ) ? (int )tag : LFS_ERR_INVAL ;
3905+ struct lfs_remove_state s ;
3906+ s . tag = lfs_dir_find (lfs , & s . cwd , & path , NULL );
3907+ if (s . tag < 0 || lfs_tag_id (s . tag ) == 0x3ff ) {
3908+ return (s . tag < 0 ) ? (int )s . tag : LFS_ERR_INVAL ;
38923909 }
38933910
3894- struct lfs_mlist dir ;
3895- dir .next = lfs -> mlist ;
3896- if (lfs_tag_type3 (tag ) == LFS_TYPE_DIR ) {
3911+ s .dir .next = lfs -> mlist ;
3912+ if (lfs_tag_type3 (s .tag ) == LFS_TYPE_DIR ) {
38973913 // must be empty before removal
3898- lfs_block_t pair [2 ];
3899- lfs_stag_t res = lfs_dir_get (lfs , & cwd , LFS_MKTAG (0x700 , 0x3ff , 0 ),
3900- LFS_MKTAG (LFS_TYPE_STRUCT , lfs_tag_id (tag ), 8 ), pair );
3914+ lfs_stag_t res = lfs_dir_get (lfs , & s .cwd , LFS_MKTAG (0x700 , 0x3ff , 0 ),
3915+ LFS_MKTAG (LFS_TYPE_STRUCT , lfs_tag_id (s .tag ), 8 ), s .dir_head );
39013916 if (res < 0 ) {
39023917 return (int )res ;
39033918 }
3904- lfs_pair_fromle32 (pair );
3919+ lfs_pair_fromle32 (s . dir_head );
39053920
3906- err = lfs_dir_fetch (lfs , & dir .m , pair );
3921+ err = lfs_dir_fetch (lfs , & s . dir .m , s . dir_head );
39073922 if (err ) {
39083923 return err ;
39093924 }
39103925
3911- if (dir .m .count > 0 || dir .m .split ) {
3926+ if (s . dir .m .count > 0 || s . dir .m .split ) {
39123927 return LFS_ERR_NOTEMPTY ;
39133928 }
39143929
@@ -3920,33 +3935,33 @@ static int lfs_remove_(lfs_t *lfs, const char *path) {
39203935
39213936 // I know it's crazy but yes, dir can be changed by our parent's
39223937 // commit (if predecessor is child)
3923- dir .type = 0 ;
3924- dir .id = 0 ;
3925- lfs -> mlist = & dir ;
3938+ s . dir .type = 0 ;
3939+ s . dir .id = 0 ;
3940+ lfs -> mlist = & s . dir ;
39263941 }
39273942
39283943 // delete the entry
3929- err = lfs_dir_commit (lfs , & cwd , LFS_MKATTRS (
3930- {LFS_MKTAG (LFS_TYPE_DELETE , lfs_tag_id (tag ), 0 ), NULL }));
3944+ err = lfs_dir_commit (lfs , & s . cwd , LFS_MKATTRS (
3945+ {LFS_MKTAG (LFS_TYPE_DELETE , lfs_tag_id (s . tag ), 0 ), NULL }));
39313946 if (err ) {
3932- lfs -> mlist = dir .next ;
3947+ lfs -> mlist = s . dir .next ;
39333948 return err ;
39343949 }
39353950
3936- lfs -> mlist = dir .next ;
3937- if (lfs_tag_type3 (tag ) == LFS_TYPE_DIR ) {
3951+ lfs -> mlist = s . dir .next ;
3952+ if (lfs_tag_type3 (s . tag ) == LFS_TYPE_DIR ) {
39383953 // fix orphan
39393954 err = lfs_fs_preporphans (lfs , -1 );
39403955 if (err ) {
39413956 return err ;
39423957 }
39433958
3944- err = lfs_fs_pred (lfs , dir .m .pair , & cwd );
3959+ err = lfs_fs_pred (lfs , s . dir .m .pair , & s . cwd );
39453960 if (err ) {
39463961 return err ;
39473962 }
39483963
3949- err = lfs_dir_drop (lfs , & cwd , & dir .m );
3964+ err = lfs_dir_drop (lfs , & s . cwd , & s . dir .m );
39503965 if (err ) {
39513966 return err ;
39523967 }
@@ -3972,21 +3987,20 @@ static int lfs_rename_(lfs_t *lfs, const char *oldpath, const char *newpath) {
39723987 }
39733988
39743989 // find new entry
3975- lfs_mdir_t newcwd ;
3990+ struct lfs_remove_state n ;
39763991 uint16_t newid ;
3977- lfs_stag_t prevtag = lfs_dir_find (lfs , & newcwd , & newpath , & newid );
3978- if ((prevtag < 0 || lfs_tag_id (prevtag ) == 0x3ff ) &&
3979- !(prevtag == LFS_ERR_NOENT && lfs_path_islast (newpath ))) {
3980- return (prevtag < 0 ) ? (int )prevtag : LFS_ERR_INVAL ;
3992+ n . tag = lfs_dir_find (lfs , & n . cwd , & newpath , & newid );
3993+ if ((n . tag < 0 || lfs_tag_id (n . tag ) == 0x3ff ) &&
3994+ !(n . tag == LFS_ERR_NOENT && lfs_path_islast (newpath ))) {
3995+ return (n . tag < 0 ) ? (int )n . tag : LFS_ERR_INVAL ;
39813996 }
39823997
39833998 // if we're in the same pair there's a few special cases...
3984- bool samepair = (lfs_pair_cmp (oldcwd .pair , newcwd .pair ) == 0 );
3999+ bool samepair = (lfs_pair_cmp (oldcwd .pair , n . cwd .pair ) == 0 );
39854000 uint16_t newoldid = lfs_tag_id (oldtag );
39864001
3987- struct lfs_mlist prevdir ;
3988- prevdir .next = lfs -> mlist ;
3989- if (prevtag == LFS_ERR_NOENT ) {
4002+ n .dir .next = lfs -> mlist ;
4003+ if (n .tag == LFS_ERR_NOENT ) {
39904004 // if we're a file, don't allow trailing slashes
39914005 if (lfs_path_isdir (newpath )
39924006 && lfs_tag_type3 (oldtag ) != LFS_TYPE_DIR ) {
@@ -4005,30 +4019,28 @@ static int lfs_rename_(lfs_t *lfs, const char *oldpath, const char *newpath) {
40054019 if (samepair && newid <= newoldid ) {
40064020 newoldid += 1 ;
40074021 }
4008- } else if (lfs_tag_type3 (prevtag ) != lfs_tag_type3 (oldtag )) {
4009- return (lfs_tag_type3 (prevtag ) == LFS_TYPE_DIR )
4022+ } else if (lfs_tag_type3 (n . tag ) != lfs_tag_type3 (oldtag )) {
4023+ return (lfs_tag_type3 (n . tag ) == LFS_TYPE_DIR )
40104024 ? LFS_ERR_ISDIR
40114025 : LFS_ERR_NOTDIR ;
40124026 } else if (samepair && newid == newoldid ) {
40134027 // we're renaming to ourselves??
40144028 return 0 ;
4015- } else if (lfs_tag_type3 (prevtag ) == LFS_TYPE_DIR ) {
4016- // must be empty before removal
4017- lfs_block_t prevpair [2 ];
4018- lfs_stag_t res = lfs_dir_get (lfs , & newcwd , LFS_MKTAG (0x700 , 0x3ff , 0 ),
4019- LFS_MKTAG (LFS_TYPE_STRUCT , newid , 8 ), prevpair );
4029+ } else if (lfs_tag_type3 (n .tag ) == LFS_TYPE_DIR ) {
4030+ lfs_stag_t res = lfs_dir_get (lfs , & n .cwd , LFS_MKTAG (0x700 , 0x3ff , 0 ),
4031+ LFS_MKTAG (LFS_TYPE_STRUCT , newid , 8 ), n .dir_head );
40204032 if (res < 0 ) {
40214033 return (int )res ;
40224034 }
4023- lfs_pair_fromle32 (prevpair );
4035+ lfs_pair_fromle32 (n . dir_head );
40244036
40254037 // must be empty before removal
4026- err = lfs_dir_fetch (lfs , & prevdir . m , prevpair );
4038+ err = lfs_dir_fetch (lfs , & n . dir . m , n . dir_head );
40274039 if (err ) {
40284040 return err ;
40294041 }
40304042
4031- if (prevdir . m .count > 0 || prevdir .m .split ) {
4043+ if (n . dir . m .count > 0 || n . dir .m .split ) {
40324044 return LFS_ERR_NOTEMPTY ;
40334045 }
40344046
@@ -4040,18 +4052,18 @@ static int lfs_rename_(lfs_t *lfs, const char *oldpath, const char *newpath) {
40404052
40414053 // I know it's crazy but yes, dir can be changed by our parent's
40424054 // commit (if predecessor is child)
4043- prevdir .type = 0 ;
4044- prevdir .id = 0 ;
4045- lfs -> mlist = & prevdir ;
4055+ n . dir .type = 0 ;
4056+ n . dir .id = 0 ;
4057+ lfs -> mlist = & n . dir ;
40464058 }
40474059
40484060 if (!samepair ) {
40494061 lfs_fs_prepmove (lfs , newoldid , oldcwd .pair );
40504062 }
40514063
40524064 // move over all attributes
4053- err = lfs_dir_commit (lfs , & newcwd , LFS_MKATTRS (
4054- {LFS_MKTAG_IF (prevtag != LFS_ERR_NOENT ,
4065+ err = lfs_dir_commit (lfs , & n . cwd , LFS_MKATTRS (
4066+ {LFS_MKTAG_IF (n . tag != LFS_ERR_NOENT ,
40554067 LFS_TYPE_DELETE , newid , 0 ), NULL },
40564068 {LFS_MKTAG (LFS_TYPE_CREATE , newid , 0 ), NULL },
40574069 {LFS_MKTAG (lfs_tag_type3 (oldtag ),
@@ -4060,7 +4072,7 @@ static int lfs_rename_(lfs_t *lfs, const char *oldpath, const char *newpath) {
40604072 {LFS_MKTAG_IF (samepair ,
40614073 LFS_TYPE_DELETE , newoldid , 0 ), NULL }));
40624074 if (err ) {
4063- lfs -> mlist = prevdir .next ;
4075+ lfs -> mlist = n . dir .next ;
40644076 return err ;
40654077 }
40664078
@@ -4072,26 +4084,26 @@ static int lfs_rename_(lfs_t *lfs, const char *oldpath, const char *newpath) {
40724084 err = lfs_dir_commit (lfs , & oldcwd , LFS_MKATTRS (
40734085 {LFS_MKTAG (LFS_TYPE_DELETE , lfs_tag_id (oldtag ), 0 ), NULL }));
40744086 if (err ) {
4075- lfs -> mlist = prevdir .next ;
4087+ lfs -> mlist = n . dir .next ;
40764088 return err ;
40774089 }
40784090 }
40794091
4080- lfs -> mlist = prevdir .next ;
4081- if (prevtag != LFS_ERR_NOENT
4082- && lfs_tag_type3 (prevtag ) == LFS_TYPE_DIR ) {
4092+ lfs -> mlist = n . dir .next ;
4093+ if (n . tag != LFS_ERR_NOENT
4094+ && lfs_tag_type3 (n . tag ) == LFS_TYPE_DIR ) {
40834095 // fix orphan
40844096 err = lfs_fs_preporphans (lfs , -1 );
40854097 if (err ) {
40864098 return err ;
40874099 }
40884100
4089- err = lfs_fs_pred (lfs , prevdir . m .pair , & newcwd );
4101+ err = lfs_fs_pred (lfs , n . dir . m .pair , & n . cwd );
40904102 if (err ) {
40914103 return err ;
40924104 }
40934105
4094- err = lfs_dir_drop (lfs , & newcwd , & prevdir .m );
4106+ err = lfs_dir_drop (lfs , & n . cwd , & n . dir .m );
40954107 if (err ) {
40964108 return err ;
40974109 }
0 commit comments