Skip to content

Commit 39faf9f

Browse files
committed
Also serialize Adafruit_LittleFS_File.
This solution appears to work. However, it does not follow all best practices. For example, the use of friend declarations, and the need to make the lock/unlock functions in File public (in order to get friend status). However, it passes the stress test without errors.
1 parent 35b5d4b commit 39faf9f

File tree

4 files changed

+211
-62
lines changed

4 files changed

+211
-62
lines changed

libraries/Adafruit_LittleFS/src/Adafruit_LittleFS.cpp

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -121,10 +121,8 @@ bool Adafruit_LittleFS::format (void)
121121
// Open a file or folder
122122
Adafruit_LittleFS_Namespace::File Adafruit_LittleFS::open (char const *filepath, uint8_t mode)
123123
{
124-
xSemaphoreTake(_mutex, portMAX_DELAY);
125-
Adafruit_LittleFS_Namespace::File ret = Adafruit_LittleFS_Namespace::File(filepath, mode, *this);
126-
xSemaphoreGive(_mutex);
127-
return ret;
124+
// No lock is required here ... the File() object will synchronize with the mutex provided
125+
return Adafruit_LittleFS_Namespace::File(filepath, mode, *this);
128126
}
129127

130128
// Check if file or folder exists

libraries/Adafruit_LittleFS/src/Adafruit_LittleFS.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,9 @@ class Adafruit_LittleFS
7777
struct lfs_config* _lfs_cfg;
7878
lfs_t _lfs;
7979

80+
// these two functions need access to the private _mutex variable:
81+
friend void Adafruit_LittleFS_Namespace::File::DoNotCallFromOutsideClass_LockFilesystem(void);
82+
friend void Adafruit_LittleFS_Namespace::File::DoNotCallFromOutsideClass_UnlockFilesystem(void);
8083
//static_assert(configSUPPORT_STATIC_ALLOCATION == 1, "Currently only supports configuration with STATIC_ALLOCATION enabled");
8184
SemaphoreHandle_t _mutex;
8285

libraries/Adafruit_LittleFS/src/Adafruit_LittleFS_File.cpp

Lines changed: 189 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -46,9 +46,20 @@ File::File (Adafruit_LittleFS &fs)
4646
File::File (char const *filename, uint8_t mode, Adafruit_LittleFS &fs)
4747
: File(fs)
4848
{
49+
// public constructor calls public API open(), which will obtain the mutex
4950
this->open(filename, mode);
5051
}
5152

53+
File::File (uint8_t differentiator, char const *filename, uint8_t mode, Adafruit_LittleFS &fs)
54+
: File(fs)
55+
{
56+
// private constructor calls private API _open(), which does NOT obtain the mutex
57+
(void)differentiator;
58+
this->_open(filename, mode);
59+
}
60+
61+
62+
5263
bool File::_open_file (char const *filepath, uint8_t mode)
5364
{
5465
int flags = (mode == FILE_O_READ) ? LFS_O_RDONLY :
@@ -99,12 +110,23 @@ bool File::_open_dir (char const *filepath)
99110
return true;
100111
}
101112

113+
// TODO: wrap close() because it must be called by open()
114+
// TODO: wrap open() because it is called by openNextFile()
115+
102116
bool File::open (char const *filepath, uint8_t mode)
117+
{
118+
bool ret = false;
119+
this->DoNotCallFromOutsideClass_LockFilesystem();
120+
ret = this->_open(filepath, mode);
121+
this->DoNotCallFromOutsideClass_UnlockFilesystem();
122+
return ret;
123+
}
124+
bool File::_open (char const *filepath, uint8_t mode)
103125
{
104126
bool ret = false;
105127

106128
// close if currently opened
107-
if ( (*this) ) close();
129+
if ( this->_isOpen() ) _close();
108130

109131
struct lfs_info info;
110132
int rc = lfs_stat(_fs->getFS(), filepath, &info);
@@ -130,151 +152,260 @@ bool File::open (char const *filepath, uint8_t mode)
130152
char const* splash = strrchr(filepath, '/');
131153
strncpy(_name, splash ? (splash + 1) : filepath, LFS_NAME_MAX);
132154
}
133-
134155
return ret;
135156
}
136157

