Roleback
All checks were successful
Source release / source-package (push) Successful in 52s

This commit is contained in:
Mario Fetka
2026-05-20 14:55:44 +02:00
parent e1509868c3
commit ab0bfa4230
7 changed files with 368 additions and 1103 deletions

View File

@@ -1,519 +1,291 @@
/*
* namedos.c
/* nameos2.c 14-May-97 : NameSpace DOS Services, mars_nwe */
/* (C)opyright (C) 1993,1996 Martin Stover, Marburg, Germany
*
* Centralized DOS 8.3 short-name support.
* 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.
*/
#include "net.h"
#include <dirent.h>
#include <utime.h>
#ifndef LINUX
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#endif
#include "nwfname.h"
#include "nwvolume.h"
#include "connect.h"
#include "nwfile.h"
#include "unxfile.h"
#include "namedos.h"
static int dos83_valid_char(int c)
#if WITH_NAME_SPACE_CALLS
#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)
{
if (c >= 'A' && c <= 'Z') return 1;
if (c >= 'a' && c <= 'z') return 1;
if (c >= '0' && c <= '9') return 1;
if (c == '_' || c == '-') return 1;
return 0;
vol->dosbuf = xcmalloc(sizeof(DOSBUF));
}
static char dos83_upchar(int c)
static int vgl_name(uint8 *s, uint8 *p)
{
if (c >= 'a' && c <= 'z')
return (char)(c - 'a' + 'A');
return (char)c;
}
static void dos83_split_name(const uint8 *src,
char *base, int base_sz,
char *ext, int ext_sz)
{
const char *dot = strrchr((const char *)src, '.');
int len;
if (base_sz > 0) base[0] = '\0';
if (ext_sz > 0) ext[0] = '\0';
if (dot && dot != (const char *)src) {
len = (int)(dot - (const char *)src);
if (len >= base_sz) len = base_sz - 1;
memcpy(base, src, len);
base[len] = '\0';
strncpy(ext, dot + 1, ext_sz - 1);
ext[ext_sz - 1] = '\0';
} else {
strncpy(base, (const char *)src, base_sz - 1);
base[base_sz - 1] = '\0';
}
}
static void dos83_normalize_part(const char *src, char *dst, int dst_sz, int maxlen)
{
int di = 0;
while (*src && di < dst_sz - 1 && di < maxlen) {
unsigned char c = (unsigned char)*src++;
if (c == ' ')
continue;
if (dos83_valid_char(c))
dst[di++] = dos83_upchar(c);
}
dst[di] = '\0';
}
static void dos83_normalize_part_full(const char *src, char *dst, int dst_sz)
{
int di = 0;
while (*src && di < dst_sz - 1) {
unsigned char c = (unsigned char)*src++;
if (c == ' ')
continue;
if (dos83_valid_char(c))
dst[di++] = dos83_upchar(c);
}
dst[di] = '\0';
}
int dos83_is_valid_name(const uint8 *name, int options)
{
const uint8 *ss = name;
int len = 0;
int pf = 0;
for (; *ss; ss++) {
if (*ss == '.') {
if (pf++) return 0;
len = 0;
} else {
++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;
}
}
if (!dos83_valid_char(*ss))
return 0;
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 (*name != '\0');
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))
return(0);
++len;
}
return( ((!*s) && (*p=='/' || *p == '\0')) ? len : 0);
}
static void dos83_build_alias_candidate(const uint8 *src, int seq,
uint8 *out, int out_size)
static int get_match(uint8 *unixname, uint8 *p)
{
char base[260], ext[260];
char nbase_full[260], next[4];
char stem[9];
char seqbuf[16];
int stem_len;
dos83_split_name(src, base, sizeof(base), ext, sizeof(ext));
dos83_normalize_part_full(base, nbase_full, sizeof(nbase_full));
dos83_normalize_part(ext, next, sizeof(next), 3);
if (!*nbase_full)
strcpy(nbase_full, "FILE");
sprintf(seqbuf, "~%d", seq);
stem_len = 8 - (int)strlen(seqbuf);
if (stem_len > 6) stem_len = 6;
if (stem_len < 1) stem_len = 1;
if (stem_len > (int)strlen(nbase_full))
stem_len = (int)strlen(nbase_full);
memcpy(stem, nbase_full, stem_len);
stem[stem_len] = '\0';
if (*next)
snprintf((char *)out, out_size, "%s%s.%s", stem, seqbuf, next);
else
snprintf((char *)out, out_size, "%s%s", stem, seqbuf);
}
static void dos83_build_plain_alias(const uint8 *src, uint8 *out, int out_size)
{
char base[260], ext[260];
char nbase[9], next[4];
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);
if (!*nbase)
strcpy(nbase, "FILE");
if (*next)
snprintf((char *)out, out_size, "%s.%s", nbase, next);
else
snprintf((char *)out, out_size, "%s", nbase);
}
static int dos83_same_plain_family(const uint8 *a, const uint8 *b)
{
uint8 aa[DOS83_NAME_MAX + 1];
uint8 bb[DOS83_NAME_MAX + 1];
dos83_build_plain_alias(a, aa, sizeof(aa));
dos83_build_plain_alias(b, bb, sizeof(bb));
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,
int options)
{
DIR *d;
struct dirent *dirbuff;
int src_rank = dos83_compute_family_rank(dir_unix, src, options);
d = opendir(dir_unix);
if (!d) {
if (seteuid(0)) {}
d = opendir(dir_unix);
reseteuid();
}
if (!d)
return 0;
XDPRINTF((2,0,
"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)",
src_rank));
while ((dirbuff = readdir(d)) != NULL) {
uint8 other[DOS83_NAME_MAX + 1];
if (!dirbuff->d_ino)
continue;
if (!strcmp(dirbuff->d_name, ".") || !strcmp(dirbuff->d_name, ".."))
continue;
if (!strcmp(dirbuff->d_name, (const char *)src))
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);
XDPRINTF((2,0,
"DOS83 COLLISION EXISTING8 raw='%s' alias='%s' candidate='%s'",
dirbuff->d_name,
other,
candidate));
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;
}
}
}
closedir(d);
return 0;
}
int dos83_build_name_in_dir(const char *dir_unix,
const uint8 *src,
uint8 *out,
int out_size,
int options)
{
int rank;
if (!src || !*src || !out || out_size <= 0)
return 0;
if (dos83_is_valid_name(src, options)) {
strncpy((char *)out, (const char *)src, out_size - 1);
out[out_size - 1] = '\0';
up_fn(out);
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);
}
rank = dos83_compute_family_rank(dir_unix, src, options);
dos83_build_ranked_alias(src, rank, out, out_size);
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)) {
int seq = rank > 0 ? rank : 1;
do {
seq++;
dos83_build_alias_candidate(src, seq, out, out_size);
XDPRINTF((2,0,
"DOS83 BUILD retry dir='%s' src='%s' out='%s' seq=%d",
dir_unix ? dir_unix : "(null)",
src ? (char *)src : "(null)",
out ? (char *)out : "(null)",
seq));
} while (seq < 1000000 && dos83_alias_used_in_dir(dir_unix, src, out, options));
}
return (int)strlen((char *)out);
}
static int dos83_strip_magic(const uint8 *in, uint8 *out, int out_size)
{
const uint8 *p = in;
uint8 *q = out;
while (*p && (q - out) < out_size - 1) {
if (*p != 0xff)
*q++ = *p;
p++;
}
*q = '\0';
return (int)(q - out);
}
static int dos83_x_str_match(const uint8 *s, const uint8 *p, int soptions)
{
uint8 pbuf[256];
dos83_strip_magic(p, pbuf, sizeof(pbuf));
return fn_dos_match((uint8 *)s, pbuf, soptions);
}
int dos83_match_name_in_dir(const char *dir_unix,
const uint8 *unix_name,
const uint8 *dos_pattern,
int options,
uint8 *out_dos_name,
int out_dos_name_size)
{
uint8 dos_name[DOS83_NAME_MAX + 1];
if (!unix_name || !dos_pattern)
return 0;
dos83_build_name_in_dir(dir_unix, unix_name, dos_name, sizeof(dos_name), options);
if (out_dos_name && out_dos_name_size > 0) {
strncpy((char *)out_dos_name, (const char *)dos_name, out_dos_name_size - 1);
out_dos_name[out_dos_name_size - 1] = '\0';
}
{
int match_result = dos83_x_str_match(dos_name, dos_pattern, options);
XDPRINTF((2,0,
"DOS83 MATCH dir='%s' unix='%s' pattern='%s' alias='%s' result=%d",
dir_unix ? dir_unix : "(null)",
unix_name ? (char *)unix_name : "(null)",
dos_pattern ? (char *)dos_pattern : "(null)",
dos_name,
match_result));
return match_result;
}
}
int dos83_resolve_component(const char *dir_unix,
const uint8 *dos_name,
uint8 *resolved_name,
int resolved_size,
int options)
{
DIR *d;
struct dirent *dirbuff;
uint8 clean_name[256];
if (!dir_unix || !dos_name || !*dos_name || !resolved_name || resolved_size <= 0)
return 0;
dos83_strip_magic(dos_name, clean_name, sizeof(clean_name));
up_fn(clean_name);
d = opendir(dir_unix);
if (!d) {
if (seteuid(0)) {}
d = opendir(dir_unix);
reseteuid();
}
if (!d)
return 0;
while ((dirbuff = readdir(d)) != NULL) {
uint8 dos_alias[DOS83_NAME_MAX + 1];
if (!dirbuff->d_ino)
continue;
dos83_build_name_in_dir(dir_unix,
(uint8 *)dirbuff->d_name,
dos_alias,
sizeof(dos_alias),
options);
if (!strcmp((char *)dos_alias, (const char *)clean_name)) {
strncpy((char *)resolved_name, dirbuff->d_name, resolved_size - 1);
resolved_name[resolved_size - 1] = '\0';
closedir(d);
return 1;
}
}
closedir(d);
return 0;
}
static int dos83_get_match(uint8 *unixname, uint8 *p, int options)
{
DIR *d;
if (!p || !*p)
return 1;
*p = '\0';
d = opendir((char *)unixname);
if (!d) {
if (seteuid(0)) {}
d = opendir((char *)unixname);
reseteuid();
}
if (d) {
DIR *d;
if (!p || !*p) return(1);
*p = '\0';
if (NULL != (d=opendir(unixname))) {
struct dirent *dirbuff;
*p = '/';
while ((dirbuff = readdir(d)) != NULL) {
XDPRINTF((10, 0, "opendir OK unixname='%s' p='%s'", unixname, p+1));
*p = '/';
while ((dirbuff = readdir(d)) != (struct dirent*)NULL){
int len;
uint8 resolved[256];
if (!dirbuff->d_ino)
continue;
if (dos83_resolve_component((char *)unixname,
p + 1,
resolved,
sizeof(resolved),
options)) {
strncpy((char *)(p + 1), (const char *)resolved, 255);
closedir(d);
len = (int)strlen((char *)(p + 1));
return dos83_get_match(unixname, p + 1 + len, options);
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));
}
}
}
closedir(d);
} else {
*p = '/';
XDPRINTF((2, 0, "dos get_match opendir failed unixname='%s'", unixname));
*p='/';
}
return 0;
return(0);
}
void mangle_dos_name(NW_VOL *vol, uint8 *unixname, uint8 *pp)
#if MAX_NAME_DOS_CACHE
static int get_name(uint8 *s, uint8 *unixname, int hit, uint8 *p)
{
struct stat stbuff;
if (!stat((char *)unixname, &stbuff))
return;
dos83_get_match(unixname, pp - 1, vol->options);
if (hit && s) {
for (; *s && *p; s++,p++) {
if (*s=='/') {
if (!--hit) break;
} else *p=*s;
}
} else
--p; /* to get last '/' */
return(get_match(unixname, p));
}
#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;
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 (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];
}
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;
}
}
#else
get_match(unixname, pp-1);
#endif
}
static inline int get_n_p(uint8 **p)
{
int pc=**p;
(*p)++;
if (pc == '\\') {
pc=**p;
(*p)++;
} else if (pc == 255) {
pc=**p;
(*p)++;
switch (pc) {
case 0xaa :
case '*' : return(3000); /* star */
case 0xae :
case '.' : return(1000); /* point */
case 0xbf :
case '?' : return(2000); /* ? */
default : break;
}
}
return(pc);
}
int fn_dos_match(uint8 *s, uint8 *p, int soptions)
/* OS/2 name matching routine */
{
int pc, sc;
uint state = 0;
int anf, ende;
int not = 0;
uint found = 0;
while ( (pc = get_n_p(&p)) != 0) {
if (!(soptions & VOL_OPTION_IGNCASE)) {
if (soptions & VOL_OPTION_DOWNSHIFT){ /* only downshift chars */
if (*s >= 'A' && *s <= 'Z') return(0);
} else {
if (*s >= 'a' && *s <= 'z') return(0);
}
}
switch (state){
case 0 :
switch (pc) {
case '.' :
case 1000: if (*s && ('.' != *s++))
return(0);
break;
case '?' :
case 2000: if (!*s) return(0);
++s;
break;
case '*' :
case 3000: {
uint8 *pp;
int np;
if (!*p) return(1); /* last star */
while (*s) {
if (fn_dos_match(s, p, soptions) == 1) return(1);
else if (*s=='.') {
pp=p;
if (!get_n_p(&p) || !get_n_p(&p))
return(0);
p=pp;
}
++s;
}
pp=p;
np=get_n_p(&p);
p=pp;
if (np == '.' || np == 1000)
return(fn_dos_match(s, p, soptions));
}
return(0);
case '[' : if ( (*p == '!') || (*p == '^') ){
++p;
not = 1;
}
state = 1;
continue;
default : if (soptions & VOL_OPTION_IGNCASE) {
if (!dfn_imatch(*s, pc))
return(0);
} else if (pc != *s) return(0);
++s;
break;
} /* switch */
break;
case 1 : /* Bereich von Zeichen */
sc = *s++;
found = not;
if (!sc) return(0);
do {
if (pc == '\\') pc = *(p++);
if (!pc) return(0);
anf = pc;
if (*p == '-' && *(p+1) != ']'){
ende = *(++p);
p++;
}
else ende = anf;
if (found == not) { /* only if not found */
if (anf == sc || (anf <= sc && sc <= ende))
found = !not;
}
} while ((pc = *(p++)) != ']');
if (! found ) return(0);
not = 0;
found = 0;
state = 0;
break;
default : break;
} /* switch */
} /* while */
if (*s=='.' && *(s+1)=='\0') return(1);
return ( (*s) ? 0 : 1);
}
#endif