Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit ef49605

Browse files
committedApr 10, 2024
- fix several memory leaks
- rework member variables when calling begin/umount/format (solves inconsistenies). begin() means mounting. It must not initialize the block device, as this is global to a partition. format() is only possbile when FS is not mounted (it makes no sense to call begin()/unmount(), just to get a valid mbr block device). -> rework - When creating partition object and no partition was present on block device, the members of partition object left uninitialzed. - add function to free the allocated memory that was returned when calling utils function to create a partition name. - solve problems, where block devices keept initialized when calling listPartitions(). This function could only be called two times. Other called functions failed because of the blocked resources. It now calls deinit() to leave it clean.
1 parent 30b1a52 commit ef49605

File tree

6 files changed

+126
-77
lines changed

6 files changed

+126
-77
lines changed
 

‎examples/InternalStoragePartitioning/InternalStoragePartitioning.ino

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,13 @@
44
This example demonstrates the usage of the "Arduino_UnifiedStorage" library for retrieving and creating partitions on the internal storage.
55
The code should help you understand how to work with partitions and perform file operations in different partitions.
66
7-
It creates the partitions specified in the std::vector<Partitions> you find at the top of the sketch.
7+
It creates the partitions specified in the std::vector<Partitions> you find at the top of the sketch.
88
You can define your own, as long as the size of all partitions doesn't exceed the size of your board's QSPI flash( if you are in doubt about that check docs.arduino.com for more information) and as long as you don't have more than 4 partitions (MBR limitation)
99
The Partition struct has two values:
1010
- `size` the size of your partition in kilobytes
1111
- 'fileSystemType` which can be either `FS_FAT` or `FS_LITTLEFS`
1212
13-
Here are a few examples of valid partitioning schemes:
13+
Here are a few examples of valid partitioning schemes:
1414
- std::vector<Partition> partitioningScheme = {{16384, FS_FAT}};
1515
- std::vector<Partition> partitioningScheme = {{2048, FS_FAT}, {6144, FS_FAT} {8192, FS_LITTLEFS}};
1616
- std::vector<Partition> partitioningScheme = {{4096, FS_LITTLEFS}, {4096, FS_FAT}, {4096, FS_LITTLEFS}, {4096, FS_FAT}};
@@ -24,8 +24,8 @@
2424
INSTRUCTIONS:
2525
1. Check compatibility with your board and make sure you have "POSIXStorage" and "Arduino_UnifiedStorage" installed
2626
2. Connect your board to the serial monitor
27-
3. Wait for the sketch to run
28-
4. Modify the partitioning scheme according to your needs
27+
3. Wait for the sketch to run
28+
4. Modify the partitioning scheme according to your needs
2929
3030
Created: 26th October 2023
3131
By: Cristian Dragomir
@@ -36,7 +36,7 @@
3636
#include <vector>
3737

