Suunto EON Steel/Core: make sure to properly sort the dive list
I incorrectly thought it was already sorted in the directory listing, but once the dive list start overflowing, it looks like the ordering goes away. So sort the dives explicitly by date, rather than depend on any existing ordering when reading the list of dives. Reported-by: PM <boesch76@gmail.com> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
parent
e650acc052
commit
92cf2f8fa1
@ -641,12 +641,35 @@ read_file(suunto_eonsteel_device_t *eon, const char *filename, dc_buffer_t *buf)
|
|||||||
return DC_STATUS_SUCCESS;
|
return DC_STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Insert a directory entry in the sorted list, most recent entry
|
||||||
|
* first.
|
||||||
|
*
|
||||||
|
* The directory entry names are the timestamps as hex, so ordering
|
||||||
|
* in alphabetical order ends up also ordering in date order!
|
||||||
|
*/
|
||||||
|
static struct directory_entry *insert_dirent(struct directory_entry *entry, struct directory_entry *list)
|
||||||
|
{
|
||||||
|
struct directory_entry **pos = &list, *next;
|
||||||
|
|
||||||
|
while ((next = *pos) != NULL) {
|
||||||
|
/* Is this bigger (more recent) than the next entry? We're good! */
|
||||||
|
if (strcmp(entry->name, next->name) > 0)
|
||||||
|
break;
|
||||||
|
pos = &next->next;
|
||||||
|
}
|
||||||
|
entry->next = next;
|
||||||
|
*pos = entry;
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* NOTE! This will create the list of dirent's in reverse order,
|
* NOTE! This will create the list of dirent's in reverse order,
|
||||||
* with the last dirent first. That's intentional: for dives,
|
* with the last dirent first. That's intentional: for dives,
|
||||||
* we will want to look up the last dive first.
|
* we will want to look up the last dive first.
|
||||||
*/
|
*/
|
||||||
static struct directory_entry *parse_dirent(suunto_eonsteel_device_t *eon, int nr, const unsigned char *p, unsigned int len, struct directory_entry *old)
|
static struct directory_entry *parse_dirent(suunto_eonsteel_device_t *eon, int nr, const unsigned char *p, unsigned int len, struct directory_entry *list)
|
||||||
{
|
{
|
||||||
while (len > 8) {
|
while (len > 8) {
|
||||||
unsigned int type = array_uint32_le(p);
|
unsigned int type = array_uint32_le(p);
|
||||||
@ -667,10 +690,9 @@ static struct directory_entry *parse_dirent(suunto_eonsteel_device_t *eon, int n
|
|||||||
ERROR(eon->base.context, "out of memory");
|
ERROR(eon->base.context, "out of memory");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
entry->next = old;
|
list = insert_dirent(entry, list);
|
||||||
old = entry;
|
|
||||||
}
|
}
|
||||||
return old;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
static dc_status_t
|
static dc_status_t
|
||||||
@ -731,6 +753,19 @@ get_file_list(suunto_eonsteel_device_t *eon, struct directory_entry **res)
|
|||||||
return DC_STATUS_SUCCESS;
|
return DC_STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
count_file_list(struct directory_entry *list)
|
||||||
|
{
|
||||||
|
int count = 0;
|
||||||
|
|
||||||
|
while (list) {
|
||||||
|
count++;
|
||||||
|
list = list->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
dc_status_t
|
dc_status_t
|
||||||
suunto_eonsteel_device_open(dc_device_t **out, dc_context_t *context, dc_iostream_t *iostream, unsigned int model)
|
suunto_eonsteel_device_open(dc_device_t **out, dc_context_t *context, dc_iostream_t *iostream, unsigned int model)
|
||||||
{
|
{
|
||||||
@ -802,7 +837,6 @@ suunto_eonsteel_device_foreach(dc_device_t *abstract, dc_dive_callback_t callbac
|
|||||||
dc_buffer_t *file;
|
dc_buffer_t *file;
|
||||||
char pathname[64];
|
char pathname[64];
|
||||||
unsigned int time;
|
unsigned int time;
|
||||||
unsigned int count = 0;
|
|
||||||
dc_event_progress_t progress = EVENT_PROGRESS_INITIALIZER;
|
dc_event_progress_t progress = EVENT_PROGRESS_INITIALIZER;
|
||||||
|
|
||||||
// Emit a device info event.
|
// Emit a device info event.
|
||||||
@ -820,46 +854,17 @@ suunto_eonsteel_device_foreach(dc_device_t *abstract, dc_dive_callback_t callbac
|
|||||||
return DC_STATUS_SUCCESS;
|
return DC_STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Locate the most recent dive.
|
|
||||||
// The filename represent the time of the dive, encoded as a hexadecimal
|
|
||||||
// number. Thus the most recent dive can be found by simply sorting the
|
|
||||||
// filenames alphabetically.
|
|
||||||
struct directory_entry *head = de, *tail = de, *latest = de;
|
|
||||||
while (de) {
|
|
||||||
if (strcmp (de->name, latest->name) > 0) {
|
|
||||||
latest = de;
|
|
||||||
}
|
|
||||||
tail = de;
|
|
||||||
count++;
|
|
||||||
de = de->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make the most recent dive the head of the list.
|
|
||||||
// The linked list is made circular, by attaching the head to the tail and
|
|
||||||
// then cut open again just before the most recent dive.
|
|
||||||
de = head;
|
|
||||||
while (de) {
|
|
||||||
if (de->next == latest) {
|
|
||||||
de->next = NULL;
|
|
||||||
tail->next = head;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
de = de->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
file = dc_buffer_new (16384);
|
file = dc_buffer_new (16384);
|
||||||
if (file == NULL) {
|
if (file == NULL) {
|
||||||
ERROR (abstract->context, "Insufficient buffer space available.");
|
ERROR (abstract->context, "Insufficient buffer space available.");
|
||||||
file_list_free (latest);
|
file_list_free(de);
|
||||||
return DC_STATUS_NOMEMORY;
|
return DC_STATUS_NOMEMORY;
|
||||||
}
|
}
|
||||||
|
|
||||||
progress.maximum = count;
|
progress.maximum = count_file_list(de);
|
||||||
progress.current = 0;
|
progress.current = 0;
|
||||||
device_event_emit(abstract, DC_EVENT_PROGRESS, &progress);
|
device_event_emit(abstract, DC_EVENT_PROGRESS, &progress);
|
||||||
|
|
||||||
de = latest;
|
|
||||||
while (de) {
|
while (de) {
|
||||||
int len;
|
int len;
|
||||||
struct directory_entry *next = de->next;
|
struct directory_entry *next = de->next;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user