Add first implementation of dosmangle 8.3 support for long file names
Some checks are pending
Source release / source-package (push) Waiting to run
Some checks are pending
Source release / source-package (push) Waiting to run
This commit is contained in:
34
include/dosmangle.h
Normal file
34
include/dosmangle.h
Normal file
@@ -0,0 +1,34 @@
|
||||
#ifndef _DOSMANGLE_H_
|
||||
#define _DOSMANGLE_H_
|
||||
|
||||
/*
|
||||
* dosmangle.h
|
||||
*
|
||||
* Centralized DOS 8.3 short-name support for MARS_NWE.
|
||||
*/
|
||||
|
||||
#include "net.h"
|
||||
#include "nwvolume.h"
|
||||
|
||||
#define DOS83_NAME_MAX 13 /* 8 + '.' + 3 + NUL */
|
||||
|
||||
int dos83_is_valid_name(const uint8 *name, int options);
|
||||
int dos83_build_name_in_dir(const char *dir_unix,
|
||||
const uint8 *src,
|
||||
uint8 *out,
|
||||
int out_size,
|
||||
int options);
|
||||
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);
|
||||
int dos83_resolve_component(const char *dir_unix,
|
||||
const uint8 *dos_name,
|
||||
uint8 *resolved_name,
|
||||
int resolved_size,
|
||||
int options);
|
||||
void mangle_dos_name(NW_VOL *vol, uint8 *unixname, uint8 *pp);
|
||||
|
||||
#endif
|
||||
@@ -57,7 +57,7 @@ ELSE(ENABLE_INTERNAL_RIP_SAP)
|
||||
ENDIF(ENABLE_INTERNAL_RIP_SAP)
|
||||
|
||||
add_executable(nwserv nwserv.c net1.c tools.c ${EMUTLI} ${EMUTLI1} ${NWROUTE_0} )
|
||||
add_executable(nwconn nwconn.c net1.c tools.c connect.c namspace.c nwvolume.c nwfile.c unxfile.c nwqconn.c nameos2.c nwfname.c nwshare.c extpipe.c nwattrib.c trustee.c ${EMUTLI} )
|
||||
add_executable(nwconn nwconn.c net1.c tools.c connect.c namspace.c dosmangle.c nwvolume.c nwfile.c unxfile.c nwqconn.c nameos2.c nwfname.c nwshare.c extpipe.c nwattrib.c trustee.c ${EMUTLI} )
|
||||
add_executable(ncpserv ncpserv.c net1.c tools.c ${EMUTLI} )
|
||||
add_executable(nwclient nwclient.c net1.c tools.c ${EMUTLI} )
|
||||
add_executable(nwbind nwbind.c net1.c tools.c nwdbm.c nwcrypt.c unxlog.c sema.c nwqueue.c unxfile.c ${EMUTLI} )
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
|
||||
#include "net.h"
|
||||
#include "unxfile.h"
|
||||
#include "dosmangle.h"
|
||||
|
||||
#include <dirent.h>
|
||||
#include <utime.h>
|
||||
@@ -59,6 +60,7 @@ static int act_umode_file=0;
|
||||
#include "nwconn.h"
|
||||
#include "namspace.h"
|
||||
#include "connect.h"
|
||||
#include "dosmangle.h"
|
||||
|
||||
|
||||
typedef struct {
|
||||
@@ -780,12 +782,16 @@ static int get_dh_entry(DIR_HANDLE *dh,
|
||||
dh->sequence++;
|
||||
if (dirbuff->d_ino) {
|
||||
uint8 *name=(uint8*)(dirbuff->d_name);
|
||||
uint8 dname[256];
|
||||
xstrcpy(dname, name);
|
||||
unix2doscharset(dname);
|
||||
okflag = (name[0] != '.' &&
|
||||
( (!strcmp((char*)dname, (char*)entry))
|
||||
|| fn_dos_match(dname, entry, dh->vol_options)));
|
||||
uint8 dosname[DOS83_NAME_MAX + 1];
|
||||
|
||||
if (name[0] != '.') {
|
||||
okflag = dos83_match_name_in_dir(dh->unixname,
|
||||
name,
|
||||
entry,
|
||||
dh->vol_options,
|
||||
dosname,
|
||||
sizeof(dosname));
|
||||
}
|
||||
|
||||
if (okflag) {
|
||||
strmaxcpy(dh->kpath, (char*)name,
|
||||
@@ -805,7 +811,8 @@ static int get_dh_entry(DIR_HANDLE *dh,
|
||||
if (okflag){
|
||||
if (unixname)
|
||||
strmaxcpy(unixname, dh->unixname, size_unixname-1);
|
||||
strmaxcpy((char*)search, (char*)dname, size_search-1);
|
||||
/* Return the DOS-visible alias instead of the raw name. */
|
||||
strmaxcpy((char*)search, (char*)dosname, size_search-1);
|
||||
break; /* ready */
|
||||
}
|
||||
} else okflag = 0;
|
||||
@@ -2679,13 +2686,7 @@ static int get_match(uint8 *unixname, uint8 *p)
|
||||
return(0);
|
||||
}
|
||||
|
||||
void mangle_dos_name(NW_VOL *vol, uint8 *unixname, uint8 *pp)
|
||||
{
|
||||
struct stat stb;
|
||||
if (!s_stat(unixname, &stb, NULL)) /* path is ok I hope */
|
||||
return;
|
||||
get_match(unixname, pp-1);
|
||||
}
|
||||
/* mangle_dos_name() moved to dosmangle.c */
|
||||
|
||||
|
||||
int nw_add_trustee(int dir_handle, uint8 *data, int len,
|
||||
|
||||
391
src/dosmangle.c
Normal file
391
src/dosmangle.c
Normal file
@@ -0,0 +1,391 @@
|
||||
/*
|
||||
* dosmangle.c
|
||||
*
|
||||
* Centralized DOS 8.3 short-name support.
|
||||
*/
|
||||
|
||||
#include "net.h"
|
||||
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "nwfname.h"
|
||||
#include "nwvolume.h"
|
||||
#include "connect.h"
|
||||
#include "dosmangle.h"
|
||||
|
||||
static int dos83_valid_char(int c)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
static char dos83_upchar(int c)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
return (*name != '\0');
|
||||
}
|
||||
|
||||
static void dos83_build_alias_candidate(const uint8 *src, int seq,
|
||||
uint8 *out, int out_size)
|
||||
{
|
||||
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 int dos83_alias_used_in_dir(const char *dir_unix,
|
||||
const uint8 *src,
|
||||
const uint8 *candidate,
|
||||
int options)
|
||||
{
|
||||
DIR *d;
|
||||
struct dirent *dirbuff;
|
||||
|
||||
d = opendir(dir_unix);
|
||||
if (!d) {
|
||||
if (seteuid(0)) {}
|
||||
d = opendir(dir_unix);
|
||||
reseteuid();
|
||||
}
|
||||
if (!d)
|
||||
return 0;
|
||||
|
||||
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);
|
||||
} else {
|
||||
dos83_build_alias_candidate((uint8 *)dirbuff->d_name, 1, other, sizeof(other));
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
char base[260], ext[260];
|
||||
char nbase[9], next[4];
|
||||
int seq;
|
||||
|
||||
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);
|
||||
return (int)strlen((char *)out);
|
||||
}
|
||||
|
||||
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) {
|
||||
if (*next)
|
||||
snprintf((char *)out, out_size, "%s.%s", nbase, next);
|
||||
else
|
||||
snprintf((char *)out, out_size, "%s", nbase);
|
||||
|
||||
if (!dir_unix || !dos83_alias_used_in_dir(dir_unix, src, out, options))
|
||||
return (int)strlen((char *)out);
|
||||
}
|
||||
|
||||
for (seq = 1; seq < 1000000; seq++) {
|
||||
dos83_build_alias_candidate(src, seq, out, out_size);
|
||||
if (!dir_unix || !dos83_alias_used_in_dir(dir_unix, src, out, options))
|
||||
return (int)strlen((char *)out);
|
||||
}
|
||||
|
||||
strncpy((char *)out, "FILE~1", out_size - 1);
|
||||
out[out_size - 1] = '\0';
|
||||
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';
|
||||
}
|
||||
|
||||
return dos83_x_str_match(dos_name, dos_pattern, options);
|
||||
}
|
||||
|
||||
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) {
|
||||
struct dirent *dirbuff;
|
||||
*p = '/';
|
||||
|
||||
while ((dirbuff = readdir(d)) != 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);
|
||||
}
|
||||
}
|
||||
closedir(d);
|
||||
} else {
|
||||
*p = '/';
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void mangle_dos_name(NW_VOL *vol, uint8 *unixname, uint8 *pp)
|
||||
{
|
||||
struct stat stbuff;
|
||||
|
||||
if (!stat((char *)unixname, &stbuff))
|
||||
return;
|
||||
|
||||
dos83_get_match(unixname, pp - 1, vol->options);
|
||||
}
|
||||
@@ -45,6 +45,7 @@
|
||||
#include "unxfile.h"
|
||||
#include "namspace.h"
|
||||
#include "nameos2.h"
|
||||
#include "dosmangle.h"
|
||||
|
||||
#if WITH_NAME_SPACE_CALLS
|
||||
|
||||
@@ -906,48 +907,48 @@ static int build_base(int namespace,
|
||||
return(result);
|
||||
}
|
||||
|
||||
/*
|
||||
* Build the DOS-visible short name for one namespace directory entry.
|
||||
*
|
||||
* This wrapper delegates all DOS short-name generation to dosmangle.c so
|
||||
* that DOS namespace listings use the same naming rules as DOS path lookup
|
||||
* and DOS wildcard matching.
|
||||
*/
|
||||
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 dir_unix[1024];
|
||||
char *slash;
|
||||
uint8 *unixname;
|
||||
int options;
|
||||
|
||||
if (!e || !fname || size_fname <= 0)
|
||||
return 0;
|
||||
|
||||
options = get_volume_options(e->nwpath.volume);
|
||||
|
||||
/*
|
||||
* Convert the full entry path to Unix form, then strip the last component.
|
||||
* dosmangle.c uses the containing directory to check for alias collisions.
|
||||
*/
|
||||
unixname = alloc_nwpath2unix(&(e->nwpath), 2);
|
||||
if (!unixname)
|
||||
return 0;
|
||||
|
||||
strncpy(dir_unix, (char *)unixname, sizeof(dir_unix) - 1);
|
||||
dir_unix[sizeof(dir_unix) - 1] = ' | ||||