Skip to content
Merged
Show file tree
Hide file tree
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
45 changes: 45 additions & 0 deletions source/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include <3ds.h>

#include <curl/curl.h>
#include <mbedtls/md5.h>

#include "libs/inih/INIReader/INIReader.h"
#include "modules/dropbox.h"
Expand Down Expand Up @@ -265,6 +266,37 @@ static bool waitForMainMenuKey()
// ---------------------------------------------------------------------------
static bool g_cancelRequested = false;

// ---------------------------------------------------------------------------
// computeMd5Hex — return the MD5 of a local file as a lowercase hex string,
// or "" on error. Used to detect content changes when mtime is stale
// (FAT32 has 2-second granularity and some emulators never update mtime).
// ---------------------------------------------------------------------------
static std::string computeMd5Hex(const std::string &path)
{
FILE *fp = fopen(path.c_str(), "rb");
if (!fp)
return "";

mbedtls_md5_context ctx;
mbedtls_md5_init(&ctx);
mbedtls_md5_starts(&ctx);

unsigned char buf[4096];
size_t n;
while ((n = fread(buf, 1, sizeof(buf), fp)) > 0)
mbedtls_md5_update(&ctx, buf, n);
fclose(fp);

unsigned char digest[16];
mbedtls_md5_finish(&ctx, digest);
mbedtls_md5_free(&ctx);

char hex[33];
for (int i = 0; i < 16; i++)
snprintf(hex + i * 2, 3, "%02x", digest[i]);
return std::string(hex, 32);
}

// ---------------------------------------------------------------------------
// performSync — bidirectional sync for one SyncEntry
// Returns false if a fatal Drive error occurred or cancellation was requested.
Expand Down Expand Up @@ -328,6 +360,19 @@ static bool performSync(GoogleDrive &drive, Manifest &manifest, const SyncEntry
bool localChanged = inManifest && (localMtime != mEntry.localMtime);
bool driveChanged = inManifest && driveExists && (dfi->md5 != mEntry.driveMd5);

// FAT32 mtime has 2-second granularity and some emulators never update
// the timestamp at all. If mtime is unchanged but we have a Drive MD5
// from the last sync, compare file content as a reliable fallback.
if (!localChanged && inManifest && localExists && !mEntry.driveMd5.empty())
{
std::string localMd5 = computeMd5Hex(localPath);
if (!localMd5.empty() && localMd5 != mEntry.driveMd5)
{
printf(" (content changed, mtime frozen — uploading)\n");
localChanged = true;
}
}

printf(" %s: local=%s drive=%s manifest=%s\n",
relPath.c_str(),
localExists ? "yes" : "no",
Expand Down
2 changes: 1 addition & 1 deletion source/modules/manifest.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
// Record of one file's last-known sync state.
struct ManifestEntry
{
time_t localMtime; // st_mtime at the time of the last successful sync
time_t localMtime; // st_mtime at the time of the last successful sync
std::string driveMd5; // md5Checksum returned by Drive after the last sync
std::string driveId; // Drive file ID (for update/download without a name search)
};
Expand Down
Loading