garmin: relax file name length rules

We end up using the FIT file name as the "fingerprint" for the dive, and
include it at the beginning of the dive data as such.  And because of
how Garmin encoded the FIT files, we ended up having a fixed 24-byte
length for this, which is normally the date encoding:

    YYYY-MM-DD-HH-MM-SS.FIT

with the terminating NUL character.

Of course, then Garmin started using a short-form encoding too
(presumably due to FAT filesystem limits), and we have magic code to
sort the dates properly, using the name format

    YMDHMMSS.FIT

with the numbers encoded in a shorter format (eg "C4ND0302.fit" is
equivalent to "2022-04-23-13-03-02.fit").  See name_cmp() and
parse_short_name() for details.

Anyway, because we use the (zero-padded) 24 characters of the name as
the fingerprint, we used a fixed-size buffer for the filename that was
limited to that maximum size Garmin creates.

But then you download those things, and have multiple vendors, and
suddenly that 24-character limit on the filename is very annoying.

Instead of fixing this in some clean and generic way, let's just raise
the namelength limit to something bigger, and continue to use the first
24 characters of the name for the fingerprint.

Pretty it isn't, but it makes it slightly easier to import random FIT
files that don't conform exactly to the traditional Garmin format.

Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
Linus Torvalds 2023-07-14 12:31:33 -07:00
parent 67cd1cc0fd
commit 4a2dec531e
3 changed files with 24 additions and 21 deletions

View File

@ -138,6 +138,17 @@ garmin_device_close (dc_device_t *abstract)
return DC_STATUS_SUCCESS;
}
/*
* NOTE! The fingerprint is only the 24 first bytes of this,
* aka FIT_NAME_SIZE.
*/
#define FILE_NAME_SIZE 64
struct fit_file {
char name[FILE_NAME_SIZE + 1];
unsigned int mtp_id;
};
struct file_list {
int nr, allocated;
struct fit_file *array;
@ -175,8 +186,8 @@ static int name_cmp(const void *_a, const void *_b)
const char *a_name = a->name;
const char *b_name = b->name;
char a_buffer[FIT_NAME_SIZE];
char b_buffer[FIT_NAME_SIZE];
char a_buffer[FILE_NAME_SIZE];
char b_buffer[FILE_NAME_SIZE];
if (strlen(a_name) == 12) {
parse_short_name(a_name, a_buffer);
@ -202,19 +213,16 @@ static int
check_filename(dc_device_t *abstract, const char *name)
{
int len = strlen(name);
const char *explain = NULL;
DEBUG(abstract->context, " %s", name);
if (len < 5)
explain = "name too short";
if (len >= FIT_NAME_SIZE)
explain = "name too long";
return 0;
if (len >= FILE_NAME_SIZE)
return 0;
if (strncasecmp(name + len - 4, ".FIT", 4))
explain = "name lacks FIT suffix";
return 0;
DEBUG(abstract->context, " %s - %s", name, explain ? explain : "adding to list");
return explain == NULL;
DEBUG(abstract->context, " %s - adding to list", name);
return 1;
}
static dc_status_t
@ -245,8 +253,8 @@ add_name(struct file_list *files, const char *name, unsigned int mtp_id)
* will zero-pad the end of the result buffer.
*/
struct fit_file *entry = files->array + files->nr++;
strncpy(entry->name, name, FIT_NAME_SIZE);
entry->name[FIT_NAME_SIZE] = 0; // ensure it's null-terminated
strncpy(entry->name, name, FILE_NAME_SIZE);
entry->name[FILE_NAME_SIZE] = 0; // ensure it's null-terminated
entry->mtp_id = mtp_id;
}
@ -409,7 +417,7 @@ read_file(char *pathname, int pathlen, const char *name, dc_buffer_t *file)
int fd, rc;
pathname[pathlen] = '/';
memcpy(pathname+pathlen+1, name, FIT_NAME_SIZE);
memcpy(pathname+pathlen+1, name, FILE_NAME_SIZE);
fd = open(pathname, O_RDONLY | O_BINARY);
if (fd < 0)
@ -468,7 +476,7 @@ garmin_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, void
// The actual dives are under the "Garmin/Activity/" directory
// as FIT files, with names like "2018-08-20-10-23-30.fit".
// Make sure our buffer is big enough.
if (pathlen + strlen("/Garmin/Activity/") + FIT_NAME_SIZE + 2 > PATH_MAX) {
if (pathlen + strlen("/Garmin/Activity/") + FILE_NAME_SIZE + 2 > PATH_MAX) {
ERROR (abstract->context, "Invalid Garmin base directory '%s'", pathname_input);
return DC_STATUS_IO;
}

View File

@ -49,11 +49,6 @@ garmin_parser_is_dive (dc_parser_t *abstract, const unsigned char *data, unsigne
// special fixed header in the parser data too.
#define FIT_NAME_SIZE 24
struct fit_file {
char name[FIT_NAME_SIZE + 1];
unsigned int mtp_id;
};
#ifdef __cplusplus
}
#endif /* __cplusplus */

View File

@ -1409,7 +1409,7 @@ traverse_data(struct garmin_parser_t *garmin)
if (len < FIT_NAME_SIZE)
return DC_STATUS_IO;
DEBUG(garmin->base.context, "file %s", data);
DEBUG(garmin->base.context, "file %.*s", FIT_NAME_SIZE, data);
data += FIT_NAME_SIZE;
len -= FIT_NAME_SIZE;