137158
size_t File::write (uint8_t ch)
138159
{
139-
VERIFY(!_is_dir, 0);
140160
return write(&ch, 1);
141161
}
142162

143163
size_t File::write (uint8_t const *buf, size_t size)
144164
{
145-
VERIFY(!_is_dir, 0);
146-
147-
lfs_ssize_t wrcount = lfs_file_write(_fs->getFS(), _file, buf, size);
148-
VERIFY(wrcount > 0, 0);
165+
lfs_ssize_t wrcount = 0;
166+
this->DoNotCallFromOutsideClass_LockFilesystem();
167+
if (!this->_is_dir)
168+
{
169+
wrcount = lfs_file_write(_fs->getFS(), _file, buf, size);
170+
if (wrcount < 0)
171+
{
172+
wrcount = 0;
173+
};
174+
}
175+
this->DoNotCallFromOutsideClass_UnlockFilesystem();
149176
return wrcount;
150177
}
151178

152179
int File::read (void)
153180
{
154-
VERIFY(!_is_dir, -1);
181+
// this thin wrapper relies on called function to synchronize
182+
int ret = -1;
155183
uint8_t ch;
156-
return (read(&ch, 1) > 0) ? ch : -1;
184+
if (read(&ch, 1) > 0)
185+
{
186+
ret = static_cast<int>(ch);
187+
}
188+
return ret;
157189
}
158190

159191
int File::read (void *buf, uint16_t nbyte)
160192
{
161-
VERIFY(!_is_dir, 0);
162-
return lfs_file_read(_fs->getFS(), _file, buf, nbyte);
193+
int ret = 0;
194+
this->DoNotCallFromOutsideClass_LockFilesystem();
195+
if (!this->_is_dir)
196+
{
197+
ret = lfs_file_read(_fs->getFS(), _file, buf, nbyte);
198+
}
199+
this->DoNotCallFromOutsideClass_UnlockFilesystem();
200+
return ret;
163201
}
164202

165203
int File::peek (void)
166204
{
167-
VERIFY(!_is_dir, -1);
168-
169-
int ch = read();
170-
uint32_t pos = position();
171-
seek((pos > 0) ? (pos - 1) : 0);
172-
return ch;
205+
int ret = -1;
206+
this->DoNotCallFromOutsideClass_LockFilesystem();
207+
if (!this->_is_dir)
208+
{
209+
uint32_t pos = lfs_file_tell(_fs->getFS(), _file);
210+
uint8_t ch = 0;
211+
if (lfs_file_read(_fs->getFS(), _file, &ch, 1) > 0)
212+
{
213+
ret = static_cast<int>(ch);
214+
}
215+
(void)lfs_file_seek(_fs->getFS(), _file, pos, LFS_SEEK_SET);
216+
}
217+
this->DoNotCallFromOutsideClass_UnlockFilesystem();
218+
return ret;
173219
}
174220

175221
int File::available (void)
176222
{
177-
return size() - position();
223+
int ret = 0;
224+
this->DoNotCallFromOutsideClass_LockFilesystem();
225+
if (!this->_is_dir)
226+
{
227+
uint32_t size = lfs_file_size(_fs->getFS(), _file);
228+
uint32_t pos = lfs_file_tell(_fs->getFS(), _file);
229+
ret = size - pos;
230+
}
231+
this->DoNotCallFromOutsideClass_UnlockFilesystem();
232+
return ret;
178233
}
179234

