From 4caf0a87957abbeb4a23db72a766723a0d452f0b Mon Sep 17 00:00:00 2001 From: Mario Fetka Date: Wed, 20 May 2026 15:11:31 +0200 Subject: [PATCH] 2nd try --- include/namedos.h | 8 +- src/namedos.c | 343 ++++++++++++++++++++++++++++++---------------- src/namspace.c | 67 ++++----- 3 files changed, 253 insertions(+), 165 deletions(-) diff --git a/include/namedos.h b/include/namedos.h index 8306afe..76d6976 100644 --- a/include/namedos.h +++ b/include/namedos.h @@ -1,12 +1,14 @@ /* - * namedos.h: 08-Aug-96 - * - * (C)opyright (C) 1993,1996 Martin Stover, Marburg, Germany + * namedos.h: DOS namespace helpers for mars_nwe */ #ifndef _NAMEDOS_H_ #define _NAMEDOS_H_ #if WITH_NAME_SPACE_CALLS +extern int dos_is_83_name(uint8 *name, int options); +extern int build_dos_83_alias(int options, uint8 *parent_unix, + uint8 *real_name, ino_t inode, + uint8 *alias, int alias_len); extern void mangle_dos_name(NW_VOL *vol, uint8 *unixname, uint8 *pp, int len); extern int fn_dos_match(uint8 *s, uint8 *p, int soptions); diff --git a/src/namedos.c b/src/namedos.c index 7ec0c72..ae148d0 100644 --- a/src/namedos.c +++ b/src/namedos.c @@ -1,24 +1,16 @@ -/* nameos2.c 14-May-97 : NameSpace DOS Services, mars_nwe */ -/* (C)opyright (C) 1993,1996 Martin Stover, Marburg, Germany +/* namedos.c : NameSpace DOS Services, mars_nwe * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public 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 Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * Adds DOS 8.3 alias generation/resolution for long filenames on DOS + * namespace clients. This file was originally derived from nameos2.c, + * but DOS needs synthetic aliases while OS/2 can address long names. */ #include "net.h" #include #include +#include +#include +#include #ifndef LINUX #include #endif @@ -34,133 +26,246 @@ #define MAX_NAME_DOS_CACHE 0 -#if MAX_NAME_DOS_CACHE -typedef struct { - uint8 *cache[MAX_NAME_DOS_CACHE]; -} DOSBUF; - -static void init_dosbuf(NW_VOL *vol) +static int dos_is_alias_char(int c) { - vol->dosbuf = xcmalloc(sizeof(DOSBUF)); -} - -static int vgl_name(uint8 *s, uint8 *p) -{ - int hit=0; - if (!s) return(0); - for (; *s && *p; s++,p++) { - if (*s == *p) { - if (*s == '/') - ++hit; - } else if ((!isalpha(*p)) || (!isalpha(*s)) - || (*p | 0x20) != (*s | 0x20)) { - return(hit); - } - } - return((*s == *p) ? -1 : hit); -} -#endif - -static int my_match(uint8 *s, uint8 *p) -{ - int len=0; - for (; *s && *p; s++,p++) { - if (!ufn_imatch(*s, *p)) + if (isalnum((unsigned char)c)) return(1); + switch (c) { + case '$': case '%': case '\'': case '-': case '_': case '@': + case '~': case '`': case '!': case '(': case ')': case '{': + case '}': case '^': case '#': case '&': + return(1); + default: return(0); - ++len; } - return( ((!*s) && (*p=='/' || *p == '\0')) ? len : 0); } -static int get_match(uint8 *unixname, uint8 *p) +static int dos_alias_char(int c) { - DIR *d; - if (!p || !*p) return(1); - *p = '\0'; - if (NULL != (d=opendir(unixname))) { - struct dirent *dirbuff; - XDPRINTF((10, 0, "opendir OK unixname='%s' p='%s'", unixname, p+1)); - *p = '/'; - while ((dirbuff = readdir(d)) != (struct dirent*)NULL){ - int len; - if (dirbuff->d_ino) { - XDPRINTF((10, 0, "get match found d_name='%s'", dirbuff->d_name)); - if (0 != (len=my_match(dirbuff->d_name, p+1))) { - memcpy(p+1, dirbuff->d_name, len); - XDPRINTF((10, 0, "get match, match OK")); - closedir(d); - return(get_match(unixname, p+1+len)); + if (c >= 'a' && c <= 'z') c -= ('a' - 'A'); + if (dos_is_alias_char(c)) return(c); + return('_'); +} + +int dos_is_83_name(uint8 *name, int options) +{ + uint8 *ss=name; + int len=0; + int pf=0; + + if (!name || !*name) return(0); + if (!strcmp((char*)name, ".") || !strcmp((char*)name, "..")) return(1); + + for (; *ss; ss++){ + if (*ss == '.') { + if (pf++) return(0); /* no second dot */ + if (!len) return(0); /* no empty base */ + len=0; + } else { + if (!dos_is_alias_char(*ss)) return(0); + ++len; + if ((pf && len > 3) || len > 8) return(0); + if (!(options & VOL_OPTION_IGNCASE)){ + if (options & VOL_OPTION_DOWNSHIFT){ + if (*ss >= 'A' && *ss <= 'Z') return(0); + } else { + if (*ss >= 'a' && *ss <= 'z') return(0); } } } - closedir(d); - } else { - XDPRINTF((2, 0, "dos get_match opendir failed unixname='%s'", unixname)); - *p='/'; } - return(0); + return(len > 0); } -#if MAX_NAME_DOS_CACHE -static int get_name(uint8 *s, uint8 *unixname, int hit, uint8 *p) +static void build_dos_83_raw(uint8 *real_name, uint8 *alias, int alias_len) { - if (hit && s) { - for (; *s && *p; s++,p++) { - if (*s=='/') { - if (!--hit) break; - } else *p=*s; + uint8 base[9]; + uint8 ext[4]; + uint8 *dot=NULL; + uint8 *s; + int bl=0, el=0; + + memset(base, 0, sizeof(base)); + memset(ext, 0, sizeof(ext)); + + if (!real_name || !*real_name) { + strmaxcpy(alias, "_", alias_len-1); + return; + } + + if (real_name[0] != '.') + dot=(uint8*)strrchr((char*)real_name, '.'); + + for (s=real_name; *s && s != dot; s++) { + if (bl < 8) base[bl++] = (uint8)dos_alias_char(*s); + } + if (!bl) base[bl++] = '_'; + + if (dot) { + for (s=dot+1; *s; s++) { + if (el < 3) ext[el++] = (uint8)dos_alias_char(*s); } - } else - --p; /* to get last '/' */ - return(get_match(unixname, p)); + } + + if (el) + snprintf((char*)alias, alias_len, "%s.%s", base, ext); + else + snprintf((char*)alias, alias_len, "%s", base); +} + +static int alias_base_equal(uint8 *a, uint8 *b) +{ + uint8 aa[14], bb[14]; + uint8 *pa, *pb; + strmaxcpy(aa, a, sizeof(aa)-1); + strmaxcpy(bb, b, sizeof(bb)-1); + pa=(uint8*)strchr((char*)aa, '.'); + pb=(uint8*)strchr((char*)bb, '.'); + if (pa) *pa='\0'; + if (pb) *pb='\0'; + return(!strcmp((char*)aa, (char*)bb)); +} + +static char dos_digit(int n) +{ + n &= 0x0f; + return((n < 10) ? ('0' + n) : ('A' + n - 10)); +} + +static void apply_collision_number(uint8 *alias, int collision) +{ + uint8 *dot=(uint8*)strchr((char*)alias, '.'); + uint8 ext[5]; + uint8 base[9]; + int bl; + + memset(ext, 0, sizeof(ext)); + memset(base, 0, sizeof(base)); + if (dot) { + strmaxcpy(ext, dot, sizeof(ext)-1); + *dot='\0'; + } + strmaxcpy(base, alias, sizeof(base)-1); + bl=strlen((char*)base); + if (bl >= 8) bl=7; + base[bl++] = dos_digit(collision); + base[bl] = '\0'; + snprintf((char*)alias, 14, "%s%s", base, ext); +} + +int build_dos_83_alias(int options, uint8 *parent_unix, + uint8 *real_name, ino_t inode, + uint8 *alias, int alias_len) +{ + uint8 raw[14]; + int collisions=0; + DIR *d; + + (void)inode; + + if (alias_len < 2) return(0); + *alias='\0'; + + if (dos_is_83_name(real_name, options)) { + strmaxcpy(alias, real_name, alias_len-1); + up_fn(alias); + return(strlen((char*)alias)); + } + + build_dos_83_raw(real_name, raw, sizeof(raw)); + strmaxcpy(alias, raw, alias_len-1); + + if (parent_unix && *parent_unix && NULL != (d=opendir((char*)parent_unix))) { + struct dirent *de; + while ((de=readdir(d)) != NULL) { + uint8 other[14]; + if (!de->d_ino) continue; + if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..")) continue; + if (!strcmp(de->d_name, (char*)real_name)) continue; + build_dos_83_raw((uint8*)de->d_name, other, sizeof(other)); + if (!strcmp((char*)other, (char*)raw)) { + if (strcmp(de->d_name, (char*)real_name) < 0) + collisions++; + } + /* A real 8.3 name that equals the raw alias consumes that alias. */ + if (dos_is_83_name((uint8*)de->d_name, options)) { + uint8 native[14]; + strmaxcpy(native, (uint8*)de->d_name, sizeof(native)-1); + up_fn(native); + if (!strcmp((char*)native, (char*)raw)) collisions++; + } + } + closedir(d); + } + + if (collisions > 0) { + strmaxcpy(alias, raw, alias_len-1); + apply_collision_number(alias, collisions-1); + } + + up_fn(alias); + return(strlen((char*)alias)); +} + +static int dos_alias_match(uint8 *a, uint8 *b) +{ + uint8 aa[14], bb[14]; + strmaxcpy(aa, a, sizeof(aa)-1); + strmaxcpy(bb, b, sizeof(bb)-1); + up_fn(aa); + up_fn(bb); + return(!strcmp((char*)aa, (char*)bb)); } -#endif void mangle_dos_name(NW_VOL *vol, uint8 *unixname, uint8 *pp, int len) { -#if MAX_NAME_DOS_CACHE - int k = -1; - int besthit = -1; - int maxhits = 0; - DOSBUF *b; - if (!vol->dosbuf) init_dosbuf(vol); - b= (DOSBUF*)vol->dosbuf; + uint8 wanted[14]; + uint8 rest[512]; + uint8 *slash; + uint8 *parent_slash; + DIR *d; - while (++k < MAX_NAME_DOS_CACHE) { - int hits=vgl_name(b->cache[k], pp); - if (hits < 0) { - besthit=k; - break; - } else if (hits > maxhits) { - besthit=k; - maxhits =hits; - } + if (!vol || !unixname || !pp || !*pp || len <= 1) return; + + slash=(uint8*)strchr((char*)pp, '/'); + memset(rest, 0, sizeof(rest)); + if (slash) { + strmaxcpy(rest, slash, sizeof(rest)-1); + *slash='\0'; } - if (maxhits > -1) { - /* do not completely match */ - if (get_name(maxhits ? b->cache[besthit] : NULL, - unixname, maxhits, pp)) { - int k=MAX_NAME_DOS_CACHE-1; - xfree(b->cache[k]); - while (k--) { - b->cache[k+1] = b->cache[k]; + + strmaxcpy(wanted, pp, sizeof(wanted)-1); + up_fn(wanted); + + parent_slash = (pp > unixname && *(pp-1) == '/') ? pp-1 : NULL; + if (parent_slash) *parent_slash='\0'; + + d=opendir((char*)unixname); + if (d) { + struct dirent *de; + while ((de=readdir(d)) != NULL) { + uint8 alias[14]; + if (!de->d_ino) continue; + if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..")) continue; + build_dos_83_alias(vol->options, unixname, (uint8*)de->d_name, + de->d_ino, alias, sizeof(alias)); + if (dos_alias_match(alias, wanted)) { + if (parent_slash) *parent_slash='/'; + snprintf((char*)pp, len, "%s%s", de->d_name, rest); + closedir(d); + if (*rest) { + uint8 *next=(uint8*)strchr((char*)pp, '/'); + if (next && *(next+1)) + mangle_dos_name(vol, unixname, next+1, + len - (int)((next+1)-pp)); + } + return; } - b->cache[0] = NULL; - new_str(b->cache[0], pp); - } - } else { - strncpy(pp, b->cache[besthit], len-1); - if (besthit > 2) { - uint8 *sp=b->cache[besthit]; - while (besthit--) { - b->cache[besthit+1] = b->cache[besthit]; - } - b->cache[0] = sp; } + closedir(d); } -#else - get_match(unixname, pp-1); -#endif + + if (parent_slash) *parent_slash='/'; + if (slash) *slash='/'; } static inline int get_n_p(uint8 **p) diff --git a/src/namspace.c b/src/namspace.c index 8f68b77..3659b0e 100644 --- a/src/namspace.c +++ b/src/namspace.c @@ -45,6 +45,7 @@ #include "unxfile.h" #include "namspace.h" #include "nameos2.h" +#include "namedos.h" #if WITH_NAME_SPACE_CALLS @@ -654,11 +655,13 @@ leave_build_nwpath: else up_fn(pp); - mangle_dos_name(v, unixname, pp); + mangle_dos_name(v, unixname, pp, + sizeof(unixname)-v->unixnamlen-npbeg); if (nplen > 0) { unix2doscharset(pp); - memcpy(nwpath->path+npbeg, pp, nplen); + strmaxcpy(nwpath->path+npbeg, pp, + sizeof(nwpath->path)-npbeg-1); } XDPRINTF((5,0, "Mangle DOS unixname='%s'", unixname)); } @@ -908,46 +911,20 @@ static int build_base(int namespace, static int build_dos_name(DIR_BASE_ENTRY *e, uint8 *fname, int size_fname) { - uint8 *ss=e->nwpath.fn; - int len=0; - int pf=0; - int is_ok=1; - int options=get_volume_options(e->nwpath.volume); - for (; *ss; ss++){ - if (*ss == '.') { - if (pf++) { /* no 2. point */ - is_ok=0; - break; - } - len=0; - } else { - ++len; - if ((pf && len > 3) || len > 8) { - is_ok=0; - break; - } - if (!(options & VOL_OPTION_IGNCASE)){ - if (options & VOL_OPTION_DOWNSHIFT){ /* only downshift chars */ - if (*ss >= 'A' && *ss <= 'Z') { - is_ok=0; - break; - } - } else { /* only upshift chars */ - if (*ss >= 'a' && *ss <= 'z') { - is_ok=0; - break; - } - } - } - } - } - if (is_ok) { - strmaxcpy(fname, e->nwpath.fn, size_fname-1); - up_fn(fname); - return(strlen(fname)); - } else { - return(sprintf(fname, "%ld.___", (long)e->nwpath.statb.st_ino)); - } + char *parent_unix; + int result; + + if (!e || !fname || size_fname < 2) return(0); + + parent_unix = alloc_nwpath2unix(&(e->nwpath), 1|2); + result = build_dos_83_alias(get_volume_options(e->nwpath.volume), + (uint8*)parent_unix, + e->nwpath.fn, + e->nwpath.statb.st_ino, + fname, + size_fname); + xfree(parent_unix); + return(result); } #if 0 @@ -1517,7 +1494,11 @@ static int search_match(struct dirent *dirbuff, XDPRINTF((8,0,"search_match, Name='%s' dname='%s'", name, dname)); if (!inode_search) { if (namespace == NAME_DOS) { - flag = (*name != '.' && fn_dos_match_old(dname, entry, vol_options)); + if (*name != '.') { + build_dos_83_alias(vol_options, ds->unixname, name, + dirbuff->d_ino, dname, size_dname); + flag = fn_dos_match_old(dname, entry, vol_options); + } } else if (namespace == NAME_OS2) { flag = (*name != '.' || (*(name+1) != '.' && *(name+1) != '\0' )) && fn_os2_match(dname, entry, vol_options);