397 lines
9.7 KiB
C
397 lines
9.7 KiB
C
/* namedos.c : NameSpace DOS Services, mars_nwe
|
|
*
|
|
* 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 <dirent.h>
|
|
#include <utime.h>
|
|
#include <ctype.h>
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
#ifndef LINUX
|
|
#include <errno.h>
|
|
#endif
|
|
|
|
#include "nwfname.h"
|
|
#include "nwvolume.h"
|
|
#include "connect.h"
|
|
#include "nwfile.h"
|
|
#include "unxfile.h"
|
|
#include "namedos.h"
|
|
|
|
#if WITH_NAME_SPACE_CALLS
|
|
|
|
#define MAX_NAME_DOS_CACHE 0
|
|
|
|
static int dos_is_alias_char(int c)
|
|
{
|
|
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);
|
|
}
|
|
}
|
|
|
|
static int dos_alias_char(int c)
|
|
{
|
|
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);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return(len > 0);
|
|
}
|
|
|
|
static void build_dos_83_raw(uint8 *real_name, uint8 *alias, int alias_len)
|
|
{
|
|
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);
|
|
}
|
|
}
|
|
|
|
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));
|
|
}
|
|
|
|
void mangle_dos_name(NW_VOL *vol, uint8 *unixname, uint8 *pp, int len)
|
|
{
|
|
uint8 wanted[14];
|
|
uint8 rest[512];
|
|
uint8 *slash;
|
|
uint8 *parent_slash;
|
|
DIR *d;
|
|
|
|
if (!vol || !unixname || !pp || !*pp) return;
|
|
if (len <= 1) return;
|
|
|
|
slash=(uint8*)strchr((char*)pp, '/');
|
|
memset(rest, 0, sizeof(rest));
|
|
if (slash) {
|
|
strmaxcpy(rest, slash, sizeof(rest)-1);
|
|
*slash='\0';
|
|
}
|
|
|
|
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;
|
|
}
|
|
}
|
|
closedir(d);
|
|
}
|
|
|
|
if (parent_slash) *parent_slash='/';
|
|
if (slash) *slash='/';
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
static int ns_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 (ns_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(ns_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
|