180235
bool File::seek (uint32_t pos)
181236
{
182-
VERIFY(!_is_dir, false);
183-
return lfs_file_seek(_fs->getFS(), _file, pos, LFS_SEEK_SET) >= 0;
237+
bool ret = false;
238+
this->DoNotCallFromOutsideClass_LockFilesystem();
239+
if (!this->_is_dir)
240+
{
241+
ret = lfs_file_seek(_fs->getFS(), _file, pos, LFS_SEEK_SET) >= 0;
242+
}
243+
this->DoNotCallFromOutsideClass_UnlockFilesystem();
244+
return ret;
184245
}
185246

186247
uint32_t File::position (void)
187248
{
188-
VERIFY(!_is_dir, 0);
189-
return lfs_file_tell(_fs->getFS(), _file);
249+
uint32_t ret = 0;
250+
this->DoNotCallFromOutsideClass_LockFilesystem();
251+
if (!this->_is_dir)
252+
{
253+
ret = lfs_file_tell(_fs->getFS(), _file);
254+
}
255+
this->DoNotCallFromOutsideClass_UnlockFilesystem();
256+
return ret;
190257
}
191258

192259
uint32_t File::size (void)
193260
{
194-
VERIFY(!_is_dir, 0);
195-
return lfs_file_size(_fs->getFS(), _file);
261+
uint32_t ret = 0;
262+
this->DoNotCallFromOutsideClass_LockFilesystem();
263+
if (!this->_is_dir)
264+
{
265+
ret = lfs_file_size(_fs->getFS(), _file);
266+
}
267+
this->DoNotCallFromOutsideClass_UnlockFilesystem();
268+
return ret;
269+
196270
}
197271

198272
void File::flush (void)
199273
{
200-
VERIFY(!_is_dir,);
201-
lfs_file_sync(_fs->getFS(), _file);
274+
this->DoNotCallFromOutsideClass_LockFilesystem();
275+
if (!this->_is_dir)
276+
{
277+
lfs_file_sync(_fs->getFS(), _file);
278+
}
279+
this->DoNotCallFromOutsideClass_UnlockFilesystem();
280+
return;
202281
}
203282

204283
void File::close (void)
205284
{
206-
if ( (*this) )
285+
this->DoNotCallFromOutsideClass_LockFilesystem();
286+
this->_close();
287+
this->DoNotCallFromOutsideClass_UnlockFilesystem();
288+
}
289+
void File::_close(void)
290+
{
291+
if ( this->_isOpen() )
207292
{
208-
if ( _is_dir )
293+
if ( this->_is_dir )
209294
{
210295
lfs_dir_close(_fs->getFS(), _dir);
211296
rtos_free(_dir);
212297
_dir = NULL;
213298

214-
if ( _dir_path ) rtos_free(_dir_path);
299+
if ( this->_dir_path ) rtos_free(_dir_path);
215300
_dir_path = NULL;
216301
}
217302
else
218303
{
219-
lfs_file_close(_fs->getFS(), _file);
304+
lfs_file_close(this->_fs->getFS(), _file);
220305
rtos_free(_file);
221306
_file = NULL;
222307
}
223308
}
224309
}
225310

311+
[[deprecated("Recommend use of isOpen() for clarity")]]
226312
File::operator bool (void)
313+
{
314+
bool ret = false;
315+
this->DoNotCallFromOutsideClass_LockFilesystem();
316+
ret = this->_isOpen();
317+
this->DoNotCallFromOutsideClass_UnlockFilesystem();
318+
return ret;
319+
}
320+
bool File::isOpen(void)
321+
{
322+
bool ret = 0;
323+
this->DoNotCallFromOutsideClass_LockFilesystem();
324+
ret = this->_isOpen();
325+
this->DoNotCallFromOutsideClass_UnlockFilesystem();
326+
return ret;
327+
}
328+
bool File::_isOpen(void)
227329
{
228330
return (_file != NULL) || (_dir != NULL);
229331
}
230332

333+
// WARNING -- although marked as `const`, the values pointed
334+
// to may change. For example, if the same File
335+
// object has `open()` called with a different
336+
// file or directory name, this same pointer will
337+
// suddenly (unexpectedly?) have different values.
231338
char const* File::name (void)
232339
{
233-
return _name;
340+
this->DoNotCallFromOutsideClass_LockFilesystem();
341+
char const* ret = this->_name;
342+
this->DoNotCallFromOutsideClass_UnlockFilesystem();
343+
return ret;
234344
}
235345

