1 /*
2 * Copyright (C) 2017 National Institute of Advanced Industrial Science
3 * and Technology (AIST)
4 *
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are met:
9 *
10 * Redistributions of source code must retain the above copyright notice, this
11 * list of conditions and the following disclaimer.
12 *
13 * Redistributions in binary form must reproduce the above copyright notice,
14 * this list of conditions and the following disclaimer in the documentation
15 * and/or other materials provided with the distribution.
16 *
17 * Neither the name of AIST nor the names of its contributors may be used
18 * to endorse or promote products derived from this software without specific
19 * prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
25 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
32 */
33
34 #include <libwebsockets.h>
35 #include <string.h>
36 #include <stdint.h>
37 #include <stdio.h>
38 #include "romfs.h"
39 #if defined(LWS_WITH_ESP32)
40 #include "esp_spi_flash.h"
41 #endif
42
43 #define RFS_STRING_MAX 96
44
45 static u32_be_t cache[(RFS_STRING_MAX + 32) / 4];
46 static romfs_inode_t ci = (romfs_inode_t)cache;
47 static romfs_t cr = (romfs_t)cache;
48
49 static void
set_cache(romfs_inode_t inode,size_t len)50 set_cache(romfs_inode_t inode, size_t len)
51 {
52 #if defined(LWS_WITH_ESP32)
53 spi_flash_read((uint32_t)inode, cache, len);
54 #endif
55 }
56
57 static uint32_t
untohl(const u32_be_t be)58 untohl(const u32_be_t be)
59 {
60 return ((be >> 24) & 0xff) |
61 ((be >> 16) & 0xff) << 8 |
62 ((be >> 8) & 0xff) << 16 |
63 (be & 0xff) << 24;
64 }
65 static romfs_inode_t
66 romfs_lookup(romfs_t romfs, romfs_inode_t start, const char *path);
67
68 static int
plus_padding(const uint8_t * s)69 plus_padding(const uint8_t *s)
70 {
71 int n;
72
73 set_cache((romfs_inode_t)s, RFS_STRING_MAX);
74 n = strlen((const char *)cache);
75
76 if (!(n & 15))
77 n += 0x10;
78
79 return (n + 15) & ~15;
80 }
81
82 static romfs_inode_t
skip_and_pad(romfs_inode_t ri)83 skip_and_pad(romfs_inode_t ri)
84 {
85 const uint8_t *p = ((const uint8_t *)ri) + sizeof(*ri);
86
87 return (romfs_inode_t)(p + plus_padding(p));
88 }
89
90 size_t
romfs_mount_check(romfs_t romfs)91 romfs_mount_check(romfs_t romfs)
92 {
93 set_cache((romfs_inode_t)romfs, sizeof(*romfs));
94
95 if (cr->magic1 != 0x6d6f722d ||
96 cr->magic2 != 0x2d736631)
97 return 0;
98
99 return untohl(cr->size);
100 }
101
102 static romfs_inode_t
romfs_symlink(romfs_t romfs,romfs_inode_t level,romfs_inode_t i)103 romfs_symlink(romfs_t romfs, romfs_inode_t level, romfs_inode_t i)
104 {
105 const char *p = (const char *)skip_and_pad(i);
106
107 if (*p == '/') {
108 level = skip_and_pad((romfs_inode_t)romfs);
109 p++;
110 }
111
112 return romfs_lookup(romfs, level, p);
113 }
114
115 static romfs_inode_t
dir_link(romfs_t romfs,romfs_inode_t i)116 dir_link(romfs_t romfs, romfs_inode_t i)
117 {
118 set_cache(i, sizeof(*i));
119 return (romfs_inode_t)((const uint8_t *)romfs +
120 untohl(ci->dir_start));
121 }
122
123 static romfs_inode_t
romfs_lookup(romfs_t romfs,romfs_inode_t start,const char * path)124 romfs_lookup(romfs_t romfs, romfs_inode_t start, const char *path)
125 {
126 romfs_inode_t level, i = start, i_in;
127 const char *p, *cp;
128 uint32_t next_be;
129
130 if (start == (romfs_inode_t)romfs)
131 i = skip_and_pad((romfs_inode_t)romfs);
132 level = i;
133 while (i != (romfs_inode_t)romfs) {
134 const char *n = ((const char *)i) + sizeof(*i);
135
136 p = path;
137 i_in = i;
138
139 set_cache(i, sizeof(*i));
140 next_be = ci->next;
141
142 cp = (const char *)cache;
143 set_cache((romfs_inode_t)n, RFS_STRING_MAX);
144
145 while (*p && *p != '/' && *cp && *p == *cp &&
146 (p - path) < RFS_STRING_MAX) {
147 p++;
148 n++;
149 cp++;
150 }
151
152 while (*p == '/' && p[1] == '/')
153 p++;
154
155 if (!*cp && (!*p || *p == '/') &&
156 (untohl(next_be) & 7) == RFST_HARDLINK) {
157 set_cache(i, sizeof(*i));
158 return (romfs_inode_t)
159 ((const uint8_t *)romfs +
160 (untohl(ci->dir_start) & ~15));
161 }
162
163 if (!*p && !*cp) {
164 set_cache(i, sizeof(*i));
165 if ((untohl(ci->next) & 7) == RFST_SYMLINK) {
166 i = romfs_symlink(romfs, level, i);
167 continue;
168 }
169 return i;
170 }
171
172 if (!*p && *cp == '/')
173 return NULL;
174
175 while (*p == '/' && p[1] == '/')
176 p++;
177
178 if (*p == '/' && !*cp) {
179 set_cache(i, sizeof(*i));
180 switch (untohl(ci->next) & 7) {
181 case RFST_SYMLINK:
182 i = romfs_symlink(romfs, level, i);
183 if (!i)
184 return NULL;
185 i = dir_link(romfs, i);
186 while (*path != '/' && *path)
187 path++;
188 if (!*path)
189 return NULL;
190 path++;
191 continue;
192 case RFST_DIR:
193 path = p + 1;
194 i = dir_link(romfs, i);
195 break;
196 default:
197 path = p + 1;
198 i = skip_and_pad(i);
199 break;
200 }
201 level = i;
202 continue;
203 }
204
205 set_cache(i, sizeof(*i));
206 if (!(untohl(ci->next) & ~15))
207 return NULL;
208
209 i = (romfs_inode_t)((const uint8_t *)romfs +
210 (untohl(ci->next) & ~15));
211 if (i == i_in)
212 return NULL;
213 }
214
215 return NULL;
216 }
217
218 const void *
romfs_get_info(romfs_t romfs,const char * path,size_t * len,size_t * csum)219 romfs_get_info(romfs_t romfs, const char *path, size_t *len, size_t *csum)
220 {
221 romfs_inode_t i;
222
223 if (*path == '/')
224 path++;
225
226 i = romfs_lookup(romfs, (romfs_inode_t)romfs, path);
227
228 if (!i)
229 return NULL;
230
231 set_cache(i, sizeof(*i));
232 *len = untohl(ci->size);
233 if (csum)
234 *csum = untohl(ci->checksum);
235
236 return (void *)skip_and_pad(i);
237 }
238