From 80f0debf2032e16629cb13682b8fb9ceccde423c Mon Sep 17 00:00:00 2001 From: Eduardo Casino Date: Tue, 24 May 2022 07:58:48 +0200 Subject: Add support for hash-generated short file names --- sftsr.c | 132 +++++++++++++++++++++++++++++++++++++++------------------------- 1 file changed, 81 insertions(+), 51 deletions(-) (limited to 'sftsr.c') diff --git a/sftsr.c b/sftsr.c index b6d89c2..9282c58 100644 --- a/sftsr.c +++ b/sftsr.c @@ -54,9 +54,12 @@ TSRDATA data = { 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0 } }; -#define __IN_SFTSR__ 1 -#include "unicode.h" -#include "nls.h" +static union { + SHFLVOLINFO volinfo; + SHFLFSOBJINFO objinfo; + SHFLCREATEPARMS create; +} parms; + /** Private buffer for VirtualBox filenames. */ static SHFLSTRING_WITH_BUF(shflstr, SHFL_MAX_LEN); @@ -64,11 +67,10 @@ static SHFLSTRING_WITH_BUF(shflstr, SHFL_MAX_LEN); /** Private buffer where we store VirtualBox-obtained dir entries. */ static SHFLDIRINFO_WITH_NAME_BUF(shfldirinfo, SHFL_MAX_LEN); -static union { - SHFLVOLINFO volinfo; - SHFLFSOBJINFO objinfo; - SHFLCREATEPARMS create; -} parms; +#define __IN_SFTSR__ 1 +#include "unicode.h" +#include "nls.h" +#include "lfn.h" static uint8_t map_shfl_attr_to_dosattr(const SHFLFSOBJATTR *a) { @@ -233,13 +235,11 @@ static int my_strrchr(const char __far *str, char c) return last; } -static inline bool translate_filename_from_host(SHFLSTRING *str) +static inline bool translate_filename_from_host(SHFLSTRING *str, bool case_insensitive) { - bool valid; + bool valid = utf8_to_local(&data, str->ach, str->ach, &str->u16Length); - valid = utf8_to_local( &data, str->ach, str->ach, &str->u16Length); - - nls_uppercase(str); + valid = (nls_uppercase(str) || case_insensitive) && valid; return valid; } @@ -287,22 +287,38 @@ static void fix_wildcards(SHFLSTRING *str) str->ach[i] = '*'; } } + + // If there is a '~' in the pattern search, assume that this is a shortened + // file name. Nothing to do for windows short names, as they exist in the + // host, but for the hash ones, we have to replace the tilde and any following + // characters with an '*' + if (!data.short_fnames) { + for (i = 0; i < str->u16Length; i++) { + if ( str->ach[i] == '~') { + strcpy(&str->ach[i], "*"); + str->u16Length = i + 1; + break; + } + } + } } -static void copy_drive_relative_filename(SHFLSTRING *str, const char __far *path) +static void copy_drive_relative_filename(SHFLROOT root, SHFLSTRING *str, char __far *path) { - // Assume X:.... path for now, i.e. drive_relative path starts at char 2 - str->u16Length = local_to_utf8( &data, str->ach, path + 2, str->u16Size ); + // Assume X:.... path for now, i.e. drive_relative path starts at char + + str->u16Length = get_true_host_name( root, &data, str->ach, path + 2, str->u16Size ); + } -static void copy_drive_relative_dirname(SHFLSTRING *str, const char __far *path) +static void copy_drive_relative_dirname(SHFLROOT root, SHFLSTRING *str, char __far *path) { int last_sep = my_strrchr(path + 2, '\\'); if (last_sep >= 0) { - str->u16Length = local_to_utf8_n( &data, str->ach, path + 2, str->u16Size, last_sep == 0 ? 1 : last_sep ); + str->u16Length = get_true_host_name_n( root, &data, str->ach, path + 2, str->u16Size, last_sep == 0 ? 1 : last_sep ); } else { - str->u16Length = local_to_utf8( &data, str->ach, path + 2, str->u16Size ); + str->u16Length = get_true_host_name( root, &data, str->ach, path + 2, str->u16Size ); } } @@ -460,7 +476,7 @@ static void flush_sft_metadata(DOSSFT __far *sft) static void handle_create_open_ex(union INTPACK __far *r) { - const char __far *path = data.dossda->fn1; + char __far *path = data.dossda->fn1; int drive = drive_letter_to_index(path[0]); SHFLROOT root = data.drives[drive].root; DOSSFT __far *sft = MK_FP(r->w.es, r->w.di); @@ -496,7 +512,7 @@ static void handle_create_open_ex(union INTPACK __far *r) return; } - copy_drive_relative_filename(&shflstr.shflstr, path); + copy_drive_relative_filename(root, &shflstr.shflstr, path); memset(&parms.create, 0, sizeof(SHFLCREATEPARMS)); if (action & OPENEX_REPLACE_IF_EXISTS) { @@ -833,14 +849,14 @@ static void handle_close_all(union INTPACK __far *r) static void handle_delete(union INTPACK __far *r) { - const char __far *path = data.dossda->fn1; + char __far *path = data.dossda->fn1; int drive = drive_letter_to_index(path[0]); SHFLROOT root = data.drives[drive].root; vboxerr err; dprintf("handle_delete %Fs\n", path); - copy_drive_relative_filename(&shflstr.shflstr, path); + copy_drive_relative_filename(root, &shflstr.shflstr, path); err = vbox_shfl_remove(&data.vb, data.hgcm_client_id, root, &shflstr.shflstr, SHFL_REMOVE_FILE); @@ -854,9 +870,9 @@ static void handle_delete(union INTPACK __far *r) static void handle_rename(union INTPACK __far *r) { - const char __far *src = data.dossda->fn1; + char __far *src = data.dossda->fn1; int srcdrive = drive_letter_to_index(src[0]); - const char __far *dst = data.dossda->fn2; + char __far *dst = data.dossda->fn2; int dstdrive = drive_letter_to_index(dst[0]); SHFLROOT root = data.drives[srcdrive].root; vboxerr err; @@ -868,10 +884,10 @@ static void handle_rename(union INTPACK __far *r) return; } - copy_drive_relative_filename(&shflstr.shflstr, src); + copy_drive_relative_filename(root, &shflstr.shflstr, src); // Reusing shfldirinfo buffer space here for our second filename - copy_drive_relative_filename(&shfldirinfo.dirinfo.name, dst); + copy_drive_relative_filename(root, &shfldirinfo.dirinfo.name, dst); err = vbox_shfl_rename(&data.vb, data.hgcm_client_id, root, &shflstr.shflstr, &shfldirinfo.dirinfo.name, @@ -886,14 +902,14 @@ static void handle_rename(union INTPACK __far *r) static void handle_getattr(union INTPACK __far *r) { - const char __far *path = data.dossda->fn1; + char __far *path = data.dossda->fn1; int drive = drive_letter_to_index(path[0]); SHFLROOT root = data.drives[drive].root; vboxerr err; dprintf("handle_getattr %Fs\n", path); - copy_drive_relative_filename(&shflstr.shflstr, path); + copy_drive_relative_filename(root, &shflstr.shflstr, path); memset(&parms.create, 0, sizeof(SHFLCREATEPARMS)); parms.create.CreateFlags = SHFL_CF_LOOKUP; @@ -929,13 +945,13 @@ static void handle_setattr(union INTPACK __far *r) /** Opens directory corresponding to file in path (i.e. we use the dirname), * filling corresponding openfile entry. */ -static vboxerr open_search_dir(unsigned openfile, SHFLROOT root, const char __far *path) +static vboxerr open_search_dir(unsigned openfile, SHFLROOT root, char __far *path) { vboxerr err; dprintf("open_search_dir openfile=%u path=%Fs\n", openfile, path); - copy_drive_relative_dirname(&shflstr.shflstr, path); + copy_drive_relative_dirname(root, &shflstr.shflstr, path); memset(&parms.create, 0, sizeof(SHFLCREATEPARMS)); parms.create.CreateFlags = SHFL_CF_DIRECTORY @@ -980,7 +996,7 @@ static vboxerr find_volume_label(SHFLROOT root) err = vbox_shfl_query_map_name(&data.vb, data.hgcm_client_id, root, &shflstr.shflstr); if (err) return err; - (void) translate_filename_from_host(&shflstr.shflstr); + (void) translate_filename_from_host(&shflstr.shflstr, false); dprintf("label: %s\n", shflstr.buf); @@ -995,12 +1011,15 @@ static vboxerr find_volume_label(SHFLROOT root) } /** Gets and fills in the next directory entry from VirtualBox. */ -static vboxerr find_next_from_vbox(unsigned openfile, const char __far *path) +static vboxerr find_next_from_vbox(unsigned openfile, char __far *path) { + int drive = drive_letter_to_index(path[0]); + SHFLROOT root = data.drives[drive].root; DOSSDB __far *sdb = &data.dossda->sdb; DOSDIR __far *found_file = &data.dossda->found_file; uint16_t search_mask; vboxerr err; + uint32_t hash; // Always accept files with these attributes, even if mask says otherwise search_mask = ~(sdb->search_attr | _A_ARCH | _A_RDONLY); @@ -1009,7 +1028,7 @@ static vboxerr find_next_from_vbox(unsigned openfile, const char __far *path) // a correct absolute mask with the correct wildcards; // this is what VirtualBox will use in future calls. if (path) { - copy_drive_relative_filename(&shflstr.shflstr, path); + copy_drive_relative_filename(root, &shflstr.shflstr, path); fix_wildcards(&shflstr.shflstr); dprintf("fixed path=%s\n", shflstr.buf); @@ -1026,6 +1045,7 @@ static vboxerr find_next_from_vbox(unsigned openfile, const char __far *path) while (1) { // Loop until we have a valid file (or an error) unsigned size = sizeof(shfldirinfo), resume = 0, count = 0; + bool valid; err = vbox_shfl_list(&data.vb, data.hgcm_client_id, data.files[openfile].root, data.files[openfile].handle, @@ -1065,9 +1085,14 @@ static vboxerr find_next_from_vbox(unsigned openfile, const char __far *path) } // Now convert the filename - // Use the short filename if available from a windows host + + // Calculate hash using host file name + hash = lfn_name_hash( shfldirinfo.dirinfo.name.ach, shfldirinfo.dirinfo.name.u16Length ); + if (data.short_fnames && shfldirinfo.dirinfo.cucShortName != 0) { - if (!utf16_to_local( &data, &shfldirinfo.dirinfo.name.ach, &shfldirinfo.dirinfo.uszShortName, shfldirinfo.dirinfo.cucShortName)) { + valid = utf16_to_local( &data, &shfldirinfo.dirinfo.name.ach, &shfldirinfo.dirinfo.uszShortName, shfldirinfo.dirinfo.cucShortName); + + if (!valid) { // Should not happen as Windows short names are pure ascii dputs("hiding file with illegal character(s)"); continue; @@ -1075,14 +1100,19 @@ static vboxerr find_next_from_vbox(unsigned openfile, const char __far *path) shfldirinfo.dirinfo.name.u16Length = shfldirinfo.dirinfo.cucShortName; dprintf(" Host short filename: '%s'\n", shfldirinfo.dirinfo.name.ach); } - else if (!translate_filename_from_host(&shfldirinfo.dirinfo.name)) { - dputs("hiding file with illegal character(s)"); - continue; + else { + valid = translate_filename_from_host(&shfldirinfo.dirinfo.name, data.drives[drive].case_insensitive); } - - if (!copy_to_8_3_filename(found_file->filename, &shfldirinfo.dirinfo.name)) { - dputs("hiding file with long filename"); - continue; + + if (valid) { + if (!copy_to_8_3_filename(found_file->filename, &shfldirinfo.dirinfo.name)) { + dputs("Mangling long filename"); + mangle_to_8_3_filename(hash, found_file->filename, &shfldirinfo.dirinfo.name); + } + } + else { + dputs("Mangling filename with illegal character(s)"); + mangle_to_8_3_filename(hash, found_file->filename, &shfldirinfo.dirinfo.name); } if (!matches_8_3_wildcard(found_file->filename, sdb->search_templ)) { @@ -1107,7 +1137,7 @@ static vboxerr find_next_from_vbox(unsigned openfile, const char __far *path) * Return the results in dossda.found_file (see find_next). */ static void handle_find_first(union INTPACK __far *r) { - const char __far *path = data.dossda->fn1; + char __far *path = data.dossda->fn1; const char __far *search_mask = data.dossda->fcb_fn1; int drive = drive_letter_to_index(path[0]); SHFLROOT root = data.drives[drive].root; @@ -1141,7 +1171,7 @@ static void handle_find_first(union INTPACK __far *r) dputs("search volid OK"); clear_dos_err(r); return; - } + } // First, open the desired directory for searching openfile = find_free_openfile(); @@ -1224,7 +1254,7 @@ static void handle_find_next(union INTPACK __far *r) static void handle_chdir(union INTPACK __far *r) { - const char __far *path = data.dossda->fn1; + char __far *path = data.dossda->fn1; int drive = drive_letter_to_index(path[0]); SHFLROOT root = data.drives[drive].root; vboxerr err; @@ -1232,7 +1262,7 @@ static void handle_chdir(union INTPACK __far *r) dprintf("handle_chdir %Fs\n", path); // Just have to check if the directory exists - copy_drive_relative_filename(&shflstr.shflstr, path); + copy_drive_relative_filename(root, &shflstr.shflstr, path); memset(&parms.create, 0, sizeof(SHFLCREATEPARMS)); parms.create.CreateFlags = SHFL_CF_LOOKUP; @@ -1264,14 +1294,14 @@ static void handle_chdir(union INTPACK __far *r) static void handle_mkdir(union INTPACK __far *r) { - const char __far *path = data.dossda->fn1; + char __far *path = data.dossda->fn1; int drive = drive_letter_to_index(path[0]); SHFLROOT root = data.drives[drive].root; vboxerr err; dprintf("handle_mkdir %Fs\n", path); - copy_drive_relative_filename(&shflstr.shflstr, path); + copy_drive_relative_filename(root, &shflstr.shflstr, path); memset(&parms.create, 0, sizeof(SHFLCREATEPARMS)); parms.create.CreateFlags = SHFL_CF_DIRECTORY @@ -1304,14 +1334,14 @@ static void handle_mkdir(union INTPACK __far *r) static void handle_rmdir(union INTPACK __far *r) { - const char __far *path = data.dossda->fn1; + char __far *path = data.dossda->fn1; int drive = drive_letter_to_index(path[0]); SHFLROOT root = data.drives[drive].root; vboxerr err; dprintf("handle_rmdir %Fs\n", path); - copy_drive_relative_filename(&shflstr.shflstr, path); + copy_drive_relative_filename(root, &shflstr.shflstr, path); err = vbox_shfl_remove(&data.vb, data.hgcm_client_id, root, &shflstr.shflstr, SHFL_REMOVE_DIR); -- cgit v1.2.3