236346
bool File::isDirectory (void)
237347
{
238-
return _is_dir;
348+
this->DoNotCallFromOutsideClass_LockFilesystem();
349+
bool ret = this->_is_dir;
350+
this->DoNotCallFromOutsideClass_UnlockFilesystem();
351+
return ret;
352+
239353
}
240354

241355
File File::openNextFile (uint8_t mode)
242356
{
243-
File file(*_fs);
244-
245-
if ( !_is_dir ) return file;
246-
247-
struct lfs_info info;
248-
249-
int rc;
357+
this->DoNotCallFromOutsideClass_LockFilesystem();
250358

251-
// lfs_dir_read return 0 when reaching end of directory, 1 if found an entry
252-
// skip "." and ".." entries
253-
do
359+
File ret(*_fs);
360+
if (this->_is_dir)
254361
{
255-
rc = lfs_dir_read(_fs->getFS(), _dir, &info);
256-
} while ( rc == 1 && (!strcmp(".", info.name) || !strcmp("..", info.name)) );
362+
struct lfs_info info;
363+
int rc;
257364

258-
if ( rc == 1 )
259-
{
260-
// string cat name with current folder
261-
char filepath[strlen(_dir_path) + 1 + strlen(info.name) + 1];
365+
// lfs_dir_read returns 0 when reaching end of directory, 1 if found an entry
366+
// Skip the "." and ".." entries ...
367+
do
368+
{
369+
rc = lfs_dir_read(_fs->getFS(), _dir, &info);
370+
} while ( rc == 1 && (!strcmp(".", info.name) || !strcmp("..", info.name)) );
262371

263-
strcpy(filepath, _dir_path);
264-
if ( !(_dir_path[0] == '/' && _dir_path[1] == 0) ) strcat(filepath, "/"); // only add '/' if cwd is not root
265-
strcat(filepath, info.name);
372+
if ( rc == 1 )
373+
{
374+
// string cat name with current folder
375+
char filepath[strlen(_dir_path) + 1 + strlen(info.name) + 1]; // potential for significant stack usage
376+
strcpy(filepath, _dir_path);
377+
if ( !(_dir_path[0] == '/' && _dir_path[1] == 0) ) strcat(filepath, "/"); // only add '/' if cwd is not root
378+
strcat(filepath, info.name);
266379

267-
file.open(filepath, mode);
380+
(void)ret._open(filepath, mode); // return value is ignored ... caller is expected to check isOpened()
381+
}
382+
else if ( rc < 0 )
383+
{
384+
PRINT_LFS_ERR(rc);
385+
}
268386
}
269-
else if ( rc < 0 )
387+
this->DoNotCallFromOutsideClass_UnlockFilesystem();
388+
return ret;
389+
}
390+
391+
void File::rewindDirectory (void)
392+
{
393+
this->DoNotCallFromOutsideClass_LockFilesystem();
394+
if (this->_is_dir)
270395
{
271-
PRINT_LFS_ERR(rc);
396+
lfs_dir_rewind(_fs->getFS(), _dir);
272397
}
273-
274-
return file;
398+
this->DoNotCallFromOutsideClass_UnlockFilesystem();
399+
return;
275400
}
276401

277-
void File::rewindDirectory (void)
402+
void File::DoNotCallFromOutsideClass_LockFilesystem(void)
278403
{
279-
VERIFY_LFS(lfs_dir_rewind(_fs->getFS(), _dir),);
404+
xSemaphoreTake(this->_fs->_mutex, portMAX_DELAY);
280405
}
406+
void File::DoNotCallFromOutsideClass_UnlockFilesystem(void)
407+
{
408+
xSemaphoreGive(this->_fs->_mutex);
409+
}
410+
411+

0 commit comments

Comments
 (0)