Skip to content

fatfs: Add full support for multiple fs volume prefixes #4561

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jul 10, 2017
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
94 changes: 77 additions & 17 deletions features/filesystem/fat/FATFileSystem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,61 @@ static int fat_error_remap(FRESULT res)
}
}

// Helper class for deferring operations when variable falls out of scope
template <typename T>
class Deferred {
public:
T _t;
Callback<void(T)> _ondefer;

Deferred(const Deferred&);
Deferred &operator=(const Deferred&);

public:
Deferred(T t, Callback<void(T)> ondefer = NULL)
: _t(t), _ondefer(ondefer)
{
}

operator T()
{
return _t;
}

~Deferred()
{
if (_ondefer) {
_ondefer(_t);
}
}
};

static void dodelete(const char *data)
{
delete[] data;
}

// Adds prefix needed internally by fatfs, this can be avoided for the first fatfs
// (id 0) otherwise a prefix of "id:/" is inserted in front of the string.
static Deferred<const char*> fat_path_prefix(int id, const char *path)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happens when id > 256?

Copy link
Contributor Author

@geky geky Jun 14, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • The fsid will break.
  • The chanfs will fail to mount.
  • MBR will fail with >4 partitions
  • GPT will fail with >128 partitions.
  • Linux won't recognize >255 partitions.
  • Windows won't recognize >1 partition.
  • You will need ~800KB of ram to mount all of the filesystems at once.
  • With 160MB of storage you will be wasting 10% on metadata alone.

Oh and this code may break.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 😆

Copy link
Contributor

@theotherjimmy theotherjimmy Jun 14, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, reading tha GPT article, the format supports >128 partitions. The maximum should be 4,294,967,295 or 0xFFFFFFFF

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah looks like you're right, glad we won't have to reinvent partitioning to get your 300 fs cluster working.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could it just be uint8? we don't loose anything by doing that.

{
// We can avoid dynamic allocation when only on fatfs is in use
if (id == 0) {
return path;
}

// Prefix path with id, will look something like 2:/hi/hello/filehere.txt
char *buffer = new char[strlen("0:/") + strlen(path) + 1];
if (!buffer) {
return NULL;
}

buffer[0] = '0' + id;
buffer[1] = ':';
buffer[2] = '/';
strcpy(buffer + strlen("0:/"), path);
return Deferred<const char*>(buffer, dodelete);
}


////// Disk operations //////
Expand Down Expand Up @@ -263,9 +318,11 @@ int FATFileSystem::format(BlockDevice *bd, int allocation_unit) {
return 0;
}

int FATFileSystem::remove(const char *filename) {
int FATFileSystem::remove(const char *path) {
Deferred<const char*> fpath = fat_path_prefix(_id, path);

lock();
FRESULT res = f_unlink(filename);
FRESULT res = f_unlink(fpath);
unlock();

if (res != FR_OK) {
Expand All @@ -274,9 +331,12 @@ int FATFileSystem::remove(const char *filename) {
return fat_error_remap(res);
}

int FATFileSystem::rename(const char *oldname, const char *newname) {
int FATFileSystem::rename(const char *oldpath, const char *newpath) {
Deferred<const char*> oldfpath = fat_path_prefix(_id, oldpath);
Deferred<const char*> newfpath = fat_path_prefix(_id, newpath);

lock();
FRESULT res = f_rename(oldname, newname);
FRESULT res = f_rename(oldfpath, newfpath);
unlock();

if (res != FR_OK) {
Expand All @@ -285,9 +345,11 @@ int FATFileSystem::rename(const char *oldname, const char *newname) {
return fat_error_remap(res);
}

int FATFileSystem::mkdir(const char *name, mode_t mode) {
int FATFileSystem::mkdir(const char *path, mode_t mode) {
Deferred<const char*> fpath = fat_path_prefix(_id, path);

lock();
FRESULT res = f_mkdir(name);
FRESULT res = f_mkdir(fpath);
unlock();

if (res != FR_OK) {
Expand All @@ -296,12 +358,14 @@ int FATFileSystem::mkdir(const char *name, mode_t mode) {
return fat_error_remap(res);
}

int FATFileSystem::stat(const char *name, struct stat *st) {
int FATFileSystem::stat(const char *path, struct stat *st) {
Deferred<const char*> fpath = fat_path_prefix(_id, path);

lock();
FILINFO f;
memset(&f, 0, sizeof(f));

FRESULT res = f_stat(name, &f);
FRESULT res = f_stat(fpath, &f);
if (res != FR_OK) {
unlock();
return fat_error_remap(res);
Expand Down Expand Up @@ -332,13 +396,10 @@ void FATFileSystem::unlock() {

////// File operations //////
int FATFileSystem::file_open(fs_file_t *file, const char *path, int flags) {
debug_if(FFS_DBG, "open(%s) on filesystem [%s], drv [%s]\n", path, getName(), _fsid);
debug_if(FFS_DBG, "open(%s) on filesystem [%s], drv [%s]\n", path, getName(), _id);

FIL *fh = new FIL;
char *buffer = new char[strlen(_fsid) + strlen(path) + 3];
strcpy(buffer, _fsid);
strcat(buffer, "/");
strcat(buffer, path);
Deferred<const char*> fpath = fat_path_prefix(_id, path);

/* POSIX flags -> FatFS open mode */
BYTE openmode;
Expand All @@ -358,12 +419,11 @@ int FATFileSystem::file_open(fs_file_t *file, const char *path, int flags) {
}

lock();
FRESULT res = f_open(fh, buffer, openmode);
FRESULT res = f_open(fh, fpath, openmode);

if (res != FR_OK) {
unlock();
debug_if(FFS_DBG, "f_open('w') failed: %d\n", res);
delete[] buffer;
delete fh;
return fat_error_remap(res);
}
Expand All @@ -373,7 +433,6 @@ int FATFileSystem::file_open(fs_file_t *file, const char *path, int flags) {
}
unlock();

delete[] buffer;
*file = fh;
return 0;
}
Expand Down Expand Up @@ -480,9 +539,10 @@ off_t FATFileSystem::file_size(fs_file_t file) {
////// Dir operations //////
int FATFileSystem::dir_open(fs_dir_t *dir, const char *path) {
FATFS_DIR *dh = new FATFS_DIR;
Deferred<const char*> fpath = fat_path_prefix(_id, path);

lock();
FRESULT res = f_opendir(dh, path);
FRESULT res = f_opendir(dh, fpath);
unlock();

if (res != FR_OK) {
Expand Down