From 7b243074da3f4be6ed47426925f203c547c1c729 Mon Sep 17 00:00:00 2001 From: Eduardo Casino Date: Mon, 16 May 2022 20:12:19 +0200 Subject: Add support for windows host short file names --- nls.h | 78 +++++++++++++++++++++++++++++++++++++++++++++++++++++ sfmain.c | 24 +++++++++++------ sftsr.c | 92 ++++++++++++++++++++------------------------------------------- sftsr.h | 2 ++ unicode.h | 42 +++++++++++++++++++++++++---- 5 files changed, 162 insertions(+), 76 deletions(-) create mode 100644 nls.h diff --git a/nls.h b/nls.h new file mode 100644 index 0000000..9699bb1 --- /dev/null +++ b/nls.h @@ -0,0 +1,78 @@ +/* + * VBSF - NLS support functions + * Copyright (C) 2011-2022 Eduardo Casino + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General License for more details. + * + * You should have received a copy of the GNU General License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef NLS_H +#define NLS_H + +static bool illegal_char( unsigned char c ) +{ + int i= 0; + + for ( i= 0; i < data.file_char->n_illegal; ++i ) + { + if ( c == data.file_char->illegal[i] ) + { + return true; + } + } + if ( ( c < data.file_char->lowest || c > data.file_char->highest ) || + !( c < data.file_char->first_x || c > data.file_char->last_x ) ) + { + return true; + } + + return false; +} + +static unsigned char nls_toupper( unsigned char c ) +{ + if ( c > 0x60 && c < 0x7b ) + { + return c & 0xDF; + } + + return ( c < 0x80 ? c : data.file_upper_case[c - 0x80] ); +} + +static inline void nls_uppercase(SHFLSTRING *str) +{ + int i; + + for (i= 0; i < str->u16Length; ++i) + { + str->ach[i] = nls_toupper(str->ach[i]); + } +} + +static inline bool valid_8_3_file_chars(char __far *fname ) +{ + int i; + + for (i = 0; i < 11; ++i) + { + if ( fname[i] != ' ' && illegal_char(fname[i]) ) + { + break; + } + } + + return ( i == 11 ); +} + +#endif // NLS_H diff --git a/sfmain.c b/sfmain.c index 9432508..3cbd336 100644 --- a/sfmain.c +++ b/sfmain.c @@ -452,7 +452,7 @@ error: } -static int configure_driver(LPTSRDATA data) +static int configure_driver(LPTSRDATA data, bool short_fnames) { unsigned i; int32_t err; @@ -481,6 +481,16 @@ static int configure_driver(LPTSRDATA data) data->tz_offset = 0; } + // Get uppercase and valid file char tables + err = get_nls(&data->file_upper_case, &data->file_char); + if (err) { + puts("Cannot get the NLS tables."); + return -1; + } + + // Set use of short file names from Windows hosts + data->short_fnames = short_fnames; + // Now try to initialize VirtualBox communication err = vbox_init_device(&data->vb); if (err) { @@ -512,12 +522,6 @@ static int configure_driver(LPTSRDATA data) return -1; } - err = get_nls(&data->file_upper_case, &data->file_char); - if (err) { - puts("Cannot get the NLS tables."); - return -1; - } - load_unicode_table( &data->unicode_table); printf("Connected to VirtualBox shared folder service\n"); @@ -617,6 +621,7 @@ static void print_help(void) "Supported actions:\n" " install install the driver (default)\n" " low install in conventional memory (otherwise UMB)\n" + " short use short file names from windows hosts\n" " uninstall uninstall the driver from memory\n" " list list available shared folders\n" " mount mount a shared folder into drive X:\n" @@ -668,6 +673,7 @@ int main(int argc, const char *argv[]) if (argi >= argc || stricmp(argv[argi], "install") == 0) { bool high = true; + bool short_fnames = false; argi++; for (; argi < argc; argi++) { @@ -675,6 +681,8 @@ int main(int argc, const char *argv[]) high = false; } else if (stricmp(argv[argi], "high") == 0) { high = true; + } else if (stricmp(argv[argi], "short") == 0) { + short_fnames = true; } else { return invalid_arg(argv[argi]); } @@ -695,7 +703,7 @@ int main(int argc, const char *argv[]) } else { deallocate_environment(_psp); } - err = configure_driver(data); + err = configure_driver(data, short_fnames); if (err) { if (high) cancel_reallocation(FP_SEG(data)); return EXIT_FAILURE; diff --git a/sftsr.c b/sftsr.c index 5819ce5..86fb5b9 100644 --- a/sftsr.c +++ b/sftsr.c @@ -25,8 +25,6 @@ #include "unixtime.h" #include "vboxshfl.h" #include "sftsr.h" -#define __IN_SFTSR__ 1 -#include "unicode.h" TSRDATA data = { // TSR installation data @@ -56,6 +54,10 @@ TSRDATA data = { 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0 } }; +#define __IN_SFTSR__ 1 +#include "unicode.h" +#include "nls.h" + /** Private buffer for VirtualBox filenames. */ static SHFLSTRING_WITH_BUF(shflstr, SHFL_MAX_LEN); @@ -231,6 +233,17 @@ static int my_strrchr(const char __far *str, char c) return last; } +static inline bool translate_filename_from_host(SHFLSTRING *str) +{ + bool valid; + + valid = utf8_to_local( &data, str->ach, str->ach, &str->u16Length); + + nls_uppercase(str); + + return valid; +} + static const char * get_basename(const char *path) { int last_sep = my_strrchr(path, '\\'); @@ -241,61 +254,6 @@ static const char * get_basename(const char *path) } } -static bool illegal_char( unsigned char c ) -{ - int i= 0; - - for ( i= 0; i < data.file_char->n_illegal; ++i ) - { - if ( c == data.file_char->illegal[i] ) - { - return true; - } - } - if ( ( c < data.file_char->lowest || c > data.file_char->highest ) || - !( c < data.file_char->first_x || c > data.file_char->last_x ) ) - { - return true; - } - - return false; -} - -static unsigned char nls_toupper( unsigned char c ) -{ - if ( c > 0x60 && c < 0x7b ) - { - return c & 0xDF; - } - - return ( c < 0x80 ? c : data.file_upper_case[c - 0x80] ); -} - -static inline bool translate_filename_from_host(SHFLSTRING *str) -{ - unsigned i; - bool ret; - unsigned dots = 0; - - ret = utf8_to_local(&data, str->ach, str->ach, &str->u16Length); - - for (i = 0; i < str->u16Length; i++) { - if (str->ach[i] == '.') { - ++dots; - } - else { - if (illegal_char(str->ach[i])) { - ret = false; - } - else { - str->ach[i] = nls_toupper(str->ach[i]); - } - } - } - - return ret && (dots <= 1); -} - /** Tries to do some very simple heuristics to convert DOS-style wildcards * into win32-like (as expected by VirtualBox). */ static void fix_wildcards(SHFLSTRING *str) @@ -352,7 +310,7 @@ static bool copy_to_8_3_filename(char __far *dst, const SHFLSTRING *str) { int last_dot = my_strrchr(str->ach, '.'); unsigned namelen, extlen; - bool valid_8_3 = true; + bool valid_8_3 = true, dotfile = false; namelen = last_dot >= 0 ? last_dot : str->u16Length; extlen = last_dot >= 0 ? str->u16Length - (last_dot + 1) : 0; @@ -361,6 +319,7 @@ static bool copy_to_8_3_filename(char __far *dst, const SHFLSTRING *str) // . , .. files namelen = str->u16Length; extlen = 0; + dotfile = true; } if (namelen == 0) { @@ -381,7 +340,7 @@ static bool copy_to_8_3_filename(char __far *dst, const SHFLSTRING *str) _fmemcpy(&dst[8], str->ach + last_dot + 1, extlen); _fmemset(&dst[8+extlen], ' ', 3 - extlen); - return valid_8_3; + return valid_8_3 && (dotfile || valid_8_3_file_chars(dst)); } static bool is_8_3_wildcard(const char __far *name) @@ -1089,10 +1048,17 @@ static vboxerr find_next_from_vbox(unsigned openfile, const char __far *path) } // Now convert the filename - // TODO Use the short filename if available from a windows host - // i.e. shfldirinfo.dirinfo.cucShortName - - if (!translate_filename_from_host(&shfldirinfo.dirinfo.name)) { + // Use the short filename if available from a windows host + if (data.short_fnames && shfldirinfo.dirinfo.cucShortName != 0) { + if (!utf16_to_local( &data, &shfldirinfo.dirinfo.name.ach, &shfldirinfo.dirinfo.uszShortName, shfldirinfo.dirinfo.cucShortName)) { + // Should not happen as Windows short names are pure ascii + dputs("hiding file with illegal character(s)"); + continue; + } + 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; } diff --git a/sftsr.h b/sftsr.h index f318bd4..c832169 100644 --- a/sftsr.h +++ b/sftsr.h @@ -72,6 +72,8 @@ typedef struct { FCHAR __far *file_char; /** Codepage to unicode lookup table. */ uint16_t unicode_table[128]; + /** LFN support */ + bool short_fnames; // Current status /** Array of all possible DOS drives. */ diff --git a/unicode.h b/unicode.h index 9e70895..81d187a 100644 --- a/unicode.h +++ b/unicode.h @@ -1,8 +1,5 @@ /* - * VBSF - unix to DOS time conversion - * Copyright (C) 2022 Javier S. Pedro - * - * unicode.h: Unicode conversion routines + * VBSF - Unicode conversion routines * Copyright (C) 2011-2022 Eduardo Casino * * This program is free software; you can redistribute it and/or @@ -212,4 +209,39 @@ cont: } -#endif +// Returns true on success, false if any unsupported char is found +// +static bool utf16_to_local( TSRDATAPTR data, uint8_t *dst, uint16_t *src, uint16_t len ) +{ + bool ret = true; + int i; + uint16_t cp; + uint8_t c; + + for ( i = 0; i < len; ++i ) + { + cp = src[i]; + + if ( cp < 0x80 ) + { + *dst++ = ( uint8_t ) cp; + } + else + { + c = lookup_codepage( data, cp ); + if ( c == '\0' ) + { + c = '_'; + ret = false; + } + *dst++ = c; + } + } + + *dst = '\0'; + + return ret; + +} + +#endif // UNICODE_H -- cgit v1.2.3