diff --git a/src/namedos.c b/src/namedos.c index 993f49b..ef50f01 100644 --- a/src/namedos.c +++ b/src/namedos.c @@ -178,6 +178,54 @@ static int dos83_same_plain_family(const uint8 *a, const uint8 *b) return !strcmp((char *)aa, (char *)bb); } +static int dos83_compute_family_rank(const char *dir_unix, + const uint8 *src, + int options) +{ + DIR *d; + struct dirent *dirbuff; + int rank = 0; + + if (!dir_unix) + return 0; + + d = opendir(dir_unix); + if (!d) { + if (seteuid(0)) {} + d = opendir(dir_unix); + reseteuid(); + } + if (!d) + return 0; + + while ((dirbuff = readdir(d)) != NULL) { + if (!dirbuff->d_ino) + continue; + if (!strcmp(dirbuff->d_name, ".") || !strcmp(dirbuff->d_name, "..")) + continue; + if (!strcmp(dirbuff->d_name, (const char *)src)) + break; + + if (!dos83_is_valid_name((uint8 *)dirbuff->d_name, options) && + dos83_same_plain_family((uint8 *)dirbuff->d_name, src)) + rank++; + } + + closedir(d); + return rank; +} + +static void dos83_build_ranked_alias(const uint8 *src, + int rank, + uint8 *out, + int out_size) +{ + if (rank <= 0) + dos83_build_plain_alias(src, out, out_size); + else + dos83_build_alias_candidate(src, rank, out, out_size); +} + static int dos83_alias_used_in_dir(const char *dir_unix, const uint8 *src, const uint8 *candidate, @@ -185,6 +233,7 @@ static int dos83_alias_used_in_dir(const char *dir_unix, { DIR *d; struct dirent *dirbuff; + int src_rank = dos83_compute_family_rank(dir_unix, src, options); d = opendir(dir_unix); if (!d) { @@ -196,10 +245,11 @@ static int dos83_alias_used_in_dir(const char *dir_unix, return 0; XDPRINTF((2,0, - "DOS83 COLLISION CHECK dir='%s' src='%s' candidate='%s'", + "DOS83 COLLISION CHECK dir='%s' src='%s' candidate='%s' src_rank=%d", dir_unix ? dir_unix : "(null)", src ? (char *)src : "(null)", - candidate ? (char *)candidate : "(null)")); + candidate ? (char *)candidate : "(null)", + src_rank)); while ((dirbuff = readdir(d)) != NULL) { uint8 other[DOS83_NAME_MAX + 1]; @@ -211,27 +261,44 @@ static int dos83_alias_used_in_dir(const char *dir_unix, if (!strcmp(dirbuff->d_name, (const char *)src)) continue; - if (!dos83_is_valid_name((uint8 *)dirbuff->d_name, options)) - continue; + if (dos83_is_valid_name((uint8 *)dirbuff->d_name, options)) { + strncpy((char *)other, dirbuff->d_name, sizeof(other) - 1); + other[sizeof(other) - 1] = '\0'; + up_fn(other); - strncpy((char *)other, dirbuff->d_name, sizeof(other) - 1); - other[sizeof(other) - 1] = '\0'; - up_fn(other); - - XDPRINTF((2,0, - "DOS83 COLLISION EXISTING8 raw='%s' alias='%s' candidate='%s'", - dirbuff->d_name, - other, - candidate)); - - if (!strcmp((char *)other, (const char *)candidate)) { XDPRINTF((2,0, - "DOS83 COLLISION HIT EXISTING8 raw='%s' alias='%s' candidate='%s'", + "DOS83 COLLISION EXISTING8 raw='%s' alias='%s' candidate='%s'", dirbuff->d_name, other, candidate)); - closedir(d); - return 1; + + if (!strcmp((char *)other, (const char *)candidate)) { + closedir(d); + return 1; + } + continue; + } + + if (dos83_same_plain_family((uint8 *)dirbuff->d_name, src)) { + int other_rank = dos83_compute_family_rank(dir_unix, + (uint8 *)dirbuff->d_name, + options); + dos83_build_ranked_alias((uint8 *)dirbuff->d_name, + other_rank, + other, + sizeof(other)); + + XDPRINTF((2,0, + "DOS83 COLLISION FAMILY raw='%s' alias='%s' candidate='%s' other_rank=%d", + dirbuff->d_name, + other, + candidate, + other_rank)); + + if (!strcmp((char *)other, (const char *)candidate)) { + closedir(d); + return 1; + } } } @@ -245,9 +312,7 @@ int dos83_build_name_in_dir(const char *dir_unix, int out_size, int options) { - char base[260], ext[260]; - char nbase[9], next[4]; - int seq; + int rank; if (!src || !*src || !out || out_size <= 0) return 0; @@ -265,81 +330,31 @@ int dos83_build_name_in_dir(const char *dir_unix, return (int)strlen((char *)out); } - dos83_split_name(src, base, sizeof(base), ext, sizeof(ext)); - dos83_normalize_part(base, nbase, sizeof(nbase), 8); - dos83_normalize_part(ext, next, sizeof(next), 3); + rank = dos83_compute_family_rank(dir_unix, src, options); + dos83_build_ranked_alias(src, rank, out, out_size); - if (*nbase) { - if (*next) - snprintf((char *)out, out_size, "%s.%s", nbase, next); - else - snprintf((char *)out, out_size, "%s", nbase); + XDPRINTF((2,0, + "DOS83 BUILD dir='%s' src='%s' out='%s' valid=%d rank=%d", + dir_unix ? dir_unix : "(null)", + src ? (char *)src : "(null)", + out ? (char *)out : "(null)", + dos83_is_valid_name(src, options), + rank)); - if (!dir_unix || !dos83_alias_used_in_dir(dir_unix, src, out, options)) { + if (dir_unix && dos83_alias_used_in_dir(dir_unix, src, out, options)) { + int seq = rank > 0 ? rank : 1; + do { + seq++; + dos83_build_alias_candidate(src, seq, out, out_size); XDPRINTF((2,0, - "DOS83 BUILD dir='%s' src='%s' out='%s' valid=%d", + "DOS83 BUILD retry dir='%s' src='%s' out='%s' seq=%d", dir_unix ? dir_unix : "(null)", src ? (char *)src : "(null)", out ? (char *)out : "(null)", - dos83_is_valid_name(src, options))); - return (int)strlen((char *)out); - } + seq)); + } while (seq < 1000000 && dos83_alias_used_in_dir(dir_unix, src, out, options)); } - /* - * Number colliding long names by their directory order within the same - * unnumbered alias family. This gives stable ~1, ~2, ... aliases without - * comparing against hypothetical aliases of every other long filename. - */ - seq = 1; - if (dir_unix) { - DIR *d = opendir(dir_unix); - if (!d) { - if (seteuid(0)) {} - d = opendir(dir_unix); - reseteuid(); - } - - if (d) { - struct dirent *dirbuff; - while ((dirbuff = readdir(d)) != NULL) { - if (!dirbuff->d_ino) - continue; - if (!strcmp(dirbuff->d_name, ".") || !strcmp(dirbuff->d_name, "..")) - continue; - - if (!strcmp(dirbuff->d_name, (const char *)src)) - break; - - if (!dos83_is_valid_name((uint8 *)dirbuff->d_name, options) && - dos83_same_plain_family((uint8 *)dirbuff->d_name, src)) { - seq++; - XDPRINTF((2,0, - "DOS83 FAMILY PRIOR raw='%s' src='%s' seq_now=%d", - dirbuff->d_name, - src, - seq)); - } - } - closedir(d); - } - } - - for (; seq < 1000000; seq++) { - dos83_build_alias_candidate(src, seq, out, out_size); - if (!dir_unix || !dos83_alias_used_in_dir(dir_unix, src, out, options)) { - XDPRINTF((2,0, - "DOS83 BUILD dir='%s' src='%s' out='%s' valid=%d", - dir_unix ? dir_unix : "(null)", - src ? (char *)src : "(null)", - out ? (char *)out : "(null)", - dos83_is_valid_name(src, options))); - return (int)strlen((char *)out); - } - } - - strncpy((char *)out, "FILE~1", out_size - 1); - out[out_size - 1] = '\0'; return (int)strlen((char *)out); }