diff options
Diffstat (limited to 'firmware')
-rw-r--r-- | firmware/common/dircache.c | 80 | ||||
-rw-r--r-- | firmware/common/file_internal.c | 2 | ||||
-rw-r--r-- | firmware/include/file_internal.h | 2 |
3 files changed, 49 insertions, 35 deletions
diff --git a/firmware/common/dircache.c b/firmware/common/dircache.c index 08457f2da1..42585e121b 100644 --- a/firmware/common/dircache.c +++ b/firmware/common/dircache.c | |||
@@ -149,15 +149,18 @@ enum | |||
149 | DCM_LAST = DCM_PROCEED, | 149 | DCM_LAST = DCM_PROCEED, |
150 | }; | 150 | }; |
151 | 151 | ||
152 | #define MAX_TINYNAME sizeof (uint32_t) | 152 | #define MAX_TINYNAME sizeof (uint32_t) |
153 | #define DC_MAX_NAME MIN(MAX_NAME, UINT8_MAX) | 153 | #define NAMELEN_ADJ (MAX_TINYNAME+1) |
154 | #define DC_MAX_NAME (UINT8_MAX+NAMELEN_ADJ) | ||
155 | #define CE_NAMESIZE(len) ((len)+NAMELEN_ADJ) | ||
156 | #define NAMESIZE_CE(size) ((size)-NAMELEN_ADJ) | ||
154 | 157 | ||
155 | /* Throw some warnings if about the limits if things may not work */ | 158 | /* Throw some warnings if about the limits if things may not work */ |
156 | #if MAX_NAME > UINT8_MAX | 159 | #if MAX_COMPNAME > UINT8_MAX+5 |
157 | #warning Need more than 8 bits in name length bitfield | 160 | #warning Need more than 8 bits in name length bitfield |
158 | #endif | 161 | #endif |
159 | 162 | ||
160 | #if DIRCACHE_LIMIT > ((1 << 24)-255) | 163 | #if DIRCACHE_LIMIT > ((1 << 24)-1+5) |
161 | #warning Names may not be addressable with 24 bits | 164 | #warning Names may not be addressable with 24 bits |
162 | #endif | 165 | #endif |
163 | 166 | ||
@@ -173,7 +176,7 @@ struct dircache_entry | |||
173 | union { | 176 | union { |
174 | struct { | 177 | struct { |
175 | uint32_t name : 24; /* indirect storage (.tinyname == 0) */ | 178 | uint32_t name : 24; /* indirect storage (.tinyname == 0) */ |
176 | uint32_t length : 8; /* length of name indexed by 'name' */ | 179 | uint32_t namelen : 8; /* length of name - (MAX_TINYNAME+1) */ |
177 | }; | 180 | }; |
178 | unsigned char namebuf[MAX_TINYNAME]; /* direct storage (.tinyname == 1) */ | 181 | unsigned char namebuf[MAX_TINYNAME]; /* direct storage (.tinyname == 1) */ |
179 | }; | 182 | }; |
@@ -743,7 +746,7 @@ static void entry_name_copy(char *dst, const struct dircache_entry *ce) | |||
743 | { | 746 | { |
744 | if (LIKELY(!ce->tinyname)) | 747 | if (LIKELY(!ce->tinyname)) |
745 | { | 748 | { |
746 | strmemcpy(dst, get_name(ce->name), ce->length); | 749 | strmemcpy(dst, get_name(ce->name), CE_NAMESIZE(ce->namelen)); |
747 | return; | 750 | return; |
748 | } | 751 | } |
749 | 752 | ||
@@ -876,8 +879,8 @@ static void free_name(int nameidx, size_t size) | |||
876 | /** | 879 | /** |
877 | * allocate and assign a name to the entry | 880 | * allocate and assign a name to the entry |
878 | */ | 881 | */ |
879 | static bool entry_assign_name(struct dircache_entry *ce, | 882 | static int entry_assign_name(struct dircache_entry *ce, |
880 | const unsigned char *name, size_t size) | 883 | const unsigned char *name, size_t size) |
881 | { | 884 | { |
882 | unsigned char *copyto; | 885 | unsigned char *copyto; |
883 | 886 | ||
@@ -893,21 +896,21 @@ static bool entry_assign_name(struct dircache_entry *ce, | |||
893 | else | 896 | else |
894 | { | 897 | { |
895 | if (size > DC_MAX_NAME) | 898 | if (size > DC_MAX_NAME) |
896 | size = DC_MAX_NAME; | 899 | return -ENAMETOOLONG; |
897 | 900 | ||
898 | int nameidx = alloc_name(size); | 901 | int nameidx = alloc_name(size); |
899 | if (!nameidx) | 902 | if (!nameidx) |
900 | return false; | 903 | return -ENOSPC; |
901 | 904 | ||
902 | copyto = get_name(nameidx); | 905 | copyto = get_name(nameidx); |
903 | 906 | ||
904 | ce->tinyname = 0; | 907 | ce->tinyname = 0; |
905 | ce->name = nameidx; | 908 | ce->name = nameidx; |
906 | ce->length = size; | 909 | ce->namelen = NAMESIZE_CE(size); |
907 | } | 910 | } |
908 | 911 | ||
909 | memcpy(copyto, name, size); | 912 | memcpy(copyto, name, size); |
910 | return true; | 913 | return 0; |
911 | } | 914 | } |
912 | 915 | ||
913 | /** | 916 | /** |
@@ -915,17 +918,20 @@ static bool entry_assign_name(struct dircache_entry *ce, | |||
915 | */ | 918 | */ |
916 | static void entry_unassign_name(struct dircache_entry *ce) | 919 | static void entry_unassign_name(struct dircache_entry *ce) |
917 | { | 920 | { |
918 | if (!ce->tinyname) | 921 | if (ce->tinyname) |
919 | free_name(ce->name, ce->length); | 922 | return; |
923 | |||
924 | free_name(ce->name, CE_NAMESIZE(ce->namelen)); | ||
925 | ce->tinyname = 1; | ||
920 | } | 926 | } |
921 | 927 | ||
922 | /** | 928 | /** |
923 | * assign a new name to the entry | 929 | * assign a new name to the entry |
924 | */ | 930 | */ |
925 | static bool entry_reassign_name(struct dircache_entry *ce, | 931 | static int entry_reassign_name(struct dircache_entry *ce, |
926 | const unsigned char *newname) | 932 | const unsigned char *newname) |
927 | { | 933 | { |
928 | size_t oldlen = ce->tinyname ? 0 : ce->length; | 934 | size_t oldlen = ce->tinyname ? 0 : CE_NAMESIZE(ce->namelen); |
929 | size_t newlen = strlen(newname); | 935 | size_t newlen = strlen(newname); |
930 | 936 | ||
931 | if (oldlen == newlen || (oldlen == 0 && newlen <= MAX_TINYNAME)) | 937 | if (oldlen == newlen || (oldlen == 0 && newlen <= MAX_TINYNAME)) |
@@ -934,7 +940,7 @@ static bool entry_reassign_name(struct dircache_entry *ce, | |||
934 | newname, newlen); | 940 | newname, newlen); |
935 | if (newlen < MAX_TINYNAME) | 941 | if (newlen < MAX_TINYNAME) |
936 | *p = '\0'; | 942 | *p = '\0'; |
937 | return true; | 943 | return 0; |
938 | } | 944 | } |
939 | 945 | ||
940 | /* needs a new name allocation; if the new name fits in the freed block, | 946 | /* needs a new name allocation; if the new name fits in the freed block, |
@@ -968,7 +974,7 @@ static int alloc_entry(struct dircache_entry **res) | |||
968 | { | 974 | { |
969 | dircache.last_size = 0; | 975 | dircache.last_size = 0; |
970 | *res = NULL; | 976 | *res = NULL; |
971 | return 0; | 977 | return -ENOSPC; |
972 | } | 978 | } |
973 | 979 | ||
974 | dircache.sizeused += ENTRYSIZE; | 980 | dircache.sizeused += ENTRYSIZE; |
@@ -976,7 +982,7 @@ static int alloc_entry(struct dircache_entry **res) | |||
976 | ce->next = 0; | 982 | ce->next = 0; |
977 | ce->up = 0; | 983 | ce->up = 0; |
978 | ce->down = 0; | 984 | ce->down = 0; |
979 | ce->length = 0; | 985 | ce->tinyname = 1; |
980 | ce->frontier = FRONTIER_SETTLED; | 986 | ce->frontier = FRONTIER_SETTLED; |
981 | ce->serialnum = next_serialnum(); | 987 | ce->serialnum = next_serialnum(); |
982 | 988 | ||
@@ -1030,19 +1036,20 @@ static int create_entry(const char *basename, | |||
1030 | struct dircache_entry **res) | 1036 | struct dircache_entry **res) |
1031 | { | 1037 | { |
1032 | int idx = alloc_entry(res); | 1038 | int idx = alloc_entry(res); |
1033 | if (!idx) | ||
1034 | { | ||
1035 | logf("size limit reached (entry)"); | ||
1036 | return 0; /* full */ | ||
1037 | } | ||
1038 | 1039 | ||
1039 | if (!entry_assign_name(*res, basename, strlen(basename))) | 1040 | if (idx > 0) |
1040 | { | 1041 | { |
1041 | free_orphan_entry(NULL, *res, idx); | 1042 | int rc = entry_assign_name(*res, basename, strlen(basename)); |
1042 | logf("size limit reached (name)"); | 1043 | if (rc < 0) |
1043 | return 0; /* really full! */ | 1044 | { |
1045 | free_orphan_entry(NULL, *res, idx); | ||
1046 | idx = rc; | ||
1047 | } | ||
1044 | } | 1048 | } |
1045 | 1049 | ||
1050 | if (idx == -ENOSPC) | ||
1051 | logf("size limit reached"); | ||
1052 | |||
1046 | return idx; | 1053 | return idx; |
1047 | } | 1054 | } |
1048 | 1055 | ||
@@ -1304,8 +1311,15 @@ static void sab_process_sub(struct sab *sabp) | |||
1304 | } | 1311 | } |
1305 | 1312 | ||
1306 | int idx = create_entry(fatentp->name, &ce); | 1313 | int idx = create_entry(fatentp->name, &ce); |
1307 | if (!idx) | 1314 | if (idx <= 0) |
1308 | { | 1315 | { |
1316 | if (idx == -ENAMETOOLONG) | ||
1317 | { | ||
1318 | /* not fatal; just don't include it */ | ||
1319 | establish_frontier(compp->idx, FRONTIER_ZONED); | ||
1320 | continue; | ||
1321 | } | ||
1322 | |||
1309 | sabp->quit = true; | 1323 | sabp->quit = true; |
1310 | break; | 1324 | break; |
1311 | } | 1325 | } |
@@ -2328,7 +2342,7 @@ void dircache_fileop_create(struct file_base_info *dirinfop, | |||
2328 | 2342 | ||
2329 | struct dircache_entry *ce; | 2343 | struct dircache_entry *ce; |
2330 | int idx = create_entry(basename, &ce); | 2344 | int idx = create_entry(basename, &ce); |
2331 | if (idx == 0) | 2345 | if (idx <= 0) |
2332 | { | 2346 | { |
2333 | /* failed allocation; parent cache contents are not complete */ | 2347 | /* failed allocation; parent cache contents are not complete */ |
2334 | establish_frontier(dirinfop->dcfile.idx, FRONTIER_ZONED); | 2348 | establish_frontier(dirinfop->dcfile.idx, FRONTIER_ZONED); |
@@ -2427,7 +2441,7 @@ void dircache_fileop_rename(struct file_base_info *dirinfop, | |||
2427 | insert_file_entry(dirinfop, ce); | 2441 | insert_file_entry(dirinfop, ce); |
2428 | 2442 | ||
2429 | /* lastly, update the entry name itself */ | 2443 | /* lastly, update the entry name itself */ |
2430 | if (entry_reassign_name(ce, basename)) | 2444 | if (entry_reassign_name(ce, basename) == 0) |
2431 | { | 2445 | { |
2432 | /* it's not really the same one now so re-stamp it */ | 2446 | /* it's not really the same one now so re-stamp it */ |
2433 | dc_serial_t serialnum = next_serialnum(); | 2447 | dc_serial_t serialnum = next_serialnum(); |
@@ -2506,7 +2520,7 @@ static ssize_t get_path_sub(int idx, struct get_path_sub_data *data) | |||
2506 | if (len < 0) | 2520 | if (len < 0) |
2507 | return -2; | 2521 | return -2; |
2508 | 2522 | ||
2509 | cename = alloca(MAX_NAME + 1); | 2523 | cename = alloca(DC_MAX_NAME + 1); |
2510 | entry_name_copy(cename, ce); | 2524 | entry_name_copy(cename, ce); |
2511 | } | 2525 | } |
2512 | else /* idx < 0 */ | 2526 | else /* idx < 0 */ |
diff --git a/firmware/common/file_internal.c b/firmware/common/file_internal.c index 8fee802f6f..a109563092 100644 --- a/firmware/common/file_internal.c +++ b/firmware/common/file_internal.c | |||
@@ -505,7 +505,7 @@ walk_path(struct pathwalk *walkp, struct pathwalk_component *compp, | |||
505 | if (!(compp->attr & ATTR_DIRECTORY)) | 505 | if (!(compp->attr & ATTR_DIRECTORY)) |
506 | return -ENOTDIR; | 506 | return -ENOTDIR; |
507 | 507 | ||
508 | if (len >= MAX_NAME) | 508 | if (len > MAX_COMPNAME) |
509 | return -ENAMETOOLONG; | 509 | return -ENAMETOOLONG; |
510 | 510 | ||
511 | /* check for "." and ".." */ | 511 | /* check for "." and ".." */ |
diff --git a/firmware/include/file_internal.h b/firmware/include/file_internal.h index bb1236aed1..5893737833 100644 --- a/firmware/include/file_internal.h +++ b/firmware/include/file_internal.h | |||
@@ -56,7 +56,7 @@ | |||
56 | root + 'Music' + 'Artist' + 'Album' + 'Disc N' + filename */ | 56 | root + 'Music' + 'Artist' + 'Album' + 'Disc N' + filename */ |
57 | #define STATIC_PATHCOMP_NUM 6 | 57 | #define STATIC_PATHCOMP_NUM 6 |
58 | 58 | ||
59 | #define MAX_NAME 255 | 59 | #define MAX_COMPNAME 260 |
60 | 60 | ||
61 | /* unsigned value that will also hold the off_t range we need without | 61 | /* unsigned value that will also hold the off_t range we need without |
62 | overflow */ | 62 | overflow */ |