@@ -515,13 +515,20 @@ struct lfs_region {
515
515
LFS_FROM_DROP ,
516
516
LFS_FROM_MEM ,
517
517
LFS_FROM_REGION ,
518
+ LFS_FROM_ATTRS ,
518
519
} type ;
519
520
520
521
lfs_off_t off ;
521
522
const void * buffer ;
522
523
lfs_ssize_t size ;
523
524
};
524
525
526
+ struct lfs_attrs_region {
527
+ const struct lfs_attr * attrs ;
528
+ int count ;
529
+ lfs_size_t len ;
530
+ };
531
+
525
532
struct lfs_region_region {
526
533
lfs_block_t block ;
527
534
lfs_off_t off ;
@@ -568,6 +575,73 @@ static int lfs_commit_region(lfs_t *lfs,
568
575
newoff += regions [i ].size ;
569
576
break ;
570
577
}
578
+ case LFS_FROM_ATTRS : {
579
+ const struct lfs_attrs_region * attrs = regions [i ].buffer ;
580
+
581
+ // order doesn't matter, so we write new attrs first. this
582
+ // is still O(n^2) but only O(n) disk access
583
+ for (int j = 0 ; j < attrs -> count ; j ++ ) {
584
+ if (attrs -> attrs [j ].size == 0 ) {
585
+ continue ;
586
+ }
587
+
588
+ lfs_entry_attr_t attr = {
589
+ .d .type = attrs -> attrs [j ].type ,
590
+ .d .len = attrs -> attrs [j ].size ,
591
+ };
592
+
593
+ lfs_crc (crc , & attr .d , sizeof (attr .d ));
594
+ int err = lfs_bd_prog (lfs , newblock , newoff ,
595
+ & attr .d , sizeof (attr .d ));
596
+ if (err ) {
597
+ return err ;
598
+ }
599
+
600
+ lfs_crc (crc ,
601
+ attrs -> attrs [j ].buffer , attrs -> attrs [j ].size );
602
+ err = lfs_bd_prog (lfs , newblock , newoff + sizeof (attr .d ),
603
+ attrs -> attrs [j ].buffer , attrs -> attrs [j ].size );
604
+ if (err ) {
605
+ return err ;
606
+ }
607
+
608
+ newoff += sizeof (attr .d ) + attrs -> attrs [j ].size ;
609
+ }
610
+
611
+ // copy over attributes without updates
612
+ lfs_entry_attr_t attr ;
613
+ for (lfs_off_t k = 0 ; k < attrs -> len ; k += 2 + attr .d .len ) {
614
+ int err = lfs_bd_read (lfs , oldblock , oldoff ,
615
+ & attr .d , sizeof (attr .d ));
616
+ if (err ) {
617
+ return err ;
618
+ }
619
+
620
+ bool updating = false;
621
+ for (int j = 0 ; j < attrs -> count ; j ++ ) {
622
+ if (attr .d .type == attrs -> attrs [j ].type ) {
623
+ updating = true;
624
+ }
625
+ }
626
+
627
+ if (!updating ) {
628
+ err = lfs_commit_region (lfs ,
629
+ oldblock , oldoff ,
630
+ newblock , newoff ,
631
+ 0 , NULL , 0 ,
632
+ attr .d .len , crc );
633
+ if (err ) {
634
+ return err ;
635
+ }
636
+
637
+ newoff += 2 + attr .d .len ;
638
+ }
639
+
640
+ oldoff += 2 + attr .d .len ;
641
+ }
642
+
643
+ break ;
644
+ }
571
645
}
572
646
573
647
i += 1 ;
@@ -590,6 +664,8 @@ static int lfs_commit_region(lfs_t *lfs,
590
664
}
591
665
}
592
666
667
+ // sanity check our commit math
668
+ LFS_ASSERT (newoff == end );
593
669
return 0 ;
594
670
}
595
671
@@ -1044,118 +1120,102 @@ static int lfs_dir_getinfo(lfs_t *lfs,
1044
1120
return 0 ;
1045
1121
}
1046
1122
1047
- static int lfs_dir_getattr (lfs_t * lfs ,
1123
+ static int lfs_dir_getattrs (lfs_t * lfs ,
1048
1124
lfs_dir_t * dir , const lfs_entry_t * entry ,
1049
- uint8_t type , void * buffer , lfs_size_t size ) {
1125
+ const struct lfs_attr * attrs , int count ) {
1126
+ // set to zero in case we can't find the attributes or size mismatch
1127
+ for (int j = 0 ; j < count ; j ++ ) {
1128
+ memset (attrs [j ].buffer , 0 , attrs [j ].size );
1129
+ }
1130
+
1050
1131
// search for attribute in attribute region
1051
- lfs_off_t off = sizeof (dir -> d ) + lfs_entry_elen (entry );
1052
- lfs_off_t i = 0 ;
1053
- while (i < lfs_entry_alen (entry )) {
1054
- lfs_attr_t attr ;
1132
+ lfs_off_t off = 4 + lfs_entry_elen (entry );
1133
+ lfs_entry_attr_t attr ;
1134
+ for (lfs_off_t i = 0 ; i < lfs_entry_alen (entry ); i += 2 + attr .d .len ) {
1055
1135
int err = lfs_dir_get (lfs , dir ,
1056
1136
entry -> off + off + i , & attr .d , sizeof (attr .d ));
1057
1137
if (err ) {
1058
1138
return err ;
1059
1139
}
1060
1140
1061
- if (attr .d .type != type ) {
1062
- i += attr .d .len ;
1063
- continue ;
1064
- }
1065
-
1066
- if (attr .d .len > size ) {
1067
- return LFS_ERR_RANGE ;
1068
- }
1141
+ for (int j = 0 ; j < count ; j ++ ) {
1142
+ if (attr .d .type == attrs [j ].type ) {
1143
+ if (attr .d .len > attrs [j ].size ) {
1144
+ return LFS_ERR_RANGE ;
1145
+ }
1069
1146
1070
- err = lfs_dir_get (lfs , dir ,
1071
- entry -> off + off + i + sizeof (attr .d ), buffer , attr .d .len );
1072
- if (err ) {
1073
- return err ;
1147
+ err = lfs_dir_get (lfs , dir ,
1148
+ entry -> off + off + i + sizeof (attr .d ),
1149
+ attrs [j ].buffer , attr .d .len );
1150
+ if (err ) {
1151
+ return err ;
1152
+ }
1153
+ }
1074
1154
}
1075
-
1076
- return attr .d .len ;
1077
1155
}
1078
1156
1079
- return LFS_ERR_NODATA ;
1157
+ return 0 ;
1080
1158
}
1081
1159
1082
- static int lfs_dir_setattr (lfs_t * lfs ,
1160
+ static lfs_ssize_t lfs_dir_checkattrs (lfs_t * lfs ,
1083
1161
lfs_dir_t * dir , lfs_entry_t * entry ,
1084
- uint8_t type , const void * buffer , lfs_size_t size ) {
1085
- // search for attribute in attribute region
1086
- lfs_off_t off = sizeof (dir -> d ) + lfs_entry_elen (entry );
1087
- lfs_off_t i = 0 ;
1088
- lfs_size_t oldlen = 0 ;
1089
- while (i < lfs_entry_alen (entry )) {
1090
- lfs_attr_t attr ;
1162
+ const struct lfs_attr * attrs , int count ) {
1163
+ // check that attributes fit
1164
+ lfs_size_t nsize = 0 ;
1165
+ for (int j = 0 ; j < count ; j ++ ) {
1166
+ nsize += 2 + attrs [j ].size ;
1167
+ }
1168
+
1169
+ lfs_off_t off = 4 + lfs_entry_elen (entry );
1170
+ lfs_entry_attr_t attr ;
1171
+ for (lfs_off_t i = 0 ; i < lfs_entry_alen (entry ); i += 2 + attr .d .len ) {
1091
1172
int err = lfs_dir_get (lfs , dir ,
1092
1173
entry -> off + off + i , & attr .d , sizeof (attr .d ));
1093
1174
if (err ) {
1094
1175
return err ;
1095
1176
}
1096
1177
1097
- if (attr .d .type != type ) {
1098
- i += attr .d .len ;
1099
- continue ;
1178
+ bool updated = false;
1179
+ for (int j = 0 ; j < count ; j ++ ) {
1180
+ if (attr .d .type == attrs [j ].type ) {
1181
+ updated = true;
1182
+ }
1100
1183
}
1101
1184
1102
- oldlen = attr .d .len ;
1103
- break ;
1185
+ if (!updated ) {
1186
+ nsize += 2 + attr .d .len ;
1187
+ }
1104
1188
}
1105
1189
1106
- // make sure the attribute fits
1107
- if ( lfs_entry_elen ( entry ) - oldlen + size > lfs -> attrs_size ||
1108
- ( 0x7fffffff & dir -> d . size ) - oldlen + size > lfs -> cfg -> block_size ) {
1190
+ if ( nsize > lfs -> attrs_size || (
1191
+ ( 0x7fffffff & dir -> d . size ) + lfs_entry_size ( entry ) -
1192
+ lfs_entry_alen ( entry ) + nsize > lfs -> cfg -> block_size ) ) {
1109
1193
return LFS_ERR_NOSPC ;
1110
1194
}
1111
1195
1112
- lfs_attr_t attr ;
1113
- attr .d .type = type ;
1114
- attr .d .len = size ;
1115
- int err = lfs_dir_set (lfs , dir , entry , (struct lfs_region []){
1116
- {LFS_FROM_MEM , off + i , & attr .d , sizeof (attr .d )},
1117
- {LFS_FROM_MEM , off + i , buffer , size },
1118
- {LFS_FROM_DROP , off + i , NULL , - oldlen }}, 3 );
1119
- if (err ) {
1120
- return err ;
1121
- }
1122
-
1123
- return 0 ;
1196
+ return nsize ;
1124
1197
}
1125
1198
1126
- static int lfs_dir_removeattr (lfs_t * lfs ,
1127
- lfs_dir_t * dir , lfs_entry_t * entry , uint8_t type ) {
1128
- // search for attribute in attribute region
1129
- lfs_off_t off = sizeof (dir -> d ) + lfs_entry_elen (entry );
1130
- lfs_off_t i = 0 ;
1131
- while (i < lfs_entry_alen (entry )) {
1132
- lfs_attr_t attr ;
1133
- int err = lfs_dir_get (lfs , dir ,
1134
- entry -> off + off + i , & attr .d , sizeof (attr .d ));
1135
- if (err ) {
1136
- return err ;
1137
- }
1138
-
1139
- if (attr .d .type != type ) {
1140
- i += attr .d .len ;
1141
- continue ;
1142
- }
1143
-
1144
- err = lfs_dir_set (lfs , dir , entry , (struct lfs_region []){
1145
- {LFS_FROM_DROP , off + i ,
1146
- NULL , - (sizeof (attr .d )+ attr .d .len )}}, 1 );
1147
- if (err ) {
1148
- return err ;
1149
- }
1150
-
1151
- return 0 ;
1199
+ static int lfs_dir_setattrs (lfs_t * lfs ,
1200
+ lfs_dir_t * dir , lfs_entry_t * entry ,
1201
+ const struct lfs_attr * attrs , int count ) {
1202
+ // make sure attributes fit
1203
+ lfs_ssize_t nsize = lfs_dir_checkattrs (lfs , dir , entry , attrs , count );
1204
+ if (nsize < 0 ) {
1205
+ return nsize ;
1152
1206
}
1153
1207
1154
- return LFS_ERR_NODATA ;
1208
+ // commit to entry, majority of work is in LFS_FROM_ATTRS
1209
+ lfs_size_t oldlen = lfs_entry_alen (entry );
1210
+ entry -> d .alen = (0xc0 & entry -> d .alen ) | nsize ;
1211
+ return lfs_dir_set (lfs , dir , entry , (struct lfs_region []){
1212
+ {LFS_FROM_MEM , 0 , & entry -> d , 4 },
1213
+ {LFS_FROM_DROP , 0 , NULL , -4 },
1214
+ {LFS_FROM_ATTRS , 4 + lfs_entry_elen (entry ),
1215
+ & (struct lfs_attrs_region ){attrs , count , oldlen }, nsize }}, 3 );
1155
1216
}
1156
1217
1157
1218
1158
-
1159
1219
/// Top level directory operations ///
1160
1220
int lfs_mkdir (lfs_t * lfs , const char * path ) {
1161
1221
// deorphan if we haven't yet, needed at most once after poweron
@@ -2372,25 +2432,8 @@ int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath) {
2372
2432
2373
2433
2374
2434
/// Attribute operations ///
2375
- int lfs_getattr (lfs_t * lfs , const char * path ,
2376
- uint8_t type , void * buffer , lfs_size_t size ) {
2377
- lfs_dir_t cwd ;
2378
- int err = lfs_dir_fetch (lfs , & cwd , lfs -> root );
2379
- if (err ) {
2380
- return err ;
2381
- }
2382
-
2383
- lfs_entry_t entry ;
2384
- err = lfs_dir_find (lfs , & cwd , & entry , & path );
2385
- if (err ) {
2386
- return err ;
2387
- }
2388
-
2389
- return lfs_dir_getattr (lfs , & cwd , & entry , type , buffer , size );
2390
- }
2391
-
2392
- int lfs_setattr (lfs_t * lfs , const char * path ,
2393
- uint8_t type , const void * buffer , lfs_size_t size ) {
2435
+ int lfs_getattrs (lfs_t * lfs , const char * path ,
2436
+ const struct lfs_attr * attrs , int count ) {
2394
2437
lfs_dir_t cwd ;
2395
2438
int err = lfs_dir_fetch (lfs , & cwd , lfs -> root );
2396
2439
if (err ) {
@@ -2403,10 +2446,11 @@ int lfs_setattr(lfs_t *lfs, const char *path,
2403
2446
return err ;
2404
2447
}
2405
2448
2406
- return lfs_dir_setattr (lfs , & cwd , & entry , type , buffer , size );
2449
+ return lfs_dir_getattrs (lfs , & cwd , & entry , attrs , count );
2407
2450
}
2408
2451
2409
- int lfs_removeattr (lfs_t * lfs , const char * path , uint8_t type ) {
2452
+ int lfs_setattrs (lfs_t * lfs , const char * path ,
2453
+ const struct lfs_attr * attrs , int count ) {
2410
2454
lfs_dir_t cwd ;
2411
2455
int err = lfs_dir_fetch (lfs , & cwd , lfs -> root );
2412
2456
if (err ) {
@@ -2419,7 +2463,7 @@ int lfs_removeattr(lfs_t *lfs, const char *path, uint8_t type) {
2419
2463
return err ;
2420
2464
}
2421
2465
2422
- return lfs_dir_removeattr (lfs , & cwd , & entry , type );
2466
+ return lfs_dir_setattrs (lfs , & cwd , & entry , attrs , count );
2423
2467
}
2424
2468
2425
2469
0 commit comments