aboutsummaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
Diffstat (limited to 'core')
-rw-r--r--core/downloadfromdcthread.cpp11
-rw-r--r--core/downloadfromdcthread.h2
-rw-r--r--core/libdivecomputer.c230
-rw-r--r--core/libdivecomputer.h6
4 files changed, 98 insertions, 151 deletions
diff --git a/core/downloadfromdcthread.cpp b/core/downloadfromdcthread.cpp
index 554618388..6c38812c9 100644
--- a/core/downloadfromdcthread.cpp
+++ b/core/downloadfromdcthread.cpp
@@ -218,7 +218,6 @@ DCDeviceData::DCDeviceData()
memset(&data, 0, sizeof(data));
data.download_table = nullptr;
data.diveid = 0;
- data.deviceid = 0;
#if defined(BT_SUPPORT)
data.bluetooth_mode = true;
#else
@@ -293,11 +292,6 @@ bool DCDeviceData::forceDownload() const
return data.force_download;
}
-int DCDeviceData::deviceId() const
-{
- return data.deviceid;
-}
-
int DCDeviceData::diveId() const
{
return data.diveid;
@@ -357,11 +351,6 @@ void DCDeviceData::setForceDownload(bool force)
data.force_download = force;
}
-void DCDeviceData::setDeviceId(int deviceId)
-{
- data.deviceid = deviceId;
-}
-
void DCDeviceData::setDiveId(int diveId)
{
data.diveid = diveId;
diff --git a/core/downloadfromdcthread.h b/core/downloadfromdcthread.h
index 448271211..a4a485a0e 100644
--- a/core/downloadfromdcthread.h
+++ b/core/downloadfromdcthread.h
@@ -32,7 +32,6 @@ public:
QString descriptor() const;
bool forceDownload() const;
bool saveLog() const;
- int deviceId() const;
int diveId() const;
/* this needs to be a pointer to make the C-API happy */
@@ -44,7 +43,6 @@ public:
int getDetectedVendorIndex();
int getDetectedProductIndex(const QString &currentVendorText);
- void setDeviceId(int deviceId);
void setDiveId(int diveId);
void setVendor(const QString& vendor);
void setProduct(const QString& product);
diff --git a/core/libdivecomputer.c b/core/libdivecomputer.c
index c750efdd6..0d797b66a 100644
--- a/core/libdivecomputer.c
+++ b/core/libdivecomputer.c
@@ -600,7 +600,8 @@ static dc_status_t libdc_header_parser(dc_parser_t *parser, device_data_t *devda
return rc;
}
- dive->dc.deviceid = devdata->deviceid;
+ // Our deviceid is the hash of the serial number
+ dive->dc.deviceid = 0;
if (rc == DC_STATUS_SUCCESS) {
tm.tm_year = dt.year;
@@ -771,16 +772,6 @@ static int dive_cb(const unsigned char *data, unsigned int size,
dive->dc.model = strdup(devdata->model);
dive->dc.diveid = calculate_diveid(fingerprint, fsize);
- /* Should we add it to the cached fingerprint file? */
- if (fingerprint && fsize && !devdata->fingerprint) {
- devdata->fingerprint = calloc(fsize, 1);
- if (devdata->fingerprint) {
- devdata->fsize = fsize;
- devdata->fdiveid = dive->dc.diveid;
- memcpy(devdata->fingerprint, fingerprint, fsize);
- }
- }
-
// Parse the dive's header data
rc = libdc_header_parser (parser, devdata, dive);
if (rc != DC_STATUS_SUCCESS) {
@@ -797,6 +788,22 @@ static int dive_cb(const unsigned char *data, unsigned int size,
dc_parser_destroy(parser);
+ /*
+ * Save off fingerprint data.
+ *
+ * NOTE! We do this after parsing the dive fully, so that
+ * we have the final deviceid here.
+ */
+ if (fingerprint && fsize && !devdata->fingerprint) {
+ devdata->fingerprint = calloc(fsize, 1);
+ if (devdata->fingerprint) {
+ devdata->fsize = fsize;
+ devdata->fdeviceid = dive->dc.deviceid;
+ devdata->fdiveid = dive->dc.diveid;
+ memcpy(devdata->fingerprint, fingerprint, fsize);
+ }
+ }
+
/* If we already saw this dive, abort. */
if (!devdata->force_download && find_dive(&dive->dc)) {
char *date_string = get_dive_date_c_string(dive->when);
@@ -822,95 +829,6 @@ error_exit:
}
-/*
- * The device ID for libdivecomputer devices is the first 32-bit word
- * of the SHA1 hash of the model/firmware/serial numbers.
- *
- * NOTE! This is byte-order-dependent. And I can't find it in myself to
- * care.
- */
-static uint32_t calculate_sha1(unsigned int model, unsigned int firmware, unsigned int serial)
-{
- SHA_CTX ctx;
- uint32_t csum[5];
-
- SHA1_Init(&ctx);
- SHA1_Update(&ctx, &model, sizeof(model));
- SHA1_Update(&ctx, &firmware, sizeof(firmware));
- SHA1_Update(&ctx, &serial, sizeof(serial));
- SHA1_Final((unsigned char *)csum, &ctx);
- return csum[0];
-}
-
-/*
- * libdivecomputer has returned two different serial numbers for the
- * same device in different versions. First it used to just do the four
- * bytes as one 32-bit number, then it turned it into a decimal number
- * with each byte giving two digits (0-99).
- *
- * The only way we can tell is by looking at the format of the number,
- * so we'll just fix it to the first format.
- */
-static unsigned int undo_libdivecomputer_suunto_nr_changes(unsigned int serial)
-{
- unsigned char b0, b1, b2, b3;
-
- /*
- * The second format will never have more than 8 decimal
- * digits, so do a cheap check first
- */
- if (serial >= 100000000)
- return serial;
-
- /* The original format seems to be four bytes of values 00-99 */
- b0 = (serial >> 0) & 0xff;
- b1 = (serial >> 8) & 0xff;
- b2 = (serial >> 16) & 0xff;
- b3 = (serial >> 24) & 0xff;
-
- /* Looks like an old-style libdivecomputer serial number */
- if ((b0 < 100) && (b1 < 100) && (b2 < 100) && (b3 < 100))
- return serial;
-
- /* Nope, it was converted. */
- b0 = serial % 100;
- serial /= 100;
- b1 = serial % 100;
- serial /= 100;
- b2 = serial % 100;
- serial /= 100;
- b3 = serial % 100;
-
- serial = b0 + (b1 << 8) + (b2 << 16) + (b3 << 24);
- return serial;
-}
-
-static unsigned int fixup_suunto_versions(device_data_t *devdata, const dc_event_devinfo_t *devinfo)
-{
- unsigned int serial = devinfo->serial;
- char serial_nr[13] = "";
- char firmware[13] = "";
-
- first_temp_is_air = 1;
-
- serial = undo_libdivecomputer_suunto_nr_changes(serial);
-
- if (serial) {
- snprintf(serial_nr, sizeof(serial_nr), "%02d%02d%02d%02d",
- (devinfo->serial >> 24) & 0xff,
- (devinfo->serial >> 16) & 0xff,
- (devinfo->serial >> 8) & 0xff,
- (devinfo->serial >> 0) & 0xff);
- }
- if (devinfo->firmware) {
- snprintf(firmware, sizeof(firmware), "%d.%d.%d",
- (devinfo->firmware >> 16) & 0xff,
- (devinfo->firmware >> 8) & 0xff,
- (devinfo->firmware >> 0) & 0xff);
- }
-
- return serial;
-}
#ifndef O_BINARY
#define O_BINARY 0
#endif
@@ -922,11 +840,14 @@ static void do_save_fingerprint(device_data_t *devdata, const char *tmp, const c
if (fd < 0)
return;
+ dev_info(devdata, "Saving fingerprint for %08x:%08x to '%s'",
+ devdata->fdeviceid, devdata->fdiveid, final);
+
/* The fingerprint itself.. */
written = write(fd, devdata->fingerprint, devdata->fsize);
- /* ..followed by the dive ID of the fingerprinted dive */
- if (write(fd, &devdata->fdiveid, 4) != 4)
+ /* ..followed by the device ID and dive ID of the fingerprinted dive */
+ if (write(fd, &devdata->fdeviceid, 4) != 4 || write(fd, &devdata->fdiveid, 4) != 4)
written = -1;
/* I'd like to do fsync() here too, but does Windows support it? */
@@ -934,33 +855,76 @@ static void do_save_fingerprint(device_data_t *devdata, const char *tmp, const c
written = -1;
if (written == devdata->fsize) {
- if (!subsurface_rename(tmp, final))
+ if (!subsurface_rename(tmp, final)) {
+ dev_info(devdata, " ... %d bytes and dive ID", written);
return;
+ }
}
unlink(tmp);
}
+static char *fingerprint_file(device_data_t *devdata)
+{
+ uint32_t model, serial;
+
+ // Model hash and libdivecomputer 32-bit 'serial number' for the file name
+ model = calculate_string_hash(devdata->model);
+ serial = devdata->devinfo.serial;
+
+ return format_string("%s/fingerprints/%04x.%u",
+ system_default_directory(),
+ model, serial);
+}
+
/*
* Save the fingerprint after a successful download
+ *
+ * NOTE! At this point, we have the final device ID for the divecomputer
+ * we downloaded from. But that 'deviceid' is actually not useful, because
+ * at the point where we want to _load_ this, we only have the libdivecomputer
+ * DC_EVENT_DEVINFO state (devdata->devinfo).
+ *
+ * Now, we do have the devdata->devinfo at save time, but at load time we
+ * need to verify not only that it's the proper fingerprint file: we also
+ * need to check that we actually have the particular dive that was
+ * associated with that fingerprint state.
+ *
+ * That means that the fingerprint save file needs to include not only the
+ * fingerprint data itself, but also enough data to look up a dive unambiguously
+ * when loading the fingerprint. And the fingerprint data needs to be looked
+ * up using the DC_EVENT_DEVINFO data.
+ *
+ * End result:
+ *
+ * - fingerprint filename depends on the model name and 'devinfo.serial'
+ * so that we can look it up at DC_EVENT_DEVINFO time before the full
+ * info has been parsed.
+ *
+ * - the fingerprint file contains the 'diveid' of the fingerprinted dive,
+ * which is just a hash of the fingerprint itself.
+ *
+ * - we also save the final 'deviceid' in the fingerprint file, so that
+ * looking up the dive associated with the fingerprint is possible.
*/
static void save_fingerprint(device_data_t *devdata)
{
char *dir, *tmp, *final;
- if (!devdata->fingerprint)
+ // Don't try to save nonexistent fingerprint data
+ if (!devdata->fingerprint || !devdata->fdiveid)
return;
+ // Make sure the fingerprints directory exists
dir = format_string("%s/fingerprints", system_default_directory());
subsurface_mkdir(dir);
- tmp = format_string("%s/%04x.tmp", dir, devdata->deviceid);
- final = format_string("%s/%04x", dir, devdata->deviceid);
+
+ final = fingerprint_file(devdata);
+ tmp = format_string("%s.tmp", final);
free(dir);
do_save_fingerprint(devdata, tmp, final);
free(tmp);
free(final);
- free(devdata->fingerprint);
- devdata->fingerprint = NULL;
}
static int has_dive(unsigned int deviceid, unsigned int diveid)
@@ -984,26 +948,31 @@ static int has_dive(unsigned int deviceid, unsigned int diveid)
/*
* The fingerprint cache files contain the actual libdivecomputer
- * fingerprint, followed by 4 bytes of diveid data. Before we use
- * the fingerprint data, verify that we actually do have that
- * fingerprinted dive.
+ * fingerprint, followed by 8 bytes of (deviceid,diveid) data.
+ *
+ * Before we use the fingerprint data, verify that we actually
+ * do have that fingerprinted dive.
*/
static void verify_fingerprint(dc_device_t *device, device_data_t *devdata, const unsigned char *buffer, size_t size)
{
- unsigned int diveid, deviceid;
+ uint32_t diveid, deviceid;
- if (size <= 4)
+ if (size <= 8)
return;
- size -= 4;
+ size -= 8;
/* Get the dive ID from the end of the fingerprint cache file.. */
- memcpy(&diveid, buffer + size, 4);
- /* .. and the device ID from the device data */
- deviceid = devdata->deviceid;
+ memcpy(&deviceid, buffer + size, 4);
+ memcpy(&diveid, buffer + size + 4, 4);
+ dev_info(devdata, " ... fingerprinted dive %08x:%08x", deviceid, diveid);
/* Only use it if we *have* that dive! */
- if (has_dive(deviceid, diveid))
- dc_device_set_fingerprint(device, buffer, size);
+ if (!has_dive(deviceid, diveid)) {
+ dev_info(devdata, " ... dive not found", deviceid, diveid);
+ return;
+ }
+ dc_device_set_fingerprint(device, buffer, size);
+ dev_info(devdata, " ... fingerprint of size %zu", size);
}
/*
@@ -1018,9 +987,11 @@ static void lookup_fingerprint(dc_device_t *device, device_data_t *devdata)
if (devdata->force_download)
return;
- cachename = format_string("%s/fingerprints/%04x",
- system_default_directory(), devdata->deviceid);
+
+ cachename = fingerprint_file(devdata);
+ dev_info(devdata, "Looking for fingerprint in '%s'", cachename);
if (readfile(cachename, &mem) > 0) {
+ dev_info(devdata, " ... got %zu bytes", mem.size);
verify_fingerprint(device, devdata, mem.buffer, mem.size);
free(mem.buffer);
}
@@ -1035,7 +1006,6 @@ static void event_cb(dc_device_t *device, dc_event_type_t event, const void *dat
const dc_event_clock_t *clock = data;
const dc_event_vendor_t *vendor = data;
device_data_t *devdata = userdata;
- unsigned int serial;
switch (event) {
case DC_EVENT_WAITING:
@@ -1070,19 +1040,7 @@ static void event_cb(dc_device_t *device, dc_event_type_t event, const void *dat
devinfo->serial, devinfo->serial);
}
- /*
- * libdivecomputer doesn't give serial numbers in the proper string form,
- * so we have to see if we can do some vendor-specific munging.
- */
- serial = devinfo->serial;
- if (!strcmp(devdata->vendor, "Suunto"))
- serial = fixup_suunto_versions(devdata, devinfo);
- devdata->deviceid = calculate_sha1(devinfo->model, devinfo->firmware, serial);
- /* really, firmware version is NOT a number. We'll try to save it here
- * in something that might work, but this really needs to be handled with the
- * DC_FIELD_STRING interface instead */
- devdata->libdc_firmware = devinfo->firmware;
-
+ devdata->devinfo = *devinfo;
lookup_fingerprint(device, devdata);
break;
@@ -1495,6 +1453,8 @@ const char *do_libdivecomputer_import(device_data_t *data)
* it refers to before we use the fingerprint data.
*/
save_fingerprint(data);
+ free(data->fingerprint);
+ data->fingerprint = NULL;
return err;
}
diff --git a/core/libdivecomputer.h b/core/libdivecomputer.h
index 9932c9d84..21cd3f83e 100644
--- a/core/libdivecomputer.h
+++ b/core/libdivecomputer.h
@@ -35,9 +35,9 @@ typedef struct {
const char *vendor, *product, *devname;
const char *model, *btname;
unsigned char *fingerprint;
- unsigned int fsize, fdiveid;
- uint32_t libdc_firmware;
- uint32_t deviceid, diveid;
+ unsigned int fsize, fdeviceid, fdiveid;
+ struct dc_event_devinfo_t devinfo;
+ uint32_t diveid;
dc_device_t *device;
dc_context_t *context;
dc_iostream_t *iostream;