3838
// Create a vector of partitions with one partition of 16MB using LittleFS
39-
std::vector<Partition> partitioningScheme = {
39+
std::vector<Partition> partitioningScheme = {
4040
{1024, FS_FAT}, // 1 MB for certificates
4141
{5120, FS_FAT}, // 5 MB for OTA firmware updates
4242
{8192, FS_LITTLEFS} // 8 MB for user data
@@ -50,7 +50,7 @@ void testWriting(Arduino_UnifiedStorage *storage) {
5050
// Create a new file named "file.txt" for writing
5151
UFile file = root.createFile("file.txt", FileMode::WRITE);
5252
Serial.println("\t\t - File path: " + file.getPathAsString());
53-
53+
5454
// Write data to the file
5555
file.write("writing stuff to the file");
5656

@@ -65,7 +65,7 @@ void testWriting(Arduino_UnifiedStorage *storage) {
6565
void testAllPartitions(std::vector<Partition> partitions) {
6666
for (size_t i = 1; i < partitions.size() + 1; ++i) {
6767
const char *partitionName = createPartitionName(i);
68-
68+
6969
// Create an InternalStorage object for the partition
7070
InternalStorage thisPartition = InternalStorage(i, partitionName, partitions[i - 1].fileSystemType);
7171

@@ -74,6 +74,8 @@ void testAllPartitions(std::vector<Partition> partitions) {
7474
Serial.println("\t - Successfully mounted partition: /" + String(partitionName));
7575
Serial.println("\t - Testing file operations: ");
7676
testWriting(&thisPartition); // Test writing to a file in the partition
77+
thisPartition.unmount();
78+
freePartitionName(partitionName);
7779
}
7880

7981
Serial.println();
@@ -113,7 +115,7 @@ void setup() {
113115

114116
delay(1000);
115117

116-
// Read the MBR sector and display the partitions
118+
// Read the MBR sector and display the partitions
117119
listPartitions();
118120
}
119121

‎library.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
name=Arduino_UnifiedStorage
2-
version=1.1.1
2+
version=1.1.2
33
author=Arduino
44
maintainer=Arduino <info@arduino.cc>
55
sentence=Simplify cross-device storage management on Portenta platforms with a single library supporting SD, Flash, and USB storage access.

‎src/InternalStorage.cpp

Lines changed: 40 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2,25 +2,37 @@
22

33
InternalStorage::InternalStorage(){
44
std::vector<Partition> partitionsAvailable = Partitioning::readPartitions(QSPIFBlockDeviceType::get_default_instance());
5-
if(partitionsAvailable.size() == 0){
5+
if(partitionsAvailable.size() == 0)
6+
{
67

78
//Arduino_UnifiedStorage::debugPrint("[InternalStorage][INFO] No partitions found, restoring default partitions");
89
restoreDefaultPartitions();
9-
} else {
10-
int lastPartitionNumber = partitionsAvailable.size();
11-
FileSystems lastPartitionFileSystem = partitionsAvailable.back().fileSystemType;
12-
//Arduino_UnifiedStorage::debugPrint("[InternalStorage][INFO] Found " + String(lastPartitionNumber) + " partitions, using last partition as internal storage");
13-
14-
this -> partitionNumber = lastPartitionNumber;
15-
this -> fileSystemType = lastPartitionFileSystem;
16-
this -> partitionName = (char *)"internal";
10+
// re-read table
11+
partitionsAvailable = Partitioning::readPartitions(QSPIFBlockDeviceType::get_default_instance());
1712
}
13+
14+
int lastPartitionNumber = partitionsAvailable.size();
15+
FileSystems lastPartitionFileSystem = partitionsAvailable.back().fileSystemType;
16+
//Arduino_UnifiedStorage::debugPrint("[InternalStorage][INFO] Found " + String(lastPartitionNumber) + " partitions, using last partition as internal storage");
17+
18+
this -> partitionNumber = lastPartitionNumber;
19+
this -> fileSystemType = lastPartitionFileSystem;
20+
this -> partitionName = (char *)"internal";
21+
this -> blockDevice = BlockDeviceType::get_default_instance();
22+
this -> mbrBlockDevice = new MBRBlockDeviceType(this -> blockDevice, this->partitionNumber);
1823
}
1924

2025
InternalStorage::InternalStorage(int partition, const char * name, FileSystems fileSystemType){
2126
this -> partitionNumber = partition;
22-
this -> partitionName = (char *)name;
27+
this -> partitionName = name;
2328
this -> fileSystemType = fileSystemType;
29+
this -> blockDevice = BlockDeviceType::get_default_instance();
30+
this -> mbrBlockDevice = new MBRBlockDeviceType(this -> blockDevice, this->partitionNumber);
31+
}
32+
33+
InternalStorage::~InternalStorage()
34+
{
35+
delete this -> mbrBlockDevice;
2436
}
2537

2638
bool InternalStorage::begin(FileSystems fileSystemType){
@@ -49,9 +61,6 @@ std::vector<Partition> InternalStorage::readPartitions(){
4961
}
5062

5163
bool InternalStorage::begin(){
52-
53-
this -> blockDevice = BlockDeviceType::get_default_instance();
54-
this -> mbrBlockDevice = new MBRBlockDeviceType(this->blockDevice, this->partitionNumber);
5564

5665
if(this -> fileSystemType == FS_FAT){
5766
this -> fileSystem = new FATFileSystemType(this->partitionName);
@@ -61,15 +70,23 @@ bool InternalStorage::begin(){
6170
Arduino_UnifiedStorage::debugPrint("[InternalStorage][begin][INFO] Mounting partition " + String(this->partitionNumber) + " as LittleFS");
6271
}
6372

64-
int err = this -> fileSystem -> mount(mbrBlockDevice);
73+
int err = this -> fileSystem -> mount(this -> mbrBlockDevice);
6574
if(err!=0){
6675
Arduino_UnifiedStorage::debugPrint("[InternalStorage][ERROR] Could not mount partition " + String(this->partitionNumber) + " as " + prettyPrintFileSystemType(this->fileSystemType) + ", error code: " + String(errno));
6776
}
6877
return err == 0;
6978
}
7079

7180
bool InternalStorage::unmount(){
72-
int err = this -> fileSystem -> unmount();
81+
int err = 0;
82+
83+
if(this -> fileSystem)
84+
{
85+
err = this -> fileSystem -> unmount();
86+
delete this -> fileSystem;
87+
this -> fileSystem = NULL;
88+
}
89+
7390
return err == 0;
7491
}
7592

@@ -78,23 +95,25 @@ Folder InternalStorage::getRootFolder(){
7895
}
7996

8097
bool InternalStorage::format(FileSystems fs){
81-
this -> begin();
98+
FileSystemType * tmpFileSystem = nullptr;
8299
this -> unmount();
83100
this -> fileSystemType = fs;
84101

85102
if(fs == FS_FAT){
86-
this -> fileSystem = new FATFileSystemType(this->partitionName);
87-
int err = this -> fileSystem -> reformat(this-> mbrBlockDevice);
103+
tmpFileSystem = new FATFileSystemType(this->partitionName);
104+
int err = tmpFileSystem -> reformat(this-> mbrBlockDevice);
88105
if(err != 0){
89106
Arduino_UnifiedStorage::debugPrint("[InternalStorage][format][ERROR] Error formatting partition " + String(this->partitionNumber) + " as FAT: " + String(errno));
90-
}
107+
}
108+
delete tmpFileSystem;
91109
return err == 0;
92110
} if (fs == FS_LITTLEFS) {
93-
this -> fileSystem = new LittleFileSystemType(this->partitionName);
94-
int err = this -> fileSystem -> reformat(this-> mbrBlockDevice);
111+
tmpFileSystem = new LittleFileSystemType(this->partitionName);
112+
int err = tmpFileSystem -> reformat(this-> mbrBlockDevice);
95113
if(err != 0){
96114
Arduino_UnifiedStorage::debugPrint("[InternalStorage][format][ERROR] Error formatting partition " + String(this->partitionNumber) + " as LittleFS: " + String(errno));
97115
}
116+
delete tmpFileSystem;
98117
return err == 0;
99118
}
100119

‎src/InternalStorage.h

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,66 +10,68 @@
1010
*/
1111
class InternalStorage : public Arduino_UnifiedStorage {
1212
public:
13-
13+
1414

1515
/**
1616
* Constructs an InternalStorage object with default settings.
1717
* If no partitions are available, it restores the default partitioning scheme (See restoreDefaultPartitions() for more info).
1818
* If partitions are available, it sets the partition number, file system type, and partition name based on the last partition available.
19-
* When using the default partitioning scheme the last partition would be the user partition.
19+
* When using the default partitioning scheme the last partition would be the user partition.
2020
*/
2121
InternalStorage();
2222

2323
/**
2424
* Constructs an InternalStorage object with the specified partition, name, and file system.
25-
*
25+
*
2626
* @param partition The partition number.
2727
* @param name The name of the partition.
2828
* @param fs The desired file system (FS_FAT or FS_LITTLEFS).
2929
*/
3030
InternalStorage(int partition, const char *name, FileSystems fs);
3131

32+
~InternalStorage();
33+
3234
/**
3335
* Initializes the internal storage.
34-
*
36+
*
3537
* @return true if successful, false if failed.
3638
*/
3739
bool begin() override;
3840

3941
/**
4042
* Initializes the internal storage with the specified file system.
41-
*
43+
*
4244
* @param fs The desired file system (FS_FAT or FS_LITTLEFS).
4345
* @return true if successful, false if failed.
4446
*/
4547
bool begin(FileSystems fs) override;
4648

4749
/**
4850
* Unmounts the internal storage.
49-
*
51+
*
5052
* @return true if successful, false if failed.
5153
*/
5254
bool unmount() override;
5355

5456
/**
5557
* Retrieves the root folder of the internal storage.
56-
*
58+
*
5759
* @return The root folder as a Folder object.
5860
*/
5961
Folder getRootFolder() override;
6062

6163

6264
/**
6365
* Formats the internal storage with the selected file system.
64-
*
66+
*
6567
* @return true if successful, false if failed.
6668
*/
6769
bool format(FileSystems fs) override;
6870

6971

7072
/**
7173
* Retrieves the block device associated with the internal storage.
72-
*
74+
*
7375
* @return The block device as a BlockDevice object.
7476
*/
7577
BlockDeviceType *getBlockDevice();
@@ -86,7 +88,7 @@ class InternalStorage : public Arduino_UnifiedStorage {
8688
* Creates one partition spanning over the whole size of the internal storage drive erasing the existing partitions.
8789
* @return true if successful, false if failed.
8890
*/
89-
static bool partition();
91+
static bool partition();
9092

9193
/**
9294
* Restores the default partitioning scheme (1MB FAT32 for Certificates, 5MB FAT32 for OTA, 8MB user storage) to the internal storage drive erasing the existing partitions.
@@ -96,7 +98,7 @@ class InternalStorage : public Arduino_UnifiedStorage {
9698

9799
/**
98100
* Reads the partitioning scheme from the MBR sector of the internal storage drive and returns a vector of structs of type Partition that represents the partitioning scheme
99-
* @return vector of structs of type Partition
101+
* @return vector of structs of type Partition
100102
*/
101103
static std::vector<Partition> readPartitions();
102104

@@ -105,7 +107,7 @@ class InternalStorage : public Arduino_UnifiedStorage {
105107
MBRBlockDeviceType * mbrBlockDevice;
106108
FileSystemType * fileSystem;
107109
int partitionNumber;
108-
char * partitionName;
110+
const char * partitionName;
109111
FileSystems fileSystemType;
110112

111113
};

‎src/Partitioning.cpp

Lines changed: 31 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ bool Partitioning::eraseMBRSector(BlockDeviceType * blockDevice)
2121
}
2222

2323
bool Partitioning::isPartitionSchemeValid(BlockDeviceType * blockDevice, std::vector<Partition> partitions){
24-
size_t driveSize = blockDevice -> size() / 1024; //
24+
size_t driveSize = blockDevice -> size() / 1024; //
2525
size_t totalSize = 0;
2626

2727
for (size_t i = 1; i < partitions.size() + 1; ++i) {
@@ -72,7 +72,7 @@ bool Partitioning::formatPartition(BlockDeviceType * blockDevice, int partitionN
7272
}
7373

7474
bool Partitioning::createAndFormatPartitions(BlockDeviceType * blockDevice, std::vector<Partition> partitions){
75-
75+
7676
bool success = true; // initialize to true
7777
int lastPartitionEnd = 0;
7878

@@ -117,7 +117,7 @@ bool Partitioning::partitionDrive(BlockDeviceType * blockDevice, std::vector<Par
117117

118118
std::vector<Partition> Partitioning::readPartitions(BlockDeviceType * blockDevice){
119119
std::vector<Partition> partitions;
120-
120+
121121
auto returnCode = blockDevice->init();
122122
if (returnCode) {
123123
Arduino_UnifiedStorage::debugPrint("[Partitioning][readPartitions][ERROR] Unable to read the Block Device.");
@@ -135,17 +135,18 @@ std::vector<Partition> Partitioning::readPartitions(BlockDeviceType * blockDevic
135135
returnCode = blockDevice->read(buffer, 512 - buffer_size, buffer_size);
136136
if (returnCode) {
137137
Arduino_UnifiedStorage::debugPrint("[Partitioning][readPartitions][ERROR] Unable to read the Master Boot Record");
138-
138+
blockDevice->deinit();
139139
delete[] buffer;
140140
return partitions;
141141
}
142142

143143
auto table_start_offset = buffer_size - sizeof(mbrTable);
144144
auto table = reinterpret_cast<mbrTable*>(&buffer[table_start_offset]);
145-
145+
146146
if (table->signature[0] != mbrMagicNumbers[0] || table->signature[1] != mbrMagicNumbers[1]) {
147-
147+
148148
Arduino_UnifiedStorage::debugPrint("[Partitioning][readPartitions][INFO] MBR Not Found - Flash Memory doesn't have partitions.");
149+
blockDevice->deinit();
149150
delete[] buffer;
150151
return partitions;
151152
}
@@ -156,9 +157,9 @@ std::vector<Partition> Partitioning::readPartitions(BlockDeviceType * blockDevic
156157
Partition partition;
157158

158159
/*This code calculates the size of a partition in kilobytes.
159-
It takes the Logical Block Address (LBA) size of the partition,
160+
It takes the Logical Block Address (LBA) size of the partition,
160161
multiplies it by 4096 (the size of a block in bytes),
161-
and then shifts the result 10 bits to the right to convert it to kilobytes.
162+
and then shifts the result 10 bits to the right to convert it to kilobytes.
162163
*/
163164
partition.size = (entry.lbaSize * 4096) >> 10;
164165

@@ -171,24 +172,30 @@ std::vector<Partition> Partitioning::readPartitions(BlockDeviceType * blockDevic
171172
MBRBlockDeviceType * mbrBlocKDevice = new MBRBlockDeviceType(blockDevice, partitionIndex);
172173
FATFileSystemType * fatProbeFileSystem = new FATFileSystemType("probing");
173174
LittleFileSystemType * littleFsProbeFilesystem = new LittleFileSystemType("probing");
174-
175-
if(fatProbeFileSystem -> mount(mbrBlocKDevice) == 0){
176-
Arduino_UnifiedStorage::debugPrint("[Partitioning][readPartitions][INFO] Partition " + String(partitionIndex) + " is formatted with FAT file system");
177-
fatProbeFileSystem -> unmount();
178-
partition.fileSystemType = FS_FAT;
179-
partitions.push_back(partition);
180-
181-
} else if (littleFsProbeFilesystem -> mount(mbrBlocKDevice) == 0){
182-
Arduino_UnifiedStorage::debugPrint("[Partitioning][readPartitions][INFO] Partition " + String(partitionIndex) + " is formatted with LittleFS file system");
183-
littleFsProbeFilesystem -> unmount();
184-
partition.fileSystemType = FS_LITTLEFS;
185-
partitions.push_back(partition);
186-
} else {
187-
Arduino_UnifiedStorage::debugPrint("[Partitioning][readPartitions][INFO] Partition " + String(partitionIndex) + " is not formatted with a recognized file system");
175+
176+
if(mbrBlocKDevice && fatProbeFileSystem && littleFsProbeFilesystem)
177+
{
178+
if(fatProbeFileSystem -> mount(mbrBlocKDevice) == 0){
179+
Arduino_UnifiedStorage::debugPrint("[Partitioning][readPartitions][INFO] Partition " + String(partitionIndex) + " is formatted with FAT file system");
180+
fatProbeFileSystem -> unmount();
181+
partition.fileSystemType = FS_FAT;
182+
partitions.push_back(partition);
183+
184+
} else if (littleFsProbeFilesystem -> mount(mbrBlocKDevice) == 0){
185+
Arduino_UnifiedStorage::debugPrint("[Partitioning][readPartitions][INFO] Partition " + String(partitionIndex) + " is formatted with LittleFS file system");
186+
littleFsProbeFilesystem -> unmount();
187+
partition.fileSystemType = FS_LITTLEFS;
188+
partitions.push_back(partition);
189+
} else {
190+
Arduino_UnifiedStorage::debugPrint("[Partitioning][readPartitions][INFO] Partition " + String(partitionIndex) + " is not formatted with a recognized file system");
191+
}
188192
}
189-
190-
}
191193

194+
delete mbrBlocKDevice;
195+
delete fatProbeFileSystem;
196+
delete littleFsProbeFilesystem;
197+
}
198+
blockDevice->deinit();
192199
delete[] buffer;
193200
return partitions;
194201
}

‎src/Utils.h

Lines changed: 30 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@
3939

4040
[[gnu::unused]] static String prettyPrintFileSystemType(FileSystems f){
4141
if(f == 0) return "FAT";
42-
else if(f == 1) return "LitlleFS";
42+
else if(f == 1) return "LittleFS";
4343
else return "";
4444
}
4545

@@ -56,11 +56,17 @@
5656

5757
// Dynamically allocate memory for the string and copy the generated value
5858
char* dynamicName = new char[strlen(partitionName) + 1];
59-
strcpy(dynamicName, partitionName);
59+
if(dynamicName)
60+
{
61+
strcpy(dynamicName, partitionName);
62+
}
6063

6164
return dynamicName;
6265
}
6366

67+
[[gnu::unused]] static void freePartitionName(const char* partitionName) {
68+
delete[] partitionName;
69+
}
6470

6571
[[gnu::unused]] static bool copyFolder(const char* source, const char* destination) {
6672
DIR* dir = opendir(source);
@@ -88,7 +94,16 @@
8894
size_t destinationPathLength = strlen(destination) + strlen(entry->d_name) + 1;
8995

9096
char* sourcePath = new char[sourcePathLength];
97+
if(!sourcePath)
98+
{
99+
return false;
100+
}
91101
char* destinationPath = new char[destinationPathLength];
102+
if(!destinationPath)
103+
{
104+
delete[] sourcePath;
105+
return false;
106+
}
92107

93108
snprintf(sourcePath, sourcePathLength, "%s/%s", source, entry->d_name);
94109

@@ -97,35 +112,35 @@
97112
struct stat fileInfo;
98113
if (stat(sourcePath, &fileInfo) != 0) {
99114
closedir(dir);
100-
delete(sourcePath);
101-
delete(destinationPath);
115+
delete[] sourcePath;
116+
delete[] destinationPath;
102117
return false;
103118
}
104119

105120
if (S_ISDIR(fileInfo.st_mode)) {
106121
// Recursively copy subdirectories
107122
if (!copyFolder(sourcePath, destinationPath)) {
108123
closedir(dir);
109-
delete(sourcePath);
110-
delete(destinationPath);
124+
delete[] sourcePath;
125+
delete[] destinationPath;
111126
return false;
112127
}
113128
} else {
114129
// Copy regular files
115130
FILE* sourceFile = fopen(sourcePath, "r");
116131
if (sourceFile == nullptr) {
117132
closedir(dir);
118-
delete(sourcePath);
119-
delete(destinationPath);
133+
delete[] sourcePath;
134+
delete[] destinationPath;
120135
return false;
121136
}
122137

123138
FILE* destinationFile = fopen(destinationPath, "w");
124139
if (destinationFile == nullptr) {
125140
fclose(sourceFile);
126141
closedir(dir);
127-
delete(sourcePath);
128-
delete(destinationPath);
142+
delete[] sourcePath;
143+
delete[] destinationPath;
129144
return false;
130145
}
131146

@@ -137,6 +152,10 @@
137152
fclose(sourceFile);
138153
fclose(destinationFile);
139154
}
155+
156+
delete[] sourcePath;
157+
delete[] destinationPath;
158+
140159
}
141160

142161
closedir(dir);
@@ -215,4 +234,4 @@
215234

216235

217236

218-
#endif
237+
#endif

0 commit comments

Comments
 (0)
Please sign in to comment.