mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2026-10-22 15:22:47 +00:00
fileutils: honor a filename extension the user supplied
'-f card.mfd' looked for card.mfd.bin and saved to card.mfd.bin, because the caller's suffix was appended unless the name already ended in that exact suffix. searchFile() now tries the name as typed before falling back to the suffixed one. newfilenamemcopyEx() keeps an extension that denotes the same kind of file it is about to write, and swaps any other for its own, so 'hf mf dump -f card.mfd' gives card.mfd + card.json rather than card.mfd + card.mfd.json. Both classify with get_filetype() so load and save cannot drift apart. Also drops the size_t underflow in newfilenamemcopyEx(), where a long path plus a configured save path made the snprintf bound wrap past the 1000 byte buffer. Co-Authored-By: Claude Opus 5 (1M context)
This commit is contained in:
1 parent
196a467bf8
commit
72f48c8a02
2 files changed
+82
-16
No files matched your search
+79
-16
@@ -261,6 +261,35 @@ void path_basename_without_ext(const char *path, char *out, size_t out_len) {
|
||||
}
|
||||
}
|
||||
|
||||
// the extension of the last path component, leading dot included, or NULL when
|
||||
// there is none. "dumps/vg20180106.mfd" -> ".mfd", "dumps/vg20180106" -> NULL
|
||||
static const char *path_extension(const char *path) {
|
||||
const char *base = path_basename(path);
|
||||
const char *dot = strrchr(base, '.');
|
||||
if ((dot == NULL) || (dot == base) || (dot[1] == '\0')) {
|
||||
return NULL;
|
||||
}
|
||||
return dot;
|
||||
}
|
||||
|
||||
static bool path_has_extension(const char *path) {
|
||||
return (path_extension(path) != NULL);
|
||||
}
|
||||
|
||||
// true when two extensions denote the same kind of file, ie ".mfd" and ".bin"
|
||||
// are both binary. Classified with get_filetype() so the save path and the
|
||||
// load path can never drift apart.
|
||||
static bool same_filetype(const char *ext_a, const char *ext_b) {
|
||||
if (ext_a == NULL || ext_b == NULL) {
|
||||
return false;
|
||||
}
|
||||
char a[64] = {0};
|
||||
char b[64] = {0};
|
||||
snprintf(a, sizeof(a), "dump%s", ext_a);
|
||||
snprintf(b, sizeof(b), "dump%s", ext_b);
|
||||
return (get_filetype(a) == get_filetype(b));
|
||||
}
|
||||
|
||||
static int qsort_path_cmp(const void *a, const void *b) {
|
||||
const char *pa = (const char *)a;
|
||||
const char *pb = (const char *)b;
|
||||
@@ -462,26 +491,30 @@ char *newfilenamemcopyEx(const char *preferredName, const char *suffix, savePath
|
||||
}
|
||||
}
|
||||
|
||||
// remove file extension if exist in name
|
||||
// strip the extension the name came with, if any, and decide which one to write.
|
||||
// An extension of the same kind as the file we are about to write is the user's
|
||||
// choice, keep it, `-f card.mfd` saves the binary as card.mfd.
|
||||
// Any other is swapped for ours, so the same `-f card.mfd` saves the json as
|
||||
// card.json instead of card.mfd.json
|
||||
size_t p_namelen = strlen(expanded);
|
||||
if (str_endswith(expanded, suffix)) {
|
||||
p_namelen -= strlen(suffix);
|
||||
const char *ext = suffix;
|
||||
|
||||
const char *p_ext = path_extension(expanded);
|
||||
if (p_ext != NULL) {
|
||||
if (same_filetype(p_ext, suffix)) {
|
||||
ext = p_ext;
|
||||
}
|
||||
p_namelen -= strlen(p_ext);
|
||||
}
|
||||
|
||||
len -= strlen(suffix) + 1;
|
||||
len -= p_namelen;
|
||||
|
||||
// modify filename
|
||||
snprintf(pfn, len, "%.*s%s", (int)p_namelen, expanded, suffix);
|
||||
|
||||
// "-001"
|
||||
len -= 4;
|
||||
// modify filename. len is what is left of fileName from pfn onwards
|
||||
snprintf(pfn, len, "%.*s%s", (int)p_namelen, expanded, ext);
|
||||
|
||||
int num = 1;
|
||||
// check complete path/filename if exists
|
||||
while (fileExists(fileName)) {
|
||||
// modify filename
|
||||
snprintf(pfn, len, "%.*s-%03d%s", (int)p_namelen, expanded, num, suffix);
|
||||
snprintf(pfn, len, "%.*s-%03d%s", (int)p_namelen, expanded, num, ext);
|
||||
num++;
|
||||
}
|
||||
|
||||
@@ -3941,12 +3974,42 @@ int searchFile(char **foundpath, const char *pm3dir, const char *searchname, con
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
int res = searchFinalFile(foundpath, pm3dir, filename, silent);
|
||||
if (res != PM3_SUCCESS) {
|
||||
if ((res == PM3_EFILE) && (!silent)) {
|
||||
PrintAndLogEx(FAILED, "Error - can't find `" _YELLOW_("%s") "`", filename);
|
||||
// the given name already carries an extension of its own, ie `-f dump.mfd`
|
||||
// while the caller asks for ".bin". Honour what the user typed before
|
||||
// falling back to dump.mfd.bin
|
||||
int res = PM3_EFILE;
|
||||
char *asis = NULL;
|
||||
if (path_has_extension(searchname) && (str_endswith(searchname, suffix) == false)) {
|
||||
|
||||
asis = filenamemcopy(searchname, "");
|
||||
if (asis == NULL) {
|
||||
free(filename);
|
||||
return PM3_EMALLOC;
|
||||
}
|
||||
|
||||
if ((strlen(asis) == 0) || path_is_directory(asis)) {
|
||||
free(asis);
|
||||
asis = NULL;
|
||||
} else {
|
||||
res = searchFinalFile(foundpath, pm3dir, asis, silent);
|
||||
}
|
||||
}
|
||||
|
||||
if (res != PM3_SUCCESS) {
|
||||
res = searchFinalFile(foundpath, pm3dir, filename, silent);
|
||||
}
|
||||
|
||||
if (res != PM3_SUCCESS) {
|
||||
if ((res == PM3_EFILE) && (!silent)) {
|
||||
if (asis != NULL) {
|
||||
PrintAndLogEx(FAILED, "Error - can't find `" _YELLOW_("%s") "` nor `" _YELLOW_("%s") "`", asis, filename);
|
||||
} else {
|
||||
PrintAndLogEx(FAILED, "Error - can't find `" _YELLOW_("%s") "`", filename);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
free(asis);
|
||||
free(filename);
|
||||
return res;
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user