337 lines
8.0 KiB
C
337 lines
8.0 KiB
C
|
/* nwfname.c 17-Jun-97 */
|
||
|
/* (C)opyright (C) 1997 Martin Stover, Marburg, Germany
|
||
|
*
|
||
|
* 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.
|
||
|
*/
|
||
|
|
||
|
/*
|
||
|
* some code and ideas from Victor Khimenko <khim@mccme.ru>
|
||
|
*/
|
||
|
|
||
|
#include "net.h"
|
||
|
#include "unxfile.h"
|
||
|
#include "nwvolume.h"
|
||
|
#include <utime.h>
|
||
|
#include "nwfname.h"
|
||
|
#include <limits.h>
|
||
|
|
||
|
typedef uint8 CHARTABLE[256];
|
||
|
|
||
|
static uint8 *last_filename=NULL;
|
||
|
static ino_t last_st_ino=0;
|
||
|
|
||
|
static CHARTABLE *conversiontable=NULL;
|
||
|
/* there exists 5 tables
|
||
|
* 0 = dos2unix
|
||
|
* 1 = unix2dos
|
||
|
* 2 = down2up 'dosname'
|
||
|
* 3 = up2down 'dosname'
|
||
|
* 4 = up2down 'unixname'
|
||
|
*/
|
||
|
|
||
|
void init_nwfname(char *convfile)
|
||
|
{
|
||
|
FILE *f;
|
||
|
new_str(last_filename, NULL);
|
||
|
last_st_ino=0;
|
||
|
if (conversiontable) return;
|
||
|
if (NULL != (f=fopen(convfile, "rb")))
|
||
|
conversiontable=(CHARTABLE*)xcmalloc(sizeof(CHARTABLE)*5);
|
||
|
if (conversiontable) {
|
||
|
int i=fread(conversiontable, sizeof(CHARTABLE), 5, f);
|
||
|
if (i < 4)
|
||
|
xfree(conversiontable);
|
||
|
else if (i==4) {
|
||
|
/* now we get the last table from the other */
|
||
|
int i=0;
|
||
|
while(i++ < 255) {
|
||
|
uint8 dc=conversiontable[1][i];
|
||
|
uint8 lo=conversiontable[3][dc];
|
||
|
conversiontable[4][i]=
|
||
|
conversiontable[0][lo];
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
XDPRINTF((2,0, "conversiontable: `%s` %s loaded",
|
||
|
convfile, (conversiontable==NULL) ? "not" : ""));
|
||
|
if (f) fclose(f);
|
||
|
}
|
||
|
|
||
|
uint8 *up_fn(uint8 *ss)
|
||
|
{
|
||
|
uint8 *s=ss;
|
||
|
if (!s) return((uint8*)NULL);
|
||
|
if (conversiontable)
|
||
|
for (;*s;s++) *s=conversiontable[2][*s];
|
||
|
else
|
||
|
for (;*s;s++) *s=up_char(*s);
|
||
|
return(ss);
|
||
|
}
|
||
|
|
||
|
uint8 *down_fn(uint8 *ss)
|
||
|
{
|
||
|
uint8 *s=ss;
|
||
|
if (!s) return((uint8*)NULL);
|
||
|
if (conversiontable)
|
||
|
for (;*s;s++) *s=conversiontable[3][*s];
|
||
|
else
|
||
|
for (;*s;s++) *s=down_char(*s);
|
||
|
return(ss);
|
||
|
}
|
||
|
|
||
|
uint8 *dos2unixcharset(uint8 *ss)
|
||
|
{
|
||
|
uint8 *s=ss;
|
||
|
if (!conversiontable) return ss;
|
||
|
if (!s) return((uint8*)NULL);
|
||
|
for (;*s;s++) *s=conversiontable[0][*s];
|
||
|
return(ss);
|
||
|
}
|
||
|
|
||
|
uint8 *unix2doscharset(uint8 *ss)
|
||
|
{
|
||
|
uint8 *s=ss;
|
||
|
if (!conversiontable) return ss;
|
||
|
if (!s) return((uint8*)NULL);
|
||
|
for (;*s;s++) *s=conversiontable[1][*s];
|
||
|
return(ss);
|
||
|
}
|
||
|
|
||
|
int dfn_imatch(uint8 a, uint8 b)
|
||
|
/* returns 1 if a matched b ignoring case for 'dos/os2' filename chars */
|
||
|
{
|
||
|
if (a==b) return(1);
|
||
|
if (!conversiontable)
|
||
|
return(down_char(a) == down_char(b));
|
||
|
return(conversiontable[3][a] == conversiontable[3][b]);
|
||
|
}
|
||
|
|
||
|
int ufn_imatch(uint8 a, uint8 b)
|
||
|
/* returns 1 if a matched b ignoring case for unix filename chars */
|
||
|
{
|
||
|
if (a==b) return(1);
|
||
|
if (!conversiontable)
|
||
|
return(down_char(a) == down_char(b));
|
||
|
return(conversiontable[4][a] == conversiontable[4][b]);
|
||
|
}
|
||
|
|
||
|
#if PERSISTENT_SYMLINKS
|
||
|
static dev_t last_st_dev=0;
|
||
|
static int last_islink=0;
|
||
|
|
||
|
typedef struct {
|
||
|
dev_t st_dev;
|
||
|
ino_t st_ino;
|
||
|
char *filename;
|
||
|
} S_PATH_INODE;
|
||
|
|
||
|
|
||
|
static int get_full_path(char *path)
|
||
|
/* sets last_filename */
|
||
|
{
|
||
|
char newpath[PATH_MAX];
|
||
|
char *npath=newpath;
|
||
|
char *maxpath=newpath+PATH_MAX-1;
|
||
|
char aktpath[PATH_MAX];
|
||
|
char *pp=path;
|
||
|
struct stat statb_buf;
|
||
|
struct stat *statbuf=&statb_buf;
|
||
|
int countlinks = 10; /* max. 10 links */
|
||
|
*npath++='/'; /* we begin at '/' */
|
||
|
last_islink = 0;
|
||
|
last_st_ino = 0;
|
||
|
|
||
|
while (*pp) {
|
||
|
char *save_npath;
|
||
|
if (pp[0] == '.'){
|
||
|
if (pp[1] == '.' && (pp[2] == '/' || pp[2] == '\0') ) {
|
||
|
pp+=2;
|
||
|
while(npath > newpath && *(npath-1) != '/')
|
||
|
--npath;
|
||
|
continue;
|
||
|
} else if (pp[1] == '/') {
|
||
|
pp++;
|
||
|
continue;
|
||
|
}
|
||
|
} else if (pp[0] == '/') {
|
||
|
pp++;
|
||
|
continue;
|
||
|
}
|
||
|
save_npath=npath;
|
||
|
while (*pp && *pp != '/') {
|
||
|
if (npath == maxpath) { /* path too long */
|
||
|
last_st_ino = 0;
|
||
|
return(-99);
|
||
|
}
|
||
|
*npath++ = *pp++;
|
||
|
}
|
||
|
*npath='\0';
|
||
|
if (lstat(newpath, statbuf)){
|
||
|
*save_npath='\0';
|
||
|
new_str(last_filename, newpath);
|
||
|
return(-1);
|
||
|
}
|
||
|
if (S_ISLNK(statbuf->st_mode)) {
|
||
|
int len=readlink(newpath, aktpath, PATH_MAX-1);
|
||
|
if (len < 0 || !countlinks-- ) { /* new links */
|
||
|
last_st_ino = 0;
|
||
|
return(-98);
|
||
|
}
|
||
|
aktpath[len]='\0';
|
||
|
pp=aktpath;
|
||
|
if (aktpath[0] == '/') {
|
||
|
npath=newpath+1;
|
||
|
++pp;
|
||
|
} else {
|
||
|
npath=save_npath;
|
||
|
}
|
||
|
last_islink++;
|
||
|
} else {
|
||
|
last_st_dev = statbuf->st_dev;
|
||
|
last_st_ino = statbuf->st_ino;
|
||
|
last_islink = 0;
|
||
|
}
|
||
|
}
|
||
|
new_str(last_filename, newpath);
|
||
|
return(0);
|
||
|
}
|
||
|
|
||
|
int s_stat(char *path, struct stat *statbuf, S_STATB *stb)
|
||
|
{
|
||
|
|
||
|
int result=0;
|
||
|
if (lstat(path, statbuf)) {
|
||
|
if (get_full_path(path) || lstat(last_filename, statbuf)) {
|
||
|
result=-1;
|
||
|
} else if (stb) {
|
||
|
stb->st_dev=last_st_dev;
|
||
|
stb->st_ino=last_st_ino;
|
||
|
stb->islink=last_islink;
|
||
|
}
|
||
|
} else {
|
||
|
if (stb) {
|
||
|
stb->st_dev=statbuf->st_dev;
|
||
|
stb->st_ino=statbuf->st_ino;
|
||
|
stb->islink=S_ISLNK(statbuf->st_mode);
|
||
|
}
|
||
|
if (S_ISLNK(statbuf->st_mode)) {
|
||
|
if (statbuf->st_ino == last_st_ino && statbuf->st_dev == last_st_dev) {
|
||
|
if (lstat(last_filename, statbuf)) {
|
||
|
last_st_ino=0;
|
||
|
result=-1;
|
||
|
goto s_stat_ret;
|
||
|
}
|
||
|
if (!S_ISLNK(statbuf->st_mode))
|
||
|
goto s_stat_ret;
|
||
|
}
|
||
|
|
||
|
if (get_full_path(path) || lstat(last_filename, statbuf)) {
|
||
|
last_st_ino=0;
|
||
|
result=-1;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
}
|
||
|
|
||
|
s_stat_ret:
|
||
|
MDEBUG(D_FN_NAMES, {
|
||
|
xdprintf(1,0,"s_stat_ret: result=%d, path=`%s`, last_fname=`%s`",
|
||
|
result, path, last_filename);
|
||
|
})
|
||
|
return(result);
|
||
|
}
|
||
|
|
||
|
static int get_linked_name(char *path, S_STATB *stb,
|
||
|
char **fname, int mode)
|
||
|
{
|
||
|
S_STATB stbbuf;
|
||
|
struct stat statbuf_buf;
|
||
|
struct stat *statbuf=&statbuf_buf;
|
||
|
int result=0;
|
||
|
if (!stb) {
|
||
|
stb=&stbbuf;
|
||
|
stb->st_ino=0;
|
||
|
}
|
||
|
if (!stb->st_ino || (stb->islink
|
||
|
&& (stb->st_ino != last_st_ino
|
||
|
|| stb->st_dev != last_st_dev))) {
|
||
|
|
||
|
if (lstat(path, statbuf)) {
|
||
|
if (get_full_path(path) || lstat(last_filename, statbuf)) {
|
||
|
result=-1;
|
||
|
goto get_linked_name_ret;
|
||
|
} else if (stb) {
|
||
|
stb->st_dev=last_st_dev;
|
||
|
stb->st_ino=last_st_ino;
|
||
|
stb->islink=last_islink;
|
||
|
}
|
||
|
*fname = last_filename;
|
||
|
goto get_linked_name_ret;
|
||
|
}
|
||
|
stb->st_dev=statbuf->st_dev;
|
||
|
stb->st_ino=statbuf->st_ino;
|
||
|
stb->islink=S_ISLNK(statbuf->st_mode);
|
||
|
}
|
||
|
if (stb->islink) {
|
||
|
if (stb->st_ino == last_st_ino && stb->st_dev == last_st_dev) {
|
||
|
if (lstat((char *)last_filename, statbuf)) {
|
||
|
last_st_ino=0;
|
||
|
result=-1;
|
||
|
goto get_linked_name_ret;
|
||
|
}
|
||
|
if (!S_ISLNK(statbuf->st_mode)) {
|
||
|
*fname = last_filename;
|
||
|
goto get_linked_name_ret;
|
||
|
}
|
||
|
}
|
||
|
if (get_full_path(path) || lstat(last_filename, statbuf)) {
|
||
|
last_st_ino=0;
|
||
|
result=-1;
|
||
|
goto get_linked_name_ret;
|
||
|
}
|
||
|
*fname=last_filename;
|
||
|
} else
|
||
|
*fname=path;
|
||
|
|
||
|
get_linked_name_ret:
|
||
|
MDEBUG(D_FN_NAMES, {
|
||
|
xdprintf(1,0,"get_l_name: result=%d, path=`%s`, fname=`%s`",
|
||
|
result, path, *fname);
|
||
|
})
|
||
|
return(result);
|
||
|
}
|
||
|
|
||
|
int s_utime(char *fn, struct utimbuf *ut, S_STATB *stb)
|
||
|
{
|
||
|
char *fnbuf=fn;
|
||
|
int result=get_linked_name(fn, stb, &fnbuf, 0);
|
||
|
if (!result) {
|
||
|
result=utime(fnbuf, ut);
|
||
|
}
|
||
|
return(result);
|
||
|
}
|
||
|
|
||
|
int s_chmod(char *fn, umode_t mode, S_STATB *stb)
|
||
|
{
|
||
|
char *fnbuf=fn;
|
||
|
int result=get_linked_name(fn, stb, &fnbuf, 0);
|
||
|
if (!result) {
|
||
|
result=chmod(fnbuf, mode);
|
||
|
}
|
||
|
return(result);
|
||
|
}
|
||
|
|
||
|
#endif
|