Files
mars-nwe/src/connect.c
Mario Fetka c80861b92b
All checks were successful
Source release / source-package (push) Successful in 54s
nwconn: implement extracted base handle restore
Wire NCP 0x16/0x17 Extract a Base Handle and NCP 0x16/0x18 Restore an
Extracted Base Handle to connection-local directory-handle state.

The WebSDK documents NCP 0x2222/22/23 as taking a DirectoryHandle and
returning a 14-byte save buffer composed of a 10-byte ServerNetworkAddress
plus a 4-byte HandleID. The same documentation describes NCP 0x2222/22/24 as
taking that saved ServerNetworkAddress/HandleID pair and returning a
NewDirectoryHandle plus AccessRightsMask.

The SDK headers expose these calls as NWSaveDirectoryHandle() and
NWRestoreDirectoryHandle(), with the save buffer explicitly documented as 14
bytes. The Rust nwserver and lwared references do not implement this older
save/restore pair, and newer clients typically use the normal allocate/set
directory-handle calls instead, so keep the MARS-NWE HandleID opaque and
connection-local rather than guessing a global NetWare directory-base number.

Store extracted base-handle IDs in a small per-connection table that records
the saved volume/path tuple. Extract requires a live permanent directory
handle, and Restore validates the saved server address against this server
before allocating a new permanent directory handle for the saved path.

Add the SDK request/reply semantics to the inline endpoint comments and remove
the corresponding TODO entry.

This enables the documented endpoint path while keeping the saved HandleID
conservative and private to MARS-NWE.
2026-05-30 00:12:31 +02:00

3716 lines
115 KiB
C

/* connect.c 15-Apr-00 */
/* (C)opyright (C) 1993-2000, 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.
*/
/* history since 01-Sep-00
* mst:01-Sep-00: pcz:added real unix rights patch from Przemyslaw Czerpak
*
*/
#include "net.h"
#include "unxfile.h"
#include <dirent.h>
#include <utime.h>
/* #define TEST_FNAME "PRINT.000"
*/
int use_mmap=USE_MMAP;
int tells_server_version=1; /* defaults to 3.11 */
int server_version_flags=0;
int max_burst_send_size=0x2000;
int max_burst_recv_size=0x2000;
int default_uid=-1;
int default_gid=-1;
#ifdef TEST_FNAME
static int test_handle=-1;
#endif
static int default_umode_dir = 0751;
static int default_umode_file = 0640;
static int act_umode_dir=0;
static int act_umode_file=0;
#include "nwfname.h"
#include "nwvolume.h"
#include "nwshare.h"
#include "nwattrib.h"
#include "nwarchive.h"
#include "trustee.h"
#include "nwfile.h"
#include "nwconn.h"
#include "namspace.h"
#include "namedos.h"
#include "connect.h"
/* connect.h may already be include-guarded through another header before
* NW_VOL is visible, so keep this local forward declaration before the
* first call in build_dir_name().
*/
void mangle_dos_name(NW_VOL *vol, uint8 *unixname, uint8 *pp, int len);
static void build_dos_attr_name(int volume, uint8 *path, char *unixname,
struct stat *stb, uint8 *out, int out_len);
typedef struct {
dev_t dev; /* unix dev */
ino_t inode; /* unix inode */
time_t timestamp; /* Zeitmarke */
uint8 *path; /* path ab Volume */
uint8 volume; /* Welches Volume */
uint8 is_temp; /* 0:perm. 1:temp 2: spez. temp */
uint8 drive; /* driveletter */
uint8 task; /* actual task */
} NW_DIR;
NW_DIR dirs[MAX_NW_DIRS];
int used_dirs=0;
#define MAX_EXTRACTED_BASE_HANDLES 64
typedef struct {
uint32 id;
int volume;
uint8 *path;
dev_t dev;
ino_t inode;
uint8 task;
} EXTRACTED_BASE_HANDLE;
static EXTRACTED_BASE_HANDLE extracted_base_handles[MAX_EXTRACTED_BASE_HANDLES];
static uint32 next_extracted_base_handle = 1;
static void clear_extracted_base_handles(int task)
{
int j;
for (j = 0; j < MAX_EXTRACTED_BASE_HANDLES; j++) {
EXTRACTED_BASE_HANDLE *ebh = &(extracted_base_handles[j]);
if (ebh->id && (task < 0 || ebh->task == (uint8)task)) {
xfree(ebh->path);
memset(ebh, 0, sizeof(*ebh));
}
}
if (task < 0) next_extracted_base_handle = 1;
}
int act_uid=-1; /* unix uid 0=root */
int act_gid=-1; /* unix gid */
int act_obj_id=0L; /* mars_nwe UID, 0=not logged in, 1=supervisor */
int act_id_flags=0; /* &1 == supervisor equivalence !!! */
int entry8_flags=0; /* special flags, see examples nw.ini, entry 8 */
int entry31_flags=0; /* not used yet */
static gid_t *act_grouplist=NULL; /* first element is counter !! */
static int connect_is_init = 0;
#define MAX_DIRHANDLES 80
#define EXPIRE_COST 86400 /* Is one day enough? :) */
typedef struct {
DIR *f;
char unixname[256]; /* full unixname */
dev_t dev; /* Unix dev */
ino_t inode; /* Unix Inode */
time_t timestamp; /* last allocation */
char *kpath; /* one char after unixname */
int vol_options; /* searchoptions */
int volume; /* Volume Number */
int sequence; /* Search sequence */
off_t dirpos; /* Current pos in unix dir */
int no_search_trustee; /* mst:15-Apr-00 */
} DIR_HANDLE;
static DIR_HANDLE dir_handles[MAX_DIRHANDLES];
static int anz_dirhandles=0;
/* Last real directory entry found by the old DOS scan code.
* Some callers rebuild unixname later from the synthetic DOS alias; keep the
* real parent/name pair so the final attribute formatter can still generate
* a collision-aware 8.3 alias for display.
*/
static int last_dos_alias_volume = -1;
static ino_t last_dos_alias_inode = 0;
static uint8 last_dos_alias_parent[300];
static uint8 last_dos_alias_real[256];
static uint8 last_dos_alias_alias[14];
static void remember_dos_alias_source(int volume, uint8 *parent, uint8 *real,
ino_t inode)
{
last_dos_alias_volume = volume;
last_dos_alias_inode = inode;
strmaxcpy(last_dos_alias_parent, parent ? (char*)parent : "",
sizeof(last_dos_alias_parent)-1);
strmaxcpy(last_dos_alias_real, real ? (char*)real : "",
sizeof(last_dos_alias_real)-1);
last_dos_alias_alias[0] = '\0';
if (parent && real) {
build_dos_83_alias(get_volume_options(volume), parent, real, inode,
last_dos_alias_alias, sizeof(last_dos_alias_alias));
}
}
static char *build_unix_name(NW_PATH *nwpath, int modus)
/*
* returns complete UNIX path
* modus & 1 : ignore fn, (only path)
* modus & 2 : no '/' at end
*/
{
static char unixname[300]; /* must be big enouugh */
int volume = nwpath->volume;
char *p;
if (volume < 0 || volume >= used_nw_volumes
|| !nw_volumes[volume].unixnamlen
|| nw_volumes[volume].unixnamlen > 250) {
errorp(10, "build_unix_name", "volume=%d not ok\n", volume);
xstrcpy(unixname, "Z/Z/Z/Z"); /* */
return(unixname);
}
memcpy(unixname, (char*)nw_volumes[volume].unixname,
nw_volumes[volume].unixnamlen ); /* first UNIXNAME VOLUME */
p = unixname + nw_volumes[volume].unixnamlen;
p += strmaxcpy(p, (char*)nwpath->path, sizeof(unixname) - nw_volumes[volume].unixnamlen -1); /* now the path */
if ( (!(modus & 1)) && nwpath->fn[0])
strmaxcpy(p, (char*)nwpath->fn, sizeof(unixname) - (int)(p-unixname) -1); /* and now fn */
else if ((modus & 2) && (*(p-1) == '/')) {
if (p > unixname+1) *(--p) = '\0';
else {
*p++ = '.';
*p = '\0';
}
}
dos2unixcharset(unixname);
return(unixname);
}
static int new_dir_handle(struct stat *stb, NW_PATH *nwpath)
/*
* RETURN=errorcode (<0) or dir_handle
*/
{
int rethandle;
DIR_HANDLE *dh = NULL;
time_t akttime = time(NULL);
time_t last_time = akttime;
int thandle = 1;
int nhandle = 0;
for (rethandle=0; rethandle < anz_dirhandles; rethandle++){
dh=&(dir_handles[rethandle]);
if (dh->f) { /* only the actual dir-handle should remain open */
closedir(dh->f);
dh->f=NULL;
}
if (!dh->inode) {
if (!nhandle)
nhandle = rethandle+1;
} else if (dh->dev == stb->st_dev && dh->inode == stb->st_ino
&& dh->volume == nwpath->volume){
nhandle = rethandle+1;
break;
} else if (dh->timestamp < last_time){
thandle = rethandle+1;
last_time = dh->timestamp;
}
}
if (!nhandle){
if (anz_dirhandles < MAX_DIRHANDLES) {
dh=&(dir_handles[anz_dirhandles]);
dh->f=NULL;
rethandle = ++anz_dirhandles;
} else {
dh=&(dir_handles[thandle-1]);
rethandle = thandle;
}
} else
rethandle=nhandle;
/* init dir_handle */
dh=&(dir_handles[rethandle-1]);
dh->kpath = dh->unixname + xstrcpy(dh->unixname, build_unix_name(nwpath, 0));
if (dh->f) {
closedir(dh->f);
dh->f=NULL;
}
if ( ( !(dh->no_search_trustee=tru_eff_rights_exists(nwpath->volume, dh->unixname, stb, TRUSTEE_F)))
|| (dh->no_search_trustee & TRUSTEE_T) ) {
if ((dh->f=opendir(dh->unixname)) == (DIR*)NULL) {
if (seteuid(0)) {}
dh->f=opendir(dh->unixname);
(void)reseteuid();
}
}
if (NULL != dh->f) {
dh->volume = nwpath->volume;
dh->vol_options = nw_volumes[dh->volume].options;
dh->dev = stb->st_dev;
dh->inode = stb->st_ino;
dh->timestamp = akttime;
dh->sequence = 0;
dh->dirpos = (off_t)0;
if (dh->vol_options & VOL_OPTION_REMOUNT) {
closedir(dh->f);
dh->f = NULL;
}
} else {
dh->inode = 0;
dh->unixname[0] = '\0';
dh->vol_options = 0;
dh->kpath = dh->unixname;
rethandle = /* -0x9c */ -0xff;
}
return(rethandle);
}
static int free_dir_handle(int dhandle)
{
if (dhandle > 0 && --dhandle < anz_dirhandles) {
DIR_HANDLE *dh=&(dir_handles[dhandle]);
if (dh->f != (DIR*) NULL) {
closedir(dh->f);
dh->f = (DIR*)NULL;
}
dh->inode = 0;
while (anz_dirhandles && !dir_handles[anz_dirhandles-1].inode)
anz_dirhandles--;
return(0);
}
return(-0x88); /* wrong dir_handle */
}
void set_default_guid(void)
{
if (seteuid(0)) {}
setgroups(0, NULL);
if (setegid(default_gid) < 0 || seteuid(default_uid) < 0) {
errorp(1, "set_default_guid, !! SecurityAbort !!",
"Cannot set default gid=%d and uid=%d" , default_gid, default_uid);
exit(1);
}
act_gid = default_gid;
act_uid = default_uid;
act_umode_dir = default_umode_dir;
act_umode_file = default_umode_file;
xfree(act_grouplist);
}
void set_guid(int gid, int uid)
{
if ( gid < 0 || uid < 0
|| seteuid(0)
|| setegid(gid)
|| seteuid(uid) ) {
set_default_guid();
if (gid < 0 && uid < 0) {
/* don't print error */
gid = act_gid;
uid = act_uid;
}
} else if (act_gid != gid || act_uid != uid) {
struct passwd *pw = getpwuid(uid);
if (NULL != pw) {
if (seteuid(0)) {}
initgroups(pw->pw_name, gid);
}
act_gid = gid;
act_uid = uid;
act_umode_dir = default_umode_dir;
act_umode_file = default_umode_file;
xfree(act_grouplist);
if (seteuid(uid))
set_default_guid();
else {
int k=getgroups(0, NULL);
if (k > 0) {
act_grouplist=(gid_t*)xmalloc((k+1) * sizeof(gid_t));
if (getgroups(k, act_grouplist+1) < 0) {}
*act_grouplist=(gid_t)k;
}
}
}
XDPRINTF((5,0,"SET GID=%d, UID=%d %s", gid, uid,
(gid==act_gid && uid == act_uid) ? "OK" : "failed"));
}
void reset_guid(void)
{
set_guid(act_gid, act_uid);
}
void reseteuid(void)
{
if (seteuid(act_uid))
reset_guid();
}
int in_act_groups(gid_t gid)
/* returns 1 if gid is member of act_grouplist else 0 */
{
int k;
gid_t *g;
if (!act_grouplist) return(0);
k=(int)*act_grouplist;
g = act_grouplist;
while (k--) {
if (*(++g) == gid) return(1);
}
return(0);
}
/* pcz:01-Sep-00 */
int get_unix_access_rights(struct stat *stb, uint8 *unixname)
/* returns F_OK, R_OK, W_OK, X_OK */
/* ----- old ----------------------*/
/* ORED with 0x10 if owner access */
/* ORED with 0x20 if group access */
/* ----- corrent-------------------*/
/* ORED with 0x20 if W_OK access */
/* --------------------------------*/
{
int mode=0;
uid_t ruid, euid, rgid;
ruid=getuid();
euid=geteuid();
rgid=getgid();
if (setreuid(act_uid,0)) {}
if (setgid(act_gid)) {}
if (!access(unixname, F_OK)) {
if (!access(unixname, R_OK))
mode |= R_OK;
if (!access(unixname, W_OK))
/* mode |= W_OK; */
mode |= W_OK | 0x20;
if (!access(unixname, X_OK))
mode |= X_OK;
/* mode |= get_unix_eff_rights(stb) & ~(R_OK|W_OK|X_OK); */
}
if (setgid(rgid)) {}
if (setreuid(ruid, euid)) {}
return(mode);
}
int get_unix_eff_rights(struct stat *stb)
/* returns F_OK, R_OK, W_OK, X_OK */
/* ORED with 0x10 if owner access */
/* ORED with 0x20 if group access */
{
int mode = 0;
if (!act_uid)
return(0x10 | R_OK | W_OK | X_OK) ; /* root */
else {
if (act_uid == stb->st_uid) {
mode |= 0x10;
if (stb->st_mode & S_IXUSR)
mode |= X_OK;
if (stb->st_mode & S_IRUSR)
mode |= R_OK;
if (stb->st_mode & S_IWUSR)
mode |= W_OK;
} else if ( (act_gid == stb->st_gid)
|| in_act_groups(stb->st_gid) ) {
mode |= 0x20;
if (stb->st_mode & S_IXGRP)
mode |= X_OK;
if (stb->st_mode & S_IRGRP)
mode |= R_OK;
if (stb->st_mode & S_IWGRP)
mode |= W_OK;
} else {
if (stb->st_mode & S_IXOTH)
mode |= X_OK;
if (stb->st_mode & S_IROTH)
mode |= R_OK;
if (stb->st_mode & S_IWOTH)
mode |= W_OK;
}
}
return(mode);
}
/* next routine is called after new login */
void set_nw_user(int gid, int uid,
int id_flags,
uint32 obj_id, uint8 *objname,
int unxloginlen, uint8 *unxloginname,
int grpcount, uint32 *grps)
{
uint8 unxlogin[20];
strmaxcpy(unxlogin, unxloginname, min(unxloginlen, sizeof(unxlogin)-1));
nwconn_set_program_title(objname);
set_guid(gid, uid);
act_obj_id = obj_id;
act_id_flags = id_flags;
XDPRINTF((5, 0, "actual obj_id is set to 0x%x", obj_id));
if ((act_id_flags&1) && obj_id != 1) {
XDPRINTF((1, 0, "logged in user %s (%s) has supervisor privilegs", objname, unxlogin));
}
nw_setup_vol_opts(act_gid, act_uid,
act_umode_dir, act_umode_file,
unxlogin);
tru_init_trustees(grpcount, grps);
}
uint32 get_file_owner(struct stat *stb)
/* returns nwuser creator of file */
{
uint32 owner=1L; /* default Supervisor */
if (act_obj_id && stb && (stb->st_uid == act_uid))
owner=act_obj_id;
XDPRINTF((5, 0, "get_file_owner owner=0x%x", owner));
return(owner);
}
static char *conn_get_nwpath_name(NW_PATH *p)
/* for debugging */
{
static char nwpathname[300];
char volname[100];
if (p->volume < 0 || p->volume >= used_nw_volumes) {
slprintf(volname, sizeof(volname)-1, "<%d=NOT-OK>", (int)p->volume);
} else xstrcpy(volname, (char*)nw_volumes[p->volume].sysname);
slprintf(nwpathname, sizeof(nwpathname)-1, "%s:%s%s", volname, p->path, p->fn);
return(nwpathname);
}
/* new from Andrew Sapozhnikov <sapa@hq.icb.chel.su>
* added in 0.99.pl7, removes old x_str_match routine
* Do not work for namespace routines, see namespace.c !!
*/
/* NW3.12/MSDOS-like filename matching. *
* Wildcards '*' and '?' allowed. */
static int x_str_match(uint8 *s, uint8 *p, int soptions)
{
while (*p) {
switch (*p) {
case 0xbf:
case '?': if (*s && *s != '.') s++;
p++;
break;
#if 0
case 0xaa:
case '*': while (*s && *s != '.') s++;
while (*p && *p != '.' && *p != 0xae) p++;
break;
#else
/* changed 27-May-98, 0.99.pl10 to handle '*' correct,
* and to handle '*xy.xyz' in a `better` (non DOS) way.
* now I know again why my old routine was so terrible ;-)
*/
case 0xaa:
case '*': ++p;
if (*p) {
while (*s && *s != '.') {
if (x_str_match(s, p, soptions))
return(1);
else
s++;
}
} else {
if (*(p-1) == '*') /* last star '*' match everything */
return(1);
else /* but 0xaa not */
while (*s && *s != '.') s++;
}
break;
#endif
case 0xae:
case '.': if (*s) {
if(*s != '.') return 0;
else s++;
}
p++;
break;
default : if (! ((soptions & VOL_OPTION_IGNCASE) ?
dfn_imatch(*s, *p) : (*s == *p)) ) return 0;
p++;
s++;
}
}
return (*s ? 0 : 1);
}
int fn_dos_match(uint8 *s, uint8 *p, int options)
{
uint8 *ss=s;
int len=0;
int pf=0;
uint8 p_buff[200];
uint8 *pp=p_buff;
for (; *p; p++){
if (*p != 0xff)
*pp++=*p;
}
*pp='\0';
p=p_buff;
for (; *ss; ss++){
if (*ss == '.') {
if (pf++) return(0); /* no 2. point */
len=0;
} else {
++len;
if ((pf && len > 3) || len > 8) return(0);
if (!(options & VOL_OPTION_IGNCASE)){
if (options & VOL_OPTION_DOWNSHIFT){ /* only downshift chars */
if (*ss >= 'A' && *ss <= 'Z') return(0);
} else { /* only upshift chars */
if (*ss >= 'a' && *ss <= 'z') return(0);
}
}
}
}
return(x_str_match(s, p, options));
}
typedef struct {
int attrib;
struct stat statb;
uint8 *ubuf; /* userbuff */
} FUNC_SEARCH;
static int func_search_entry(NW_PATH *nwpath, int attrib,
int (*fs_func)(NW_PATH *nwpath, FUNC_SEARCH *fs), FUNC_SEARCH *fs)
/* returns > 0 if OK < 1 if not ok or not found */
{
struct dirent* dirbuff;
DIR *f=NULL;
int result=0;
int okflag=0;
char xkpath[256];
uint8 entry[256];
int volume = nwpath->volume;
int soptions;
FUNC_SEARCH fs_local;
if (!fs) {
fs = &fs_local;
fs->ubuf = NULL;
}
fs->attrib = attrib;
if (volume < 0 || volume >= used_nw_volumes) return(-1); /* something wrong */
else soptions = nw_volumes[volume].options;
xstrcpy(entry, (char*)nwpath->fn);
nwpath->fn[0] = '\0';
xstrcpy(xkpath, build_unix_name(nwpath, 1|2));
XDPRINTF((5,0,"func_search_entry attrib=0x%x path:%s:, xkpath:%s:, entry:%s:",
attrib, nwpath->path, xkpath, entry));
if ( (!stat(xkpath, &(fs->statb)))
&& !tru_eff_rights_exists(volume, xkpath, &(fs->statb), TRUSTEE_F)) {
if ((f=opendir(xkpath)) == (DIR*)NULL) {
if (seteuid(0)) {}
f=opendir(xkpath);
(void)reseteuid();
}
}
if (f != (DIR*)NULL) {
char *kpath=xkpath+strlen(xkpath);
*kpath++ = '/';
while ((dirbuff = readdir(f)) != (struct dirent*)NULL){
okflag = 0;
if (dirbuff->d_ino) {
uint8 *name=(uint8*)(dirbuff->d_name);
uint8 dname[256];
uint8 dosalias[14];
xstrcpy(dname, name);
unix2doscharset(dname);
*kpath = '\0';
build_dos_83_alias(soptions, (uint8*)xkpath, name,
dirbuff->d_ino, dosalias, sizeof(dosalias));
okflag = (name[0] != '.' &&
( (!strcmp((char*)dosalias, (char*)entry))
|| fn_dos_match(dosalias, entry, soptions)));
if (okflag) {
strmaxcpy(kpath, (char*)name, sizeof(xkpath) - (int)(kpath-xkpath) -1 );
if (!s_stat(xkpath, &(fs->statb), NULL)) {
okflag = ( ( ( (fs->statb.st_mode & S_IFMT) == S_IFDIR) && (attrib & 0x10))
|| ( ( (fs->statb.st_mode & S_IFMT) != S_IFDIR) && !(attrib & 0x10)));
if (okflag){
*kpath = '\0';
remember_dos_alias_source(volume, (uint8*)xkpath, name,
fs->statb.st_ino);
xstrcpy(nwpath->fn, (char*)dosalias);
XDPRINTF((5,0,"FOUND=:%s: attrib=0x%x", nwpath->fn, fs->statb.st_mode));
result = (*fs_func)(nwpath, fs);
if (result < 0) break;
else result=1;
}
} else okflag = 0;
}
XDPRINTF((6,0, "NAME=:%s: OKFLAG %d", name, okflag));
} /* if */
} /* while */
closedir(f);
} /* if */
return(result);
}
static int get_dir_entry(NW_PATH *nwpath,
int *sequence,
int attrib,
struct stat *statb)
/* returns 0 if OK and errcode if not OK */
{
struct dirent* dirbuff;
DIR *f=NULL;
int okflag=-0xff; /* not found */
char xkpath[256];
uint8 entry[256];
int volume = nwpath->volume;
int soptions;
int akt_sequence=0;
int no_search_trustee = 0;
if (volume < 0 || volume >= used_nw_volumes) return(-0x98); /* something wrong */
else soptions = nw_volumes[volume].options;
xstrcpy(entry, (char*)nwpath->fn);
nwpath->fn[0] = '\0';
xstrcpy(xkpath, build_unix_name(nwpath, 1|2));
XDPRINTF((5,0,"get_dir_entry attrib=0x%x path:%s:, xkpath:%s:, entry:%s:",
attrib, nwpath->path, xkpath, entry));
if ( (!stat(xkpath, statb))
&& ( (!(no_search_trustee = tru_eff_rights_exists(volume, xkpath, statb, TRUSTEE_F)))
|| (no_search_trustee&TRUSTEE_T)) ) {
if ((f=opendir(xkpath)) == (DIR*)NULL) {
if (seteuid(0)) {}
f=opendir(xkpath);
(void)reseteuid();
}
}
if (f != (DIR*)NULL) {
char *kpath=xkpath+strlen(xkpath);
*kpath++ = '/';
if (*sequence == MAX_U16) *sequence = 0;
while (akt_sequence++ < *sequence) {
if (NULL == readdir(f)) {
closedir(f);
return(-0xff);
}
}
while ((dirbuff = readdir(f)) != (struct dirent*)NULL){
okflag = -0xff;
(*sequence)++;
if (dirbuff->d_ino) {
uint8 *name=(uint8*)(dirbuff->d_name);
uint8 dname[256];
uint8 dosalias[14];
xstrcpy(dname, name);
unix2doscharset(dname);
*kpath = '\0';
build_dos_83_alias(soptions, (uint8*)xkpath, name,
dirbuff->d_ino, dosalias, sizeof(dosalias));
okflag = ((name[0] != '.' &&
( (!strcmp((char*)dosalias, (char*)entry))
|| fn_dos_match(dosalias, entry, soptions)))) ? 0 : -0xff;
if (!okflag) {
strmaxcpy(kpath, (char*)name, sizeof(xkpath) - (int)(kpath-xkpath) -1);
if (!s_stat(xkpath, statb, NULL)) {
okflag = (( ( ( (statb->st_mode & S_IFMT) == S_IFDIR) && (attrib & 0x10))
|| ( ( (statb->st_mode & S_IFMT) != S_IFDIR) && !(attrib & 0x10))))
? 0 : -0xff;
if (!okflag){
if ( (!no_search_trustee) ||
!tru_eff_rights_exists(volume, xkpath, statb, TRUSTEE_T)) {
if (soptions & VOL_OPTION_IS_PIPE) {
statb->st_size = 0x70000000|(statb->st_mtime&0xfffffff);
}
*kpath = '\0';
remember_dos_alias_source(volume, (uint8*)xkpath, name,
statb->st_ino);
XDPRINTF((99,0,"DOSGETDIR parent='%s' real='%s' alias='%s' inode=%ld", xkpath, name, dosalias, (long)statb->st_ino));
xstrcpy(nwpath->fn, (char*)dosalias);
XDPRINTF((5,0,"FOUND=:%s: attrib=0x%x", nwpath->fn, statb->st_mode));
break; /* ready */
} else
okflag = -0xff;
}
} else okflag = -0xff;
}
XDPRINTF((6,0, "NAME=:%s: OKFLAG %d", name, okflag));
} /* if */
} /* while */
closedir(f);
} else okflag=-0x89; /* no search rights */
return(okflag);
}
static DIR *give_dh_f(DIR_HANDLE *dh)
{
if (!dh->f) {
*(dh->kpath) = '\0';
if (seteuid(0)) {}
dh->f = opendir(dh->unixname);
(void)reseteuid();
}
dh->timestamp=time(NULL); /* tnx to Andrew Sapozhnikov */
return(dh->f);
}
static void release_dh_f(DIR_HANDLE *dh, int expire)
{
if (dh->f && (dh->vol_options & VOL_OPTION_REMOUNT) ) {
closedir(dh->f);
dh->f = NULL;
}
if (expire)
dh->timestamp-=EXPIRE_COST; /* tnx to Andrew Sapozhnikov */
}
static int get_dh_entry(DIR_HANDLE *dh,
uint8 *search,
int size_search,
int *sequence,
int attrib,
char *unixname,
int size_unixname,
struct stat *statb)
/* returns 1 if OK and 0 if not OK */
{
DIR *f = give_dh_f(dh);
int okflag = 0;
if (f != (DIR*)NULL) {
struct dirent *dirbuff;
uint8 entry[256];
xstrcpy(entry, search);
if ( (uint16)*sequence == MAX_U16) *sequence = 0;
if (*sequence < dh->sequence || ((long)dh->dirpos) < 0L) {
dh->dirpos = (off_t)0;
dh->sequence = 0;
}
SEEKDIR(f, dh->dirpos);
if (dh->sequence != *sequence) {
while (dh->sequence < *sequence) {
if (NULL == readdir(f)) {
dh->dirpos = TELLDIR(f);
release_dh_f(dh, 1);
return(0);
}
dh->sequence++;
}
dh->dirpos = TELLDIR(f);
}
XDPRINTF((5,0,"get_dh_entry seq=0x%x, attrib=0x%x path:%s:, entry:%s:",
*sequence, attrib, dh->unixname, entry));
while ((dirbuff = readdir(f)) != (struct dirent*)NULL){
okflag = 0;
dh->sequence++;
if (dirbuff->d_ino) {
uint8 *name=(uint8*)(dirbuff->d_name);
uint8 dname[256];
uint8 dosalias[14];
xstrcpy(dname, name);
unix2doscharset(dname);
build_dos_83_alias(dh->vol_options, (uint8*)dh->unixname, name,
dirbuff->d_ino, dosalias, sizeof(dosalias));
okflag = (name[0] != '.' &&
( (!strcmp((char*)dosalias, (char*)entry))
|| fn_dos_match(dosalias, entry, dh->vol_options)));
if (okflag) {
strmaxcpy(dh->kpath, (char*)name,
sizeof(dh->unixname) - (int)(dh->kpath-dh->unixname) -1 );
XDPRINTF((5,0,"get_dh_entry Name=%s unixname=%s",
name, dh->unixname));
if (!s_stat(dh->unixname, statb, NULL)) {
okflag = ( (( (statb->st_mode & S_IFMT) == S_IFDIR) && (attrib & 0x10))
|| (((statb->st_mode & S_IFMT) != S_IFDIR) && !(attrib & 0x10)));
/* mst:15-Apr-00 */
if (okflag && dh->no_search_trustee
&& tru_eff_rights_exists(dh->volume, dh->unixname, statb, TRUSTEE_T))
okflag=0;
if (okflag){
if (unixname)
strmaxcpy(unixname, dh->unixname, size_unixname-1);
*(dh->kpath) = '\0';
remember_dos_alias_source(dh->volume, (uint8*)dh->unixname,
name, statb->st_ino);
XDPRINTF((99,0,"DOSDH parent='%s' real='%s' alias='%s' inode=%ld", dh->unixname, name, dosalias, (long)statb->st_ino));
strmaxcpy((char*)search, (char*)dosalias, size_search-1);
break; /* ready */
}
} else okflag = 0;
}
} /* if */
} /* while */
dh->kpath[0] = '\0';
*sequence = dh->sequence;
dh->dirpos = TELLDIR(f);
release_dh_f(dh, (dirbuff==NULL));
} /* if */
return(okflag);
}
static void conn_build_path_fn(uint8 *vol,
uint8 *path,
uint8 *fn,
int *has_wild,
uint8 *data,
int len,
int lenn)
/* is called from build_path */
{
uint8 *p = NULL;
uint8 *p1 = path;
*vol = '\0';
*has_wild = 0; /* no wild char */
while (len-- && *data){
if (*data == 0xae) *p1++ = '.';
else if (*data == 0xaa|| *data == '*' ) {
/* *p1++ = '*'; */
*p1++ = *data;
(*has_wild)++;
} else if (*data == 0xbf|| *data == '?' ) {
*p1++ = '?';
(*has_wild)++;
} else if (*data == '/' || *data == '\\') {
*p1++ = '/';
p = p1;
} else if (*data == ':') { /* extract volume */
int len = (int)(p1 - path);
memcpy(vol, path, len);
vol[len] = '\0';
up_fn(vol);
p1 = path;
} else *p1++ = *data;
data++;
}
*p1 = '\0';
if (fn != NULL) { /* if with filename */
if (p != NULL){ /* exist directory-path */
strmaxcpy((char*)fn, (char*)p, 255);
*p = '\0';
} else { /* only filename */
strmaxcpy((char*)fn, (char*)path, 255);
*path= '\0';
}
}
}
static int build_path( NW_PATH *path,
uint8 *data,
int len,
int only_dir)
/*
* fills path structure with the right values
* if only_dir > 0, then the full path will be interpreted
* as directory, in the other way, the last segment of path
* will be interpreted as fn.
* returns -0x98, if volume is wrong
*/
{
uint8 vol[256];
if (len > 255) len = 255;
conn_build_path_fn(vol,
path->path,
(only_dir) ? NULL
: path->fn,
&(path->has_wild),
data, len, sizeof(path->fn));
path->volume = -1;
if (only_dir) path->fn[0] = '\0';
if (vol[0]) { /* there is a volume in path */
int j = used_nw_volumes;
while (j--) {
if (!strcmp((char*)nw_volumes[j].sysname, (char*)vol)) {
path->volume = j;
if (nw_volumes[j].options & VOL_OPTION_DOWNSHIFT) {
down_fn(path->path);
down_fn(path->fn);
} else {
up_fn(path->path);
up_fn(path->fn);
}
break;
}
}
if (path->volume < 0) return(-0x98);
}
return(0);
}
static int nw_path_directory_is_ok(NW_PATH *nwpath, struct stat *stbuff)
/* returns UNIX inode of path */
{
int result=0;
if ((!act_obj_id) && !(entry8_flags & 1)) {
if (nwpath->volume)
result = -0x9c; /* wrong path, only volume 0 is OK */
else {
char *p=nwpath->path;
char pp[10];
while (*p=='/') ++p;
strmaxcpy(pp, p, 6);
up_fn(pp);
p=pp+5;
if (memcmp(pp, "LOGIN", 5) || (*p!='\0' && *p!='/') )
result=-0x9c;
}
}
if (!result && !s_stat(build_unix_name(nwpath, 1 | 2 ), stbuff, NULL)
&& S_ISDIR(stbuff->st_mode))
return(stbuff->st_ino);
else if (!result)
result = -0x9c; /* wrong path */
XDPRINTF((4,0x10, "NW_PATH_OK failed:`%s`", conn_get_nwpath_name(nwpath)));
return(result);
}
static int build_dir_name(NW_PATH *nwpath, /* gets complete path */
struct stat *stbuff,
int dir_handle) /* search with dirhandle */
/* return -completition code or inode */
{
uint8 searchpath[256];
uint8 *p=searchpath;
uint8 *ppp=nwpath->path;
int completition=0;
xstrcpy(searchpath, (char*)ppp); /* save path */
if (nwpath->volume > -1) { /* absolute path */
*ppp= '\0';
} else { /* volume not kwown yet, I must get it about dir_handle */
if (dir_handle > 0 &&
--dir_handle < (int)used_dirs && dirs[dir_handle].inode){
nwpath->volume = dirs[dir_handle].volume;
if (searchpath[0] == '/') { /* absolute path */
p++;
*ppp = '\0';
} else { /* get path from dir_handle */
NW_VOL *v = &nw_volumes[nwpath->volume];
strmaxcpy((char*)ppp, (char*)dirs[dir_handle].path,
sizeof(nwpath->path) - (int)(ppp-nwpath->path) -1 );
if (v->options & VOL_OPTION_IGNCASE)
ppp += strlen(ppp);
}
} else return(-0x9b); /* wrong dir handle */
}
if (*p) {
uint8 *panf = nwpath->path;
uint8 *p1 = panf+strlen((char*)panf);
uint8 *a = p;
uint8 w;
int state = 0;
while ((!completition) && (w = *p++) > 0){
if (!state){
XDPRINTF((5,0,"in build_dir_name path=:%s:", nwpath->path));
if (w == '.') state = 20;
else if (w == '/') state = 30;
else state++;
} else if (state < 9){
if (w == '.') state = 10;
else if (w == '/') state = 30;
else state++;
if (state == 9) completition= -0x9c; /* something wrong */
} else if (state < 14){
if (w == '.') return(-0x9c);
else if (w == '/') state = 30;
else state++;
if (state == 14) completition= -0x9c; /* something wrong */
} else if (state == 20){
if (ppp > nwpath->path)
ppp=nwpath->path;
if (w == '/') state = 30;
else if (w != '.') completition= -0x9c; /* something wrong */
}
if (state == 30 || !*p) { /* now action */
uint8 *xpath=a;
int len = (int)(p-a);
if (len && state == 30) --len; /* '/' don not need it here */
a = p;
if (len) {
if (*xpath == '.') {
uint8 *xp=xpath+1;
if (*xp == '.') {
while (*xp++ == '.' && completition > -1) {
p1--; /* steht nun auf letztem Zeichen '/' od. ':' */
if (p1 < panf) completition = -0x9c ;
/* wrong path, don't can go back any more */
else {
while (p1 > panf && *(--p1) != '/');;
if (p1 == panf) *p1='\0';
else *(++p1) = '\0';
}
}
}
} else {
memcpy(p1, xpath, len);
p1 += len;
*p1++ = '/';
*p1 = '\0';
}
} /* if len */
state = 0;
}
}
}
if (!completition) {
if (nwpath->volume > -1 && nwpath->volume < used_nw_volumes){
NW_VOL *v = &nw_volumes[nwpath->volume];
if (v->options & VOL_OPTION_DOWNSHIFT) {
down_fn(ppp);
down_fn(nwpath->fn);
} else {
up_fn(ppp);
up_fn(nwpath->fn);
}
if (v->options & VOL_OPTION_IGNCASE) {
uint8 unixname[1024]; /* should be enough */
uint8 *pp=unixname+v->unixnamlen;
int offset = ppp - nwpath->path;
int pathlen = strlen(nwpath->path);
int fnlen = strlen(nwpath->fn);
memcpy(unixname, v->unixname, v->unixnamlen);
strmaxcpy(pp, nwpath->path, sizeof(unixname) - v->unixnamlen-1);
if (fnlen)
strmaxcpy(pp+pathlen, nwpath->fn,
sizeof(unixname) - v->unixnamlen - pathlen-1 );
dos2unixcharset(pp);
pp += offset;
pathlen -= offset;
mangle_dos_name(v, unixname, pp, sizeof(unixname) - (int)(pp - unixname));
unix2doscharset(pp);
XDPRINTF((5, 0, "Mangled DOS/unixname=%s", unixname));
memcpy(ppp, pp, pathlen);
if (fnlen)
memcpy(nwpath->fn, pp+pathlen, fnlen);
}
} else return(-0x98); /* wrong volume */
completition = nw_path_directory_is_ok(nwpath, stbuff);
}
return(completition);
}
static int conn_get_kpl_path(NW_PATH *nwpath, struct stat *stbuff,
int dirhandle, uint8 *data, int len, int only_dir)
/*
* if ok then the inode of dir will be returned
* else a negativ errcode will be returned
*/
{
int completition = build_path(nwpath, data, len, only_dir);
XDPRINTF((5, 0, "compl=0x%x, conn_get_kpl_path %s",
completition, conn_get_nwpath_name(nwpath)));
if (!completition) completition = build_dir_name(nwpath, stbuff, dirhandle);
return(completition);
}
int conn_get_full_path(int dirhandle, uint8 *data, int len,
uint8 *fullpath, int size_fullpath)
/* returns path in form VOLUME:PATH */
{
NW_PATH nwpath;
struct stat stbuff;
int result = build_path(&nwpath, data, len, 0);
fullpath[0]='\0';
if (!result)
result = build_dir_name(&nwpath, &stbuff, dirhandle);
if (result > -1) {
uint8 *p=(*nwpath.path=='/') ? nwpath.path+1 : nwpath.path;
int len = slprintf(fullpath, size_fullpath-1, "%s:%s",
nw_volumes[nwpath.volume].sysname, p);
if (len > 0) {
if (nwpath.fn[0]) {
if (*p) fullpath[len++]='/';
strmaxcpy(fullpath+len, nwpath.fn, size_fullpath - len -1);
}
result = len + strlen(nwpath.fn);
} else result = -0x9c; /* wrong path */
}
XDPRINTF((1, 0, "conn_get_full_path: result=%d,(0x%x),`%s`", result, result, fullpath));
return(result);
}
int conn_get_kpl_unxname(char *unixname,
int size_unixname,
int dirhandle,
uint8 *data, int len)
/*
* gives the unixname of dirhandle + path
* returns volumenumber, or < 0 if error
*/
{
NW_PATH nwpath;
struct stat stbuff;
int completition = build_path(&nwpath, data, len, 0);
if (!completition)
completition = build_dir_name(&nwpath, &stbuff, dirhandle);
if (completition > -1) {
if (unixname)
strmaxcpy(unixname, build_unix_name(&nwpath, 0), size_unixname-1);
completition=nwpath.volume;
}
XDPRINTF((5, 0, "conn_get_kpl_unxname: completition=0x%x", completition));
return(completition);
}
void un_date_2_nw(time_t time, uint8 *d, int high_low)
{
struct tm *s_tm=localtime(&time);
uint16 xdate=s_tm->tm_year - 80;
xdate <<= 4;
xdate |= s_tm->tm_mon+1;
xdate <<= 5;
xdate |= s_tm->tm_mday;
if (high_low) {
U16_TO_BE16(xdate, d);
} else {
U16_TO_16(xdate, d);
}
}
void un_time_2_nw(time_t time, uint8 *d, int high_low)
{
struct tm *s_tm=localtime(&time);
uint16 xdate=s_tm->tm_hour;
xdate <<= 6;
xdate |= s_tm->tm_min;
xdate <<= 5;
xdate |= (s_tm->tm_sec / 2);
if (high_low) {
U16_TO_BE16(xdate, d);
} else {
U16_TO_16(xdate, d);
}
}
time_t nw_2_un_time(uint8 *d, uint8 *t)
{
uint16 xdate = GET_BE16(d);
uint16 xtime = (t != (uint8*) NULL) ? GET_BE16(t) : 0;
int year = (xdate >> 9) + 80;
int month = (xdate >> 5) & 0x0F;
int day = xdate & 0x1f;
int hour = xtime >> 11;
int minu = (xtime >> 5) & 0x3f;
int sec = (xtime & 0x1f) << 1; /* Tnx to Csoma Csaba */
struct tm s_tm;
s_tm.tm_year = year;
s_tm.tm_mon = month-1;
s_tm.tm_mday = day;
s_tm.tm_hour = hour;
s_tm.tm_min = minu;
s_tm.tm_sec = sec;
s_tm.tm_isdst = -1;
return(mktime(&s_tm));
}
static void un_time_2_nw_parts(time_t t, uint16 *date, uint16 *timev)
{
uint8 b[2];
if (date) {
un_date_2_nw(t, b, 0);
*date = (uint16)GET_16(b);
}
if (timev) {
un_time_2_nw(t, b, 0);
*timev = (uint16)GET_16(b);
}
}
static time_t nw_2_un_time_parts(uint16 xdate, uint16 xtime)
{
int year = (xdate >> 9) + 80;
int month = (xdate >> 5) & 0x0f;
int day = xdate & 0x1f;
int hour = xtime >> 11;
int minu = (xtime >> 5) & 0x3f;
int sec = (xtime & 0x1f) << 1;
struct tm s_tm;
if (month < 1 || month > 12 || day < 1 || day > 31 ||
hour > 23 || minu > 59 || sec > 59)
return((time_t)-1);
memset(&s_tm, 0, sizeof(s_tm));
s_tm.tm_year = year;
s_tm.tm_mon = month - 1;
s_tm.tm_mday = day;
s_tm.tm_hour = hour;
s_tm.tm_min = minu;
s_tm.tm_sec = sec;
s_tm.tm_isdst = -1;
return(mktime(&s_tm));
}
#define DM_ATTRIBUTES 0x0002UL
#define DM_CREATE_DATE 0x0004UL
#define DM_CREATE_TIME 0x0008UL
#define DM_CREATOR_ID 0x0010UL
#define DM_ARCHIVE_DATE 0x0020UL
#define DM_ARCHIVE_TIME 0x0040UL
#define DM_ARCHIVER_ID 0x0080UL
#define DM_MODIFY_DATE 0x0100UL
#define DM_MODIFY_TIME 0x0200UL
#define DM_MODIFIER_ID 0x0400UL
#define DM_LAST_ACCESS_DATE 0x0800UL
#define DM_INHERITED_RIGHTS_MASK 0x1000UL
#define DM_MAXIMUM_SPACE 0x2000UL
#define DM_NCP22_25_TIME_BITS \
(DM_MODIFY_DATE | DM_MODIFY_TIME | DM_LAST_ACCESS_DATE)
#define DM_NCP22_25_ARCHIVE_BITS \
(DM_ARCHIVE_DATE | DM_ARCHIVE_TIME | DM_ARCHIVER_ID)
#define DM_NCP22_25_SUPPORTED_BITS \
(DM_ATTRIBUTES | DM_CREATE_DATE | DM_CREATE_TIME | DM_CREATOR_ID | \
DM_NCP22_25_ARCHIVE_BITS | DM_NCP22_25_TIME_BITS | \
DM_MODIFIER_ID | DM_INHERITED_RIGHTS_MASK | DM_MAXIMUM_SPACE)
static int set_ncp22_25_times(int volume, char *unixname, struct stat *stb,
NW_SET_DIR_INFO *f, uint32 change_mask,
int is_dir)
{
uint16 mdate;
uint16 mtimev;
uint16 adate;
uint16 atimev;
struct utimbuf ut;
if (!(change_mask & DM_NCP22_25_TIME_BITS))
return(0);
if (tru_eff_rights_exists(volume, unixname, stb, TRUSTEE_M))
return(-0x8c);
ut.actime = stb->st_atime;
ut.modtime = stb->st_mtime;
if (change_mask & (DM_MODIFY_DATE | DM_MODIFY_TIME)) {
un_time_2_nw_parts(stb->st_mtime, &mdate, &mtimev);
if (is_dir) {
if (change_mask & DM_MODIFY_DATE)
mdate = (uint16)GET_16(f->u.d.modify_date);
if (change_mask & DM_MODIFY_TIME)
mtimev = (uint16)GET_16(f->u.d.modify_time);
} else {
if (change_mask & DM_MODIFY_DATE)
mdate = (uint16)GET_16(f->u.f.updated.date);
if (change_mask & DM_MODIFY_TIME)
mtimev = (uint16)GET_16(f->u.f.updated.time);
}
ut.modtime = nw_2_un_time_parts(mdate, mtimev);
if (ut.modtime == (time_t)-1)
return(-0x8c);
}
if (!is_dir && (change_mask & DM_LAST_ACCESS_DATE)) {
un_time_2_nw_parts(stb->st_atime, &adate, &atimev);
adate = (uint16)GET_16(f->u.f.last_access_date);
ut.actime = nw_2_un_time_parts(adate, atimev);
if (ut.actime == (time_t)-1)
return(-0x8c);
}
if (utime(unixname, &ut)) {
if (seteuid(0)) {}
if (utime(unixname, &ut)) {
(void)reseteuid();
return(-0x8c);
}
(void)reseteuid();
}
return(0);
}
static int set_ncp22_25_archive_info(char *unixname,
NW_SET_DIR_INFO *f,
uint32 change_mask,
int is_dir)
{
uint16 adate = 0;
uint16 atime = 0;
uint32 aid = 0;
if (!(change_mask & DM_NCP22_25_ARCHIVE_BITS))
return(0);
if (is_dir) {
if (change_mask & DM_ARCHIVE_DATE)
adate = (uint16)GET_16(f->u.d.archived.date);
if (change_mask & DM_ARCHIVE_TIME)
atime = (uint16)GET_16(f->u.d.archived.time);
if (change_mask & DM_ARCHIVER_ID)
aid = GET_BE32(f->u.d.archived.id);
} else {
if (change_mask & DM_ARCHIVE_DATE)
adate = (uint16)GET_16(f->u.f.archived.date);
if (change_mask & DM_ARCHIVE_TIME)
atime = (uint16)GET_16(f->u.f.archived.time);
if (change_mask & DM_ARCHIVER_ID)
aid = GET_BE32(f->u.f.archived.id);
}
return(mars_nwe_set_archive_info(unixname,
!!(change_mask & DM_ARCHIVE_DATE), adate,
!!(change_mask & DM_ARCHIVE_TIME), atime,
!!(change_mask & DM_ARCHIVER_ID), aid));
}
static int set_ncp22_25_file_info(char *unixname,
NW_SET_DIR_INFO *f,
uint32 change_mask,
int is_dir)
{
uint16 cdate = 0;
uint16 ctime = 0;
uint32 cid = 0;
uint32 mid = 0;
int result;
if (!(change_mask & (DM_CREATE_DATE | DM_CREATE_TIME | DM_CREATOR_ID |
DM_MODIFIER_ID)))
return(0);
if (is_dir) {
if (change_mask & DM_CREATE_DATE)
cdate = (uint16)GET_16(f->u.d.created.date);
if (change_mask & DM_CREATE_TIME)
ctime = (uint16)GET_16(f->u.d.created.time);
if (change_mask & DM_CREATOR_ID)
cid = GET_BE32(f->u.d.created.id);
} else {
if (change_mask & DM_CREATE_DATE)
cdate = (uint16)GET_16(f->u.f.created.date);
if (change_mask & DM_CREATE_TIME)
ctime = (uint16)GET_16(f->u.f.created.time);
if (change_mask & DM_CREATOR_ID)
cid = GET_BE32(f->u.f.created.id);
if (change_mask & DM_MODIFIER_ID)
mid = GET_BE32(f->u.f.updated.id);
}
result = mars_nwe_set_file_info(unixname,
!!(change_mask & DM_CREATE_DATE), cdate,
!!(change_mask & DM_CREATE_TIME), ctime,
!!(change_mask & DM_CREATOR_ID), cid);
if (!result && !is_dir)
result = mars_nwe_set_file_modifier_info(unixname,
!!(change_mask & DM_MODIFIER_ID), mid);
return(result);
}
static int set_ncp22_25_maximum_space(int volume, char *unixname,
struct stat *stb,
NW_SET_DIR_INFO *f,
uint32 change_mask,
int is_dir)
{
uint32 max_space;
uint32 quota;
int result;
if (!(change_mask & DM_MAXIMUM_SPACE))
return(0);
/* NetWare exposes maximum space on directory entries. mars_nwe already
* has a Linux user-quota backend for volume restrictions; use that as the
* closest available mapping. Files have no max_space field in the DOS
* layout, so ignore the bit if a client sends it for a file.
*/
if (!is_dir) {
XDPRINTF((5,0,
"NCP22/25 maximum space ignored for file %s",
unixname ? unixname : ""));
return(0);
}
if (tru_eff_rights_exists(volume, unixname, stb, TRUSTEE_M))
return(-0x8c);
max_space = GET_BE32(f->u.d.max_space);
/* Treat the common unlimited sentinels as "remove restriction". */
if (max_space == MAX_U32 || max_space == 0x40000000UL)
quota = 0;
else
quota = max_space;
result = nw_set_vol_restrictions((uint8)volume, act_uid, quota);
if (result) {
/* If quota support is not compiled/enabled, do not break old clients. */
XDPRINTF((5,0,
"NCP22/25 maximum space quota ignored: vol=%d uid=%d max=0x%08lx rc=%d",
volume, act_uid, (unsigned long)max_space, result));
if (result == -0xfb)
return(0);
} else {
XDPRINTF((5,0,
"NCP22/25 maximum space quota set: vol=%d uid=%d max=0x%08lx quota=0x%08lx",
volume, act_uid, (unsigned long)max_space, (unsigned long)quota));
}
return(result);
}
static void log_ncp22_25_change_bits(uint32 change_mask)
{
uint32 unsupported = change_mask & ~DM_NCP22_25_SUPPORTED_BITS;
XDPRINTF((5,0,
"NCP22/25 change bits: change=0x%08lx supported=0x%08lx unsupported=0x%08lx",
(unsigned long)change_mask,
(unsigned long)(change_mask & DM_NCP22_25_SUPPORTED_BITS),
(unsigned long)unsupported));
if (unsupported) {
XDPRINTF((5,0,
"NCP22/25 unsupported change bits ignored: other=0x%08lx",
(unsigned long)unsupported));
}
}
static int get_file_attrib(NW_FILE_INFO *f, char *unixname, struct stat *stb,
NW_PATH *nwpath)
{
uint8 spath[14];
uint32 dwattrib;
build_dos_attr_name(nwpath->volume, nwpath->fn, unixname, stb,
spath, sizeof(spath));
memset(f->name, 0, sizeof(f->name));
strncpy((char*)f->name, (char*)spath, sizeof(f->name)-1);
dwattrib = get_nw_attrib_dword(nwpath->volume, unixname, stb);
U16_TO_16(dwattrib, f->attrib);
{
uint16 create_date = 0;
uint8 meta_flags = 0;
mars_nwe_get_file_info(unixname, &create_date, NULL, NULL, &meta_flags);
if (meta_flags & MARS_NWE_FILEINFO_HAS_CREATE_DATE) {
U16_TO_BE16(create_date, f->create_date);
} else {
un_date_2_nw(stb->st_mtime, f->create_date, 1);
}
}
un_date_2_nw(stb->st_atime, f->acces_date, 1);
un_date_2_nw(stb->st_mtime, f->modify_date, 1);
un_time_2_nw(stb->st_mtime, f->modify_time, 1);
U32_TO_BE32(stb->st_size, f->size);
return(1);
}
static int get_dir_attrib(NW_DIR_INFO *d, char *unixname, struct stat *stb,
NW_PATH *nwpath)
{
uint8 spath[14];
uint32 dwattrib;
XDPRINTF((5,0, "get_dir_attrib of %s", conn_get_nwpath_name(nwpath)));
build_dos_attr_name(nwpath->volume, nwpath->fn, unixname, stb,
spath, sizeof(spath));
memset(d->name, 0, sizeof(d->name));
strncpy((char*)d->name, (char*)spath, sizeof(d->name)-1);
dwattrib = get_nw_attrib_dword(nwpath->volume, unixname, stb);
U16_TO_16(dwattrib, d->attrib);
{
uint16 create_date = 0;
uint16 create_time = 0;
uint32 creator_id = 0;
uint8 meta_flags = 0;
mars_nwe_get_file_info(unixname, &create_date, &create_time,
&creator_id, &meta_flags);
if (meta_flags & MARS_NWE_FILEINFO_HAS_CREATE_DATE) {
U16_TO_BE16(create_date, d->create_date);
} else {
un_date_2_nw(stb->st_mtime, d->create_date, 1);
}
if (meta_flags & MARS_NWE_FILEINFO_HAS_CREATE_TIME) {
U16_TO_BE16(create_time, d->create_time);
} else {
un_time_2_nw(stb->st_mtime, d->create_time, 1);
}
if (meta_flags & MARS_NWE_FILEINFO_HAS_CREATOR) {
U32_TO_BE32(creator_id, d->owner_id);
} else {
U32_TO_BE32(get_file_owner(stb), d->owner_id);
}
}
d->access_right_mask = 0;
d->reserved = 0;
U16_TO_BE16(0, d->next_search);
return(1);
}
static int do_delete_file(NW_PATH *nwpath, FUNC_SEARCH *fs)
{
char unname[256];
xstrcpy(unname, build_unix_name(nwpath, 0));
XDPRINTF((5,0,"DELETE FILE unname:%s:", unname));
return(nw_unlink_node(nwpath->volume, unname, &(fs->statb)));
}
int nw_delete_files(int dir_handle, int searchattrib, uint8 *data, int len)
{
NW_PATH nwpath;
struct stat stbuff;
int completition = conn_get_kpl_path(&nwpath, &stbuff, dir_handle, data, len, 0);
if (completition > -1) {
completition = func_search_entry(&nwpath, searchattrib, do_delete_file, NULL);
if (completition < 0) return(completition);
else if (!completition) return(-0xff);
}
return(completition);
}
#if 1
/* new since 22-May-99, 0.99.pl16 */
/* corrected 03-Jun-99, 0.99.pl17 */
typedef struct {
NW_PATH destpath;
struct stat statbuf;
} MV_FILES_STRUCT;
static int do_mv_file(NW_PATH *nwpath, FUNC_SEARCH *fs)
/* rename one File */
{
char unsource[256];
int result=0;
MV_FILES_STRUCT *nws=(MV_FILES_STRUCT*)fs->ubuf;
struct stat statb;
xstrcpy(unsource, build_unix_name(nwpath, 0));
if (stat(unsource, &statb) ||
tru_eff_rights_exists(nwpath->volume, unsource, &statb,
TRUSTEE_W|TRUSTEE_M|TRUSTEE_R))
result=-0x8b;
else if ( !S_ISDIR(fs->statb.st_mode) /* file */ && !(entry8_flags&0x80) &&
-1 == share_file(fs->statb.st_dev, fs->statb.st_ino, 0x10f, 2) )
result = -0x8a; /* NO Rename Privileges, file is shared open */
/* patch from Przemyslaw Czerpak */
if (!result) {
/* sourcefile is ok, now try to move to destfile */
char undest[256];
char saved_fn[256];
uint8 *frompath = nwpath->fn;
uint8 *topath = nws->destpath.fn;
uint8 *otopath = saved_fn;
uint8 c;
/* we must save destpath, because perhaps we must modify it */
strmaxcpy(saved_fn, nws->destpath.fn, sizeof(saved_fn)-1);
while ((0 != (c = *otopath++))) {
switch (c) {
case '?' :
case 0xbf:
if ( *frompath
&& *frompath != '.'
&& *frompath != 0xae )
*topath++ = *frompath++;
break;
case '.' :
case 0xae:
while (*frompath
&& *frompath != '.'
&& *frompath != 0xae )
frompath++;
if (*frompath)
frompath++;
/* only append '.' if not at end */
if (*otopath)
*topath++='.';
break;
default:
if (*frompath && *frompath != '.' && *frompath != 0xae)
frompath++;
*topath++=c;
break;
} /* switch */
} /* while */
*topath='\0';
xstrcpy(undest, build_unix_name(&nws->destpath, 0));
/* now restore destpath.fn */
xstrcpy(nws->destpath.fn, saved_fn);
if (seteuid(0)) {}
if (entry8_flags & 0x4) /* new: 20-Nov-96 */
result = unx_mvfile_or_dir(unsource, undest);
else
result = unx_mvfile(unsource, undest);
(void)reseteuid();
switch (result) {
case 0 : break; /* ok */
case EEXIST : result = -0x92; break; /* allready exist */
case EXDEV : result = -0x9a; break; /* cross device */
case EROFS : result = -0x8b; break; /* no rights */
default : result = -0xff; break; /* unknown error */
}
}
return(result);
}
int nw_mv_files(int searchattrib,
int sourcedirhandle, uint8 *sourcedata, int sourcedatalen,
int destdirhandle, uint8 *destdata, int destdatalen)
{
NW_PATH nwpath;
struct stat stbuff;
int completition = conn_get_kpl_path(&nwpath, &stbuff, sourcedirhandle, sourcedata, sourcedatalen, 0);
if (completition > -1) {
FUNC_SEARCH fs;
MV_FILES_STRUCT mvs;
completition=conn_get_kpl_path(&mvs.destpath, &mvs.statbuf,
destdirhandle, destdata, destdatalen, 0);
if (completition > -1) {
char destpath[256];
completition=0;
xstrcpy(destpath, build_unix_name(&mvs.destpath, 1));
if (tru_eff_rights_exists(mvs.destpath.volume, destpath,
&mvs.statbuf, TRUSTEE_W))
completition=-0x8b;
/* now destpath is tested to be writable */
}
if (completition > -1) {
fs.ubuf = (uint8*)&mvs;
completition = func_search_entry(&nwpath, searchattrib, do_mv_file, &fs);
if (completition < 0) return(completition);
else if (!completition) return(-0xff);
else return(0);
}
}
return(completition);
}
#else /* old version (before 22-May-99, 0.99.pl15 ) */
/* "Resolve" string 'topath' (possible with wildcards '?') using
* 'frompath' as source for substitution. Make changes directly in
* 'topath'. Return new length of topath (equal or less than original value)
* Routine from: Andrew Sapozhnikov
*/
static int apply_wildcards (uint8 *frompath, int flen, uint8 *topath, int tlen)
{
int i,tlen2;
uint8 c,*topath2;
for (i=flen; i > 0; i--) {
c=frompath[i-1];
if (c == ':' || c == '\\' || c == '/') break;
}
frompath+=i;
flen-=i;
for (i=tlen; i > 0; i--) {
c=topath[i-1];
if(c == ':' || c == '\\' || c == '/') break;
}
topath2=(topath+=i);
tlen2=tlen-i;
while (tlen2--) {
switch (c=*topath2++) {
case '?':
case 0xbf:
if (flen && *frompath != '.' && *frompath != 0xae) {
*topath++ = *frompath++;
flen--;
} else tlen--;
break;
case '.':
case 0xae:
while (flen && *frompath != '.' && *frompath != 0xae) {
frompath++;
flen--;
}
if (flen) {
frompath++;
flen--;
}
*topath++=c;
break;
default:
if (flen && *frompath != '.' && *frompath != 0xae) {
frompath++;
flen--;
}
*topath++=c;
}
}
return tlen;
}
int mv_file(int qdirhandle, uint8 *q, int qlen,
int zdirhandle, uint8 *z, int zlen)
{
NW_PATH quellpath;
struct stat qstbuff;
NW_PATH zielpath;
struct stat zstbuff;
int completition;
zlen=apply_wildcards(q, qlen, z, zlen);
completition=conn_get_kpl_path(&quellpath, &qstbuff, qdirhandle, q, qlen, 0);
if (completition > -1) {
char qfn[256];
xstrcpy(qfn, build_unix_name(&quellpath,0));
completition=conn_get_kpl_path(&zielpath, &zstbuff, zdirhandle, z, zlen, 0);
if (completition > -1) {
char zpath[256];
completition=0;
xstrcpy(zpath, build_unix_name(&zielpath, 1));
if (stat(qfn, &qstbuff) ||
tru_eff_rights_exists(quellpath.volume, qfn, &qstbuff,
TRUSTEE_W|TRUSTEE_M|TRUSTEE_R))
completition=-0x8b;
else if (tru_eff_rights_exists(zielpath.volume, zpath, &zstbuff,
TRUSTEE_W))
completition=-0x8b;
}
if (!completition){
char unziel[256];
xstrcpy(unziel, build_unix_name(&zielpath,0));
if (seteuid(0)) {}
if (entry8_flags & 0x4) /* new: 20-Nov-96 */
completition = unx_mvfile_or_dir(qfn, unziel);
else
completition = unx_mvfile(qfn, unziel);
(void)reseteuid();
switch (completition) {
case 0 : break;
case EEXIST : completition = -0x92; break; /* allready exist */
case EXDEV : completition = -0x9a; break; /* cross device */
case EROFS : completition = -0x8b; break; /* no rights */
default : completition = -0xff;
}
}
}
return(completition);
}
#endif
static int do_set_file_info(NW_PATH *nwpath, FUNC_SEARCH *fs)
{
char unname[256];
int result=0;
NW_FILE_INFO *f=(NW_FILE_INFO*)fs->ubuf;
int voloptions = get_volume_options(nwpath->volume);
struct stat statb;
xstrcpy(unname, build_unix_name(nwpath, 0));
if (!stat(unname, &statb)) {
if (S_ISFIFO(statb.st_mode) || (voloptions&VOL_OPTION_IS_PIPE))
return(0); /* do nothing but report OK */
if (tru_eff_rights_exists(nwpath->volume, unname, &statb, TRUSTEE_M))
result=-0x8c; /* no modify rights */
} else result=-0xff;
if (!result) {
struct utimbuf ut;
ut.actime = ut.modtime = nw_2_un_time(f->modify_date, f->modify_time);
result=set_nw_attrib_word(nwpath->volume, unname, &statb,
(int)GET_16(f->attrib));
if (!result) {
if (seteuid(0)) {}
if (utime(unname, &ut))
result= (-0x8c); /* no modify rights */
(void)reseteuid();
}
}
XDPRINTF((5,0,"set_file_info result=0x%x, unname:%s:", unname, -result));
return(result);
}
static void free_dir_stuff(struct stat *stb, int complete)
{
NW_DIR *d=&(dirs[0]);
int j = -1;
if (complete) {
while (++j < (int)used_dirs){
if ( d->dev == stb->st_dev &&
d->inode == stb->st_ino)
d->inode = 0;
d++;
}
j = -1;
}
while (++j < (int)anz_dirhandles){
DIR_HANDLE *dh=&(dir_handles[j]);
if (dh && dh->dev == stb->st_dev && dh->inode == stb->st_ino) {
if (complete)
free_dir_handle(j+1);
else if (dh->f) { /* only close directories */
/* needed to ask for null pointer, hint from Boris Popov, 21-Feb-99 */
closedir(dh->f);
dh->f = (DIR*)NULL;
}
}
}
}
int nw_set_file_information(int dir_handle, uint8 *data, int len,
int searchattrib, NW_FILE_INFO *f)
{
NW_PATH nwpath;
struct stat stbuff;
int completition = conn_get_kpl_path(&nwpath, &stbuff, dir_handle, data, len, 0);
if (completition > -1) {
FUNC_SEARCH fs;
fs.ubuf = (uint8*)f;
completition = func_search_entry(&nwpath, searchattrib,
do_set_file_info, &fs);
if (completition < 0) return(completition);
else if (!completition) return(-0xff);
}
return(completition);
}
int nw_set_file_attributes(int dir_handle, uint8 *data, int len,
int attrib, int newattrib)
{
char unname[256];
struct stat stbuff;
int completition=-0x9c;
NW_PATH nwpath;
#if PERSISTENT_SYMLINKS
S_STATB stb;
#endif
build_path(&nwpath, data, len, 0);
if (nwpath.fn[0] != '.') { /* Files with . at the beginning are not ok */
completition = build_dir_name(&nwpath, &stbuff, dir_handle);
}
if (completition < 0) return(completition);
xstrcpy(unname, build_unix_name(&nwpath, 2));
XDPRINTF((5,0,"set file attrib 0x%x, unname:%s:", newattrib, unname));
if (!s_stat(unname, &stbuff, &stb)){
int result = set_nw_attrib_byte(nwpath.volume, unname, &stbuff, newattrib);
return( (result != 0) ? -0x8c : 0); /* no modify rights */
}
return(-0x9c); /* wrong path */
}
static int nw_rmdir(uint8 *unname)
{
if (rmdir(unname)) {
if (errno == /*EEXIST*/ ENOTEMPTY) return(-0xa0); /* directory not empty */
return(-0x8a); /* no privilegs */
}
return(0);
}
int nw_unlink_node(int volume, uint8 *unname, struct stat *stb)
{
int result=-1;
uint32 attrib=get_nw_attrib_dword(volume, unname, stb);
/* first we look for attributes */
if (attrib & (FILE_ATTR_R|FILE_ATTR_DELETE_INH))
return(-0x8a); /* don't delete 'readonly' */
if (tru_eff_rights_exists(volume, unname, stb, TRUSTEE_E))
return(-0x8a); /* no delete rights */
if (S_ISDIR(stb->st_mode)) { /* directory */
free_dir_stuff(stb, 0);
result=nw_rmdir(unname);
if (result==-0x8a){ /* no privilegs */
if (seteuid(0)) {}
result=nw_rmdir(unname);
(void)reseteuid();
}
if (!result)
free_dir_stuff(stb, 1);
} else {
/* changed by: Ingmar Thiemann <ingmar@gefas.com>
* because share_file() changed
*/
if (!(entry8_flags&0x10) &&
-1 == share_file(stb->st_dev, stb->st_ino, 0x10f, 2))
return(-0x8a); /* NO Delete Privileges, file is open */
if (0 != (result=unlink(unname))){
if (seteuid(0)) {}
result=unlink(unname) ? -0x8a : 0;
(void)reseteuid();
}
}
if (!result) {
free_nw_ext_inode(volume, unname, stb->st_dev, stb->st_ino);
}
return(result);
}
int nw_creat_node(int volume, uint8 *unname, int mode)
/* creat file or directory, depending on mode */
/* mode & 0x1 == directory */
/* mode & 0x2 == creat/trunc */
/* next is only for file creation, needed by some queue functions */
/* mode & 0x8 == ignore rights, try to open as root */
{
struct stat stb;
uint8 path[260];
uint8 *p=path+strlen(unname);
xstrcpy(path, unname);
while (p > path && *p != '/') --p;
if (p > path) {
*p='\0';
if (stat(path, &stb)) return(-0x9c);
} else if (*p=='/') {
*(p+1)='.';
*(p+2)='\0';
if (stat(path, &stb)) return(-0x9c);
} else
return(-0x9c);
if (mode & 1) { /* directory */
int result=-0xff;
if (!tru_eff_rights_exists(volume, path, &stb, TRUSTEE_C)){
result=mkdir(unname, 0777);
if (result) {
if (seteuid(0)) {}
if (0==(result=mkdir(unname, 0755)))
if (chown(unname, act_uid, act_gid)) {}
(void)reseteuid();
}
if (result)
result=-0xff;
} else result=-0x84; /* no creat rights */
if (!result) {
int umode_dir=get_volume_umode_dir(volume);
if (umode_dir) {
if (umode_dir == -1) /* we get parent dir */
umode_dir=stb.st_mode;
if (seteuid(0)) {}
chmod(unname, umode_dir);
(void)reseteuid();
}
}
return(result);
} else { /* file */
int fd=-1;
struct stat stbuff;
int exist;
if (seteuid(0)) {}
exist=stat(unname, &stbuff) ? 0 : 1;
(void)reseteuid();
if (!(mode&0x8)) { /* we must test for access */
if (exist) { /* test for write rights */
if (get_nw_attrib_dword(volume, unname, &stbuff) & FILE_ATTR_R)
return(-0x94); /* No write rights */
if (tru_eff_rights_exists(volume, unname, &stbuff, TRUSTEE_W))
return(-0x94); /* No write rights */
} else { /* test for creat rights */
if (tru_eff_rights_exists(volume, path, &stb, TRUSTEE_C))
return(-0x84); /* No creat rights */
}
}
if (mode & 2 || (exist && (mode&0x8)) ) { /* trunc */
if (0 > (fd=open(unname, O_CREAT|O_TRUNC|O_RDWR, 0666))) {
if (seteuid(0)) {}
if (-1 < (fd=open(unname, O_CREAT|O_TRUNC|O_RDWR, 0600)))
if (chown(unname, act_uid, act_gid)) {}
(void)reseteuid();
}
} else if (!exist) {
if (0 > (fd = creat(unname, 0777))) {
if (seteuid(0)) {}
if (-1 < (fd = creat(unname, 0751)))
if (chown(unname, act_uid, act_gid)) {}
(void)reseteuid();
}
}
if ( fd > -1 ) {
int umode_file=get_volume_umode_file(volume);
close(fd);
if (umode_file > 0)
chmod(unname, umode_file);
return(0);
}
}
return(-0xff);
}
int nw_utime_node(int volume, uint8 *unname, struct stat *stb,
time_t t)
{
if (!tru_eff_rights_exists(volume, unname, stb, TRUSTEE_M)){
struct utimbuf ut;
ut.actime = ut.modtime = t;
if (!utime(unname, &ut))
return(0);
if (seteuid(0)) {}
if (!utime(unname, &ut)) {
(void)reseteuid();
return(0);
}
(void)reseteuid();
}
return(-0x8c); /* no modify privileges */
}
int nw_mk_rd_dir(int dir_handle, uint8 *data, int len, int mode)
{
NW_PATH nwpath;
struct stat stbuff;
int completition = conn_get_kpl_path(&nwpath, &stbuff,
dir_handle, data, len, (mode) ? 0 : 1 );
if (completition > -1) {
char unname[256];
xstrcpy(unname, build_unix_name(&nwpath, 2));
if (mode) {
completition=nw_creat_node(nwpath.volume, unname, 1);
} else { /* rmdir */
if (!stat(unname, &stbuff))
completition=nw_unlink_node(nwpath.volume, unname, &stbuff);
else
completition=-0x9c;
}
}
return(completition);
}
int mv_dir(int dir_handle, uint8 *sourcedata, int sourcedatalen,
uint8 *destdata, int destdatalen)
{
NW_PATH quellpath;
struct stat qstbuff;
NW_PATH zielpath;
int completition=conn_get_kpl_path(&quellpath, &qstbuff, dir_handle,
sourcedata, sourcedatalen, 0);
if (completition > -1){
char qfn[256];
char zpath[256];
struct stat zstbuff;
completition = 0;
xstrcpy(qfn, build_unix_name(&quellpath,0));
memcpy(&zielpath, &quellpath, sizeof(NW_PATH));
strmaxcpy(zielpath.fn, destdata, destdatalen);
/* patch from Sven Norinder <snorinder@sgens.ericsson.se> :09-Nov-96 */
if (get_volume_options(zielpath.volume) & VOL_OPTION_DOWNSHIFT)
down_fn(zielpath.fn);
else
up_fn(zielpath.fn);
#if 0
/* this is not possible ---- */
completition=conn_get_kpl_path(&zielpath, &zstbuff, dir_handle, destdata, destdatalen, 0);
/* ----------- because ----- */
/* for example the novell rendir.exe does something like this
* 0x0,0xd,0xf,0x0,0x7,'T','M','P',':','\','I','I',0x2,'K','K'
* no dirhandle, qpath = fullpath, zpath = only name
*/
#endif
xstrcpy(zpath, build_unix_name(&zielpath, 1));
if (stat(qfn, &qstbuff) ||
tru_eff_rights_exists(quellpath.volume, qfn, &qstbuff,
TRUSTEE_W|TRUSTEE_M|TRUSTEE_R))
completition=-0x8b;
else if (stat(zpath, &zstbuff) ||
tru_eff_rights_exists(zielpath.volume, zpath, &zstbuff,
TRUSTEE_W))
completition=-0x8b;
if (completition > -1){
int result;
char unziel[256];
xstrcpy(unziel, build_unix_name(&zielpath, 0));
if (seteuid(0)) {}
result = unx_mvdir((uint8 *)qfn, (uint8 *)unziel);
(void)reseteuid();
XDPRINTF((4,0, "rendir result=%d, '%s'->'%s'",
result, qfn, unziel));
if (!result)
completition = 0;
else {
if (result == EEXIST)
completition=-0x92; /* allready exist */
else if (result == EXDEV)
completition=-0x9a; /* cross devices */
else completition=-0x9c; /* wrong path */
}
}
}
return(completition);
}
int nw_mv_dir_between_handles(int sourcedirhandle, uint8 *sourcedata, int sourcedatalen,
int zdirhandle, uint8 *destdata, int destdatalen)
/*
* Rename/move a directory where source and destination are expressed using
* separate directory handles. This is needed by NCP 22/46 Rename Or Move
* (old). The older mv_dir() helper only supports the classic NCP 22/15
* style where the destination is just a new name below the source parent.
*/
{
NW_PATH quellpath;
NW_PATH zielpath;
struct stat qstbuff;
struct stat zstbuff;
int completition = conn_get_kpl_path(&quellpath, &qstbuff,
sourcedirhandle,
sourcedata, sourcedatalen, 0);
XDPRINTF((5,0,
"nw_mv_dir_between_handles: enter src_h=%d dst_h=%d src_len=%d dst_len=%d src=`%.*s` dst=`%.*s` src_res=%d",
sourcedirhandle, zdirhandle, sourcedatalen, destdatalen,
sourcedatalen, sourcedata, destdatalen, destdata, completition));
if (completition > -1) {
char qfn[256];
char zparent[256];
char unziel[256];
xstrcpy(qfn, build_unix_name(&quellpath, 0));
XDPRINTF((5,0,
"nw_mv_dir_between_handles: source nwpath=`%s` unix=`%s` mode=0%o",
conn_get_nwpath_name(&quellpath), qfn, (unsigned)qstbuff.st_mode));
if (!S_ISDIR(qstbuff.st_mode)) {
XDPRINTF((5,0, "nw_mv_dir_between_handles: source is not directory"));
return(-0x9c);
}
completition = conn_get_kpl_path(&zielpath, &zstbuff,
zdirhandle,
destdata, destdatalen, 0);
XDPRINTF((5,0,
"nw_mv_dir_between_handles: dest resolve result=%d",
completition));
if (completition < 0)
return(completition);
if (quellpath.volume != zielpath.volume) {
XDPRINTF((5,0,
"nw_mv_dir_between_handles: cross-volume src_vol=%d dst_vol=%d",
quellpath.volume, zielpath.volume));
return(-0x9a); /* cross devices/volumes */
}
xstrcpy(zparent, build_unix_name(&zielpath, 1));
if (stat(qfn, &qstbuff) ||
tru_eff_rights_exists(quellpath.volume, qfn, &qstbuff,
TRUSTEE_W|TRUSTEE_M|TRUSTEE_R)) {
XDPRINTF((5,0,
"nw_mv_dir_between_handles: source rights/stat failed path=`%s`",
qfn));
completition=-0x8b;
} else if (stat(zparent, &zstbuff) ||
tru_eff_rights_exists(zielpath.volume, zparent, &zstbuff,
TRUSTEE_W)) {
XDPRINTF((5,0,
"nw_mv_dir_between_handles: dest parent rights/stat failed path=`%s`",
zparent));
completition=-0x8b;
}
if (completition > -1) {
int result;
xstrcpy(unziel, build_unix_name(&zielpath, 0));
XDPRINTF((5,0,
"nw_mv_dir_between_handles: moving `%s` -> `%s` parent=`%s`",
qfn, unziel, zparent));
if (seteuid(0)) {}
result = unx_mvdir((uint8 *)qfn, (uint8 *)unziel);
(void)reseteuid();
XDPRINTF((4,0, "rendir/movedir result=%d, '%s'->'%s'",
result, qfn, unziel));
if (!result)
completition = 0;
else {
if (result == EEXIST)
completition=-0x92; /* already exists */
else if (result == EXDEV)
completition=-0x9a; /* cross devices */
else completition=-0x9c; /* wrong path */
}
}
}
XDPRINTF((5,0, "nw_mv_dir_between_handles: return %d", completition));
return(completition);
}
static int change_dir_entry( NW_DIR *dir, int volume,
uint8 *path,
int dev, ino_t inode,
int driveletter, int is_temp,
int new_entry, int task)
{
if (new_entry || (dir->inode && dir->is_temp != 2)) {
int len;
if (*path=='/' && *(path+1) != '\0') path++;
len=strlen(path);
if (dir->path) xfree(dir->path);
dir->path=xmalloc(len+2);
if (len) {
memcpy(dir->path, path, len);
if (dir->path[len-1] != '/') {
*(dir->path + len) = '/';
++len;
}
} else {
*(dir->path) = '/';
++len;
}
*(dir->path+len) = '\0';
dir->dev = dev;
dir->inode = inode;
dir->volume = (uint8) volume;
dir->timestamp = time(NULL);
if (driveletter > -1) {
dir->drive = (uint8) driveletter;
dir->task = (uint8)task;
} else {
if (task < (int)dir->task) dir->task = (uint8) task;
}
if (is_temp > -1) dir->is_temp = (uint8) is_temp;
return(0);
} else {
if (!dir->inode) return(-0x9b); /* wrong handle */
else return(-0xfa); /* temp remap Error */
}
}
void nw_exit_connect(void)
{
if (connect_is_init) {
init_file_module(-1);
}
#if WITH_NAME_SPACE_CALLS
exit_name_space_module();
#endif
}
int nw_init_connect(void)
/* May be called when ever you want */
{
uint8 *login = (uint8*) "LOGIN/";
NW_PATH nwlogin;
FILE *f= open_nw_ini();
if (f != (FILE*) NULL){
uint8 buff[256];
struct stat stbuff;
int what;
int k = MAX_NW_DIRS;
NW_DIR *d = &(dirs[0]);
int namspace_max_baseh=0;
int namspace_max_searchh=0;
xstrcpy(nwlogin.path, (char*)login);
nwlogin.fn[0] = '\0';
nwlogin.volume = 0;
while (k--) {
if (connect_is_init)
xfree(d->path);
else
d->path = NULL;
d->volume = 0;
d->inode = 0;
d->is_temp = 0;
d->drive = 0;
d++;
}
init_file_module(-1);
clear_extracted_base_handles(-1);
if (connect_is_init) {
k = 0;
while (k++ < anz_dirhandles)
free_dir_handle(k);
} else
connect_is_init++;
while (0 != (what = get_ini_entry(f, 0, buff, sizeof(buff)))) {
if (what == 6) { /* version */
if (2 != sscanf((char*)buff, "%d %x",
&tells_server_version,
&server_version_flags))
server_version_flags=0;
} else if (what == 8) { /* entry8_flags */
entry8_flags = hextoi((char*)buff);
} else if (what == 9) { /* umode */
uint8 buf1[300], buf2[300];
if (2 == sscanf((char*)buff, "%300s %300s", buf1, buf2)) {
default_umode_dir = octtoi(buf1);
default_umode_file = octtoi(buf2);
}
} else if (what == 10) { /* GID */
default_gid = atoi((char*)buff);
} else if (what == 11) { /* UID */
default_uid = atoi((char*)buff);
} else if (what == 30) { /* Burstmodus */
int recvsize, sendsize;
int i= sscanf((char*)buff, "%i %i", &recvsize, &sendsize);
if (i>0){
max_burst_recv_size=recvsize;
if (i>1)
max_burst_send_size=sendsize;
}
} else if (what == 31) { /* entry31_flags */
entry31_flags = hextoi((char*)buff);
} else if (50 == what) {
init_nwfname(buff);
} else if (63 == what) { /* MAX_DIR_BASE */
namspace_max_baseh=atoi(buff);
} else if (68 == what) { /* USE_MMAP */
use_mmap=atoi(buff);
} else if (80 == what) {
namspace_max_searchh=atoi(buff);
} else if (what == 103) { /* Debug */
get_debug_level(buff);
}
} /* while */
nw_init_volumes(f);
fclose(f);
#if WITH_NAME_SPACE_CALLS
init_name_space_module(namspace_max_baseh, namspace_max_searchh);
#endif
if (used_nw_volumes < 1) {
errorp(1, "No Volumes defined. Look at ini file entry 1, Abort !!", NULL);
return(-1);
}
if (get_volume_options(0) & (VOL_OPTION_DOWNSHIFT|VOL_OPTION_IGNCASE))
down_fn(nwlogin.path);
if (stat(build_unix_name(&nwlogin, 0), &stbuff)) {
errorp(1, "Stat error LOGIN Directory, Abort !!",
"UnixPath=`%s`, nwlogin.path=%s, nwlogin.fn=%s",
build_unix_name(&nwlogin, 0), nwlogin.path, nwlogin.fn );
return(-1);
}
(void)change_dir_entry(&(dirs[0]), 0, nwlogin.path,
stbuff.st_dev, stbuff.st_ino,
0, 0, 1, 0);
/* first Handle must be known und must not be temp */
/* and has no Drive-Character */
used_dirs = 1;
anz_dirhandles = 0;
return(0);
} else return(-1);
}
int nw_free_handles(int task)
/*
* if task== -1 then all is initialized
* else the temp handles of the actual task
* are deleted. I hope this is right. !??
*/
{
if (task == -1)
return(nw_init_connect());
else {
NW_DIR *d = &(dirs[0]);
int k = used_dirs;
clear_extracted_base_handles(task);
while (k--) {
if (d->is_temp && d->task == task) {
/* only actual task */
xfree(d->path);
d->volume = 0;
d->inode = 0;
d->is_temp = 0;
d->drive = 0;
}
d++;
}
for (k=0; k < anz_dirhandles; k++){
DIR_HANDLE *dh=&(dir_handles[k]);
if (dh->f) {
closedir(dh->f);
dh->f=NULL;
}
}
init_file_module(task);
}
return(0);
}
int xinsert_new_dir(int volume, uint8 *path, int dev, int inode, int drive, int is_temp, int task)
{
int j = 0;
int freehandle = 0;
int timedhandle_same_task = 0;
int timedhandle_any_task = 0;
time_t lowtime_same_task = time(NULL);
time_t lowtime_any_task = time(NULL);
/*
* Temporary directory handles are supposed to be freed automatically at
* End Of Job. Some DOS requesters/tools, notably Novell NCOPY through
* Client32, can allocate temp handles without sending EOJ often enough for
* MARS-NWE's small dir-handle table. The old code only reused empty slots
* and returned 0x9d (no directory handles) once the table had filled with
* stale temp handles. That makes NCOPY fail before the actual copy with
* "NWGetEffectiveDirectoryRights returned an error."
*
* Prefer a genuinely free slot. If the table is full and this is another
* temp-handle allocation, recycle the oldest temp handle from the same task;
* only if none exists, recycle the oldest temp handle from any task.
* Permanent handles are never recycled here.
*/
for (j = (used_dirs) ? 1 : 0; j < (int)used_dirs; j++) {
NW_DIR *d = &(dirs[j]);
if (!d->inode) {
freehandle = j+1;
} else if (is_temp && d->is_temp) {
if (d->task == (uint8)task && d->timestamp <= lowtime_same_task) {
timedhandle_same_task = j+1;
lowtime_same_task = d->timestamp;
}
if (d->timestamp <= lowtime_any_task) {
timedhandle_any_task = j+1;
lowtime_any_task = d->timestamp;
}
}
}
if (!freehandle && used_dirs < MAX_NW_DIRS) freehandle = ++used_dirs;
if (!freehandle && is_temp) {
freehandle = timedhandle_same_task ? timedhandle_same_task : timedhandle_any_task;
if (freehandle) {
NW_DIR *d = &(dirs[freehandle-1]);
XDPRINTF((3,0,"Recycle stale temp dhandle:%d old='%d:%s' oldtask=%d newtask=%d",
freehandle, d->volume, d->path ? (char*)d->path : "",
d->task, task));
if (d->path) {
xfree(d->path);
d->path = NULL;
}
d->inode = 0;
}
}
if (freehandle){
(void)change_dir_entry(&(dirs[freehandle-1]),
volume, path, dev, inode,
drive, is_temp, 1, task);
while (used_dirs > freehandle && !dirs[used_dirs-1].inode) used_dirs--;
return(freehandle);
} else return(-0x9d); /* no dir Handles */
}
static int insert_new_dir(NW_PATH *nwpath, int dev, int inode,
int drive, int is_temp, int task)
{
return(xinsert_new_dir(nwpath->volume, nwpath->path,
dev, inode, drive, is_temp, task));
}
int nw_search(uint8 *info, uint32 *fileowner,
int dirhandle, int searchsequence,
int search_attrib, uint8 *data, int len)
{
NW_PATH nwpath;
struct stat stbuff;
int completition = conn_get_kpl_path(&nwpath, &stbuff, dirhandle, data, len, 0);
XDPRINTF((5,0,"nw_search path:%s:, fn:%s:, completition:0x%x",
nwpath.path, nwpath.fn, completition));
if (completition > -1) {
struct stat stbuff;
completition=get_dir_entry(&nwpath,
&searchsequence,
search_attrib,
&stbuff);
if (!completition) {
char unixname[300];
xstrcpy(unixname, build_unix_name(&nwpath, 0));
if ( S_ISDIR(stbuff.st_mode) ) {
get_dir_attrib((NW_DIR_INFO*)info, unixname, &stbuff,
&nwpath);
} else {
get_file_attrib((NW_FILE_INFO*)info, unixname, &stbuff,
&nwpath);
}
if (fileowner) *fileowner = get_file_owner(&stbuff);
return(searchsequence);
}
}
return(completition);
}
int nw_dir_get_vol_path(int dirhandle, uint8 *path)
/* returns volume or error ( < 0) */
{
int result;
NW_DIR *dir = (dirhandle > 0 && dirhandle <= used_dirs)
? &(dirs[dirhandle-1])
: NULL;
if (dir && dir->inode) {
XDPRINTF((3,0,"MAPDEBUG nw_dir_get_vol_path handle=%d vol=%d path=`%s` drive=%d task=%d temp=%d inode=0x%x",
dirhandle, dir->volume, dir->path ? (char*)dir->path : "",
dir->drive, dir->task, dir->is_temp, dir->inode));
int llen = strlen(dir->path);
uint8 *p = path+llen;
result = dir->volume;
memcpy(path, dir->path, llen+1);
if (llen && *(p-1) == '/')
*(p-1) = '\0';
if (result < 0) result = -0x98; /* wrong volume */
} else result = -0x9b;
return(result);
}
int nw_dir_search(uint8 *info,
int dirhandle, int searchsequence,
int search_attrib, uint8 *data, int len)
{
NW_PATH nwpath;
int completition=-0x9c;
build_path(&nwpath, data, len, 0);
if (dirhandle > 0 && --dirhandle < anz_dirhandles){
DIR_HANDLE *dh = &(dir_handles[dirhandle]);
char unixname[300];
struct stat stbuff;
if (dh->vol_options & VOL_OPTION_DOWNSHIFT) {
down_fn(nwpath.fn);
} else {
up_fn(nwpath.fn);
}
nwpath.volume=dh->volume;
if (get_dh_entry(dh,
nwpath.fn,
sizeof(nwpath.fn),
&searchsequence,
search_attrib,
unixname,
sizeof(unixname),
&stbuff)){
if ( S_ISDIR(stbuff.st_mode) ) {
get_dir_attrib((NW_DIR_INFO*)info, unixname, &stbuff,
&nwpath);
} else {
if (dh->vol_options & VOL_OPTION_IS_PIPE)
stbuff.st_size = 0x70000000|(stbuff.st_mtime&0xfffffff);
get_file_attrib((NW_FILE_INFO*)info, unixname, &stbuff,
&nwpath);
}
return(searchsequence);
} else return(-0xff); /* not found */
} else return(completition); /* wrong path */
}
int nw_alloc_dir_handle( int dir_handle, /* source directory handle */
uint8 *data, /* source path */
int len, /* pathlen */
int driveletter, /* A .. Z normal */
int is_temphandle, /* temp handle = 1 */
/* special temp handle = 2 */
int task, /* process task */
int *eff_rights)
{
NW_PATH nwpath;
struct stat stbuff;
int inode=conn_get_kpl_path(&nwpath, &stbuff, dir_handle, data, len, 1);
if (inode > -1) {
uint8 unixname[257];
xstrcpy(unixname, build_unix_name(&nwpath, 0));
inode = insert_new_dir(&nwpath, stbuff.st_dev, stbuff.st_ino,
driveletter, is_temphandle, task);
*eff_rights=tru_get_eff_rights(nwpath.volume, unixname, &stbuff);
}
XDPRINTF((4,0,"Allocate %shandle:%s, Qhandle=%d, drive=%d, Task=%d, result=0x%x",
(is_temphandle) ? "Temp" : "Perm", conn_get_nwpath_name(&nwpath),
dir_handle, driveletter, task, inode));
return(inode);
}
int nw_open_dir_handle( int dir_handle,
uint8 *data, /* extra path */
int len, /* len of DATA */
int *volume, /* Volume */
int *dir_id,
int *searchsequence)
/*
* Routine returns handle to use in searchroutines.
* RETURN=errcode ( <0 ) or eff. ACCES Rights
*/
{
NW_PATH nwpath;
struct stat stbuff;
int completition = conn_get_kpl_path(&nwpath, &stbuff, dir_handle, data, len, 1);
if (completition > -1) {
XDPRINTF((5,0,"NW_OPEN_DIR: completition = 0x%x; nwpath= %s",
(int)completition, conn_get_nwpath_name(&nwpath) ));
completition = new_dir_handle(&stbuff, &nwpath);
if (completition > -1) {
struct stat stb;
DIR_HANDLE *dh = &(dir_handles[completition-1]);
s_stat(dh->unixname, &stb, NULL);
*volume = dh->volume;
*dir_id = completition;
*searchsequence = MAX_U16;
completition = tru_get_eff_rights(dh->volume, dh->unixname, &stb);
}
XDPRINTF((5,0,"NW_OPEN_DIR_2: completition = 0x%x",
completition));
} else {
XDPRINTF((4,0,"NW_OPEN_DIR failed: completition = -0x%x", -completition));
}
return(completition);
}
int nw_free_dir_handle(int dir_handle, int task)
{
if (dir_handle && --dir_handle < (int)used_dirs) {
NW_DIR *d=&(dirs[dir_handle]);
XDPRINTF((4,0,"free dhandle:%d, task=%d, d->inode=0x%x, used_dirs=%d",
dir_handle+1, task, d->inode, used_dirs));
if (!d->inode
#if 0
|| d->task != task
#endif
) return(-0x9b); /* wrong handle */
else {
d->inode = 0;
xfree(d->path);
}
return(0);
} else return(-0x9b); /* wrong handle */
}
int alter_dir_handle(int targetdir, int volume, uint8 *path,
int dev, int inode, int task)
/* targetdir will be changed */
{
if (targetdir > 0 && --targetdir < used_dirs
&& dirs[targetdir].is_temp != 2) {
/* do not change special temphandles */
XDPRINTF((3,0,"MAPDEBUG Change dhandle:%d(%d) -> '%d:%s' dev=0x%x inode=0x%x old='%d:%s' olddrive=%d oldtask=%d",
targetdir+1, task, volume, path, dev, inode,
dirs[targetdir].volume, dirs[targetdir].path ? (char*)dirs[targetdir].path : "",
dirs[targetdir].drive, dirs[targetdir].task));
XDPRINTF((5,0,"Change dhandle:%d(%d) -> '%d:%s'", targetdir+1, task,
volume, path));
return(change_dir_entry(&dirs[targetdir],
volume, path, dev, inode,
-1, -1, 0, task));
/* here the existing handle is only modified */
} else return(-0x9b); /* BAD DIR Handle */
}
int nw_set_dir_handle(int targetdir, int dir_handle,
uint8 *data, int len, int task)
/* targetdirs gets path of dirhandle + data */
{
NW_PATH nwpath;
struct stat stbuff;
int inode = conn_get_kpl_path(&nwpath, &stbuff, dir_handle, data, len, 1);
XDPRINTF((3,0,"MAPDEBUG nw_set_dir_handle target=%d source=%d len=%d task=%d resolved=%s inode=0x%x",
targetdir, dir_handle, len, task, conn_get_nwpath_name(&nwpath), inode));
if (inode > -1)
inode = alter_dir_handle(targetdir, nwpath.volume, nwpath.path,
stbuff.st_dev, stbuff.st_ino, task);
XDPRINTF((3,0,"MAPDEBUG nw_set_dir_handle result=0x%x target=%d", inode, targetdir));
return(inode); /* invalid PATH */
}
int conn_map_path_to_dir_entry(int dirhandle, uint8 *data, int len,
uint8 *volume_out, uint8 *dirnum_out)
/*
* NCP23/F4 Convert Path to Dir Entry helper.
* Returns 0 or a negative mars_nwe/NCP error.
* Reply fields are volume byte and DOS namespace directory number (LO-HI).
*/
{
char unixname[512];
struct stat stbuff;
int volume = conn_get_kpl_unxname(unixname, sizeof(unixname),
dirhandle, data, len);
if (volume < 0) return(volume);
if (s_stat(unixname, &stbuff, NULL)) return(-0x9c);
/*
* NCP23/F4 maps a path to a namespace entry number. Despite the
* historical "Dir Entry" wording, clients may use the returned number
* for file entries as well as directory entries, and NCP23/F3 maps that
* number back to a component path. Therefore do not reject regular
* files here; any stat'able volume entry that can be represented by the
* namespace handle table is valid.
*/
{
DEV_NAMESPACE_MAP dnm;
uint32 dirnum;
dnm.dev = stbuff.st_dev;
dnm.namespace = NAME_DOS;
dirnum = nw_vol_inode_to_handle(volume, stbuff.st_ino, &dnm);
if (!dirnum) return(-0x9b);
if (volume_out) *volume_out = (uint8)volume;
if (dirnum_out) U32_TO_32(dirnum, dirnum_out);
XDPRINTF((5,0,
"NCP23/F4 helper: dh=%d pathlen=%d unix=`%s` vol=%d dirnum=0x%lx",
dirhandle, len, unixname, volume, (unsigned long)dirnum));
}
return(0);
}
int nw_get_directory_path(int dir_handle, uint8 *name, int size_name)
{
int result = -0x9b;
name[0] = '\0';
if (dir_handle > 0 && --dir_handle < (int)used_dirs
&& dirs[dir_handle].inode) {
int volume = dirs[dir_handle].volume;
if (volume > -1 && volume < used_nw_volumes){
result = slprintf((char*)name, size_name-1, "%s:%s", nw_volumes[volume].sysname, dirs[dir_handle].path);
if (result > 0) {
if (name[result-1] == '/') name[--result] = '\0';
up_fn(name);
} else result= -0x9c; /* wrong path */
} else result = -0x98;
}
XDPRINTF((3,0,"MAPDEBUG nw_get_directory_path:%s: Handle=%d, result=0x%x", name, dir_handle+1, result));
XDPRINTF((5,0,"nw_get_directory_path:%s: Handle=%d, result=0x%x", name, dir_handle+1, result));
return(result);
}
int nw_extract_base_handle(int dir_handle, uint8 *handle_id)
/* Extract a Base Handle: stores an opaque handle id for Restore Directory Handle */
{
int result = -0x9b;
if (dir_handle > 0 && --dir_handle < (int)used_dirs) {
NW_DIR *d = &(dirs[dir_handle]);
if (d->inode && !d->is_temp && d->volume < used_nw_volumes) {
int j;
EXTRACTED_BASE_HANDLE *free_ebh = NULL;
for (j = 0; j < MAX_EXTRACTED_BASE_HANDLES; j++) {
EXTRACTED_BASE_HANDLE *ebh = &(extracted_base_handles[j]);
if (!ebh->id && !free_ebh) free_ebh = ebh;
if (ebh->id && ebh->volume == d->volume && ebh->path
&& !strcmp((char*)ebh->path, (char*)d->path)) {
free_ebh = ebh;
break;
}
}
if (free_ebh) {
if (!free_ebh->id) {
free_ebh->id = next_extracted_base_handle++;
if (!next_extracted_base_handle) next_extracted_base_handle = 1;
}
xfree(free_ebh->path);
free_ebh->path = xmalloc(strlen((char*)d->path)+1);
strcpy((char*)free_ebh->path, (char*)d->path);
free_ebh->volume = d->volume;
free_ebh->dev = d->dev;
free_ebh->inode = d->inode;
free_ebh->task = d->task;
U32_TO_BE32(free_ebh->id, handle_id);
result = 0;
} else result = -0x96; /* server out of memory/table space */
}
}
XDPRINTF((4,0,"Extract base handle from dhandle=%d result=0x%x", dir_handle+1, result));
return(result);
}
int nw_restore_base_handle(uint8 *handle_id, int task, int *eff_rights)
/* Restore an Extracted Base Handle: allocate a new permanent handle from a saved id */
{
uint32 id = GET_BE32(handle_id);
int j;
int result = -0x9b;
for (j = 0; j < MAX_EXTRACTED_BASE_HANDLES; j++) {
EXTRACTED_BASE_HANDLE *ebh = &(extracted_base_handles[j]);
if (ebh->id == id && ebh->path && ebh->volume >= 0 && ebh->volume < used_nw_volumes) {
NW_PATH nwpath;
struct stat stbuff;
uint8 unixname[257];
nwpath.volume = ebh->volume;
nwpath.fn[0] = '\0';
strmaxcpy(nwpath.path, (char*)ebh->path, sizeof(nwpath.path)-1);
xstrcpy(unixname, build_unix_name(&nwpath, 0));
if (stat((char*)unixname, &stbuff)) {
result = -0x9c; /* invalid path */
} else if (!S_ISDIR(stbuff.st_mode)) {
result = -0x9c;
} else {
result = xinsert_new_dir(nwpath.volume, nwpath.path,
stbuff.st_dev, stbuff.st_ino, 0, 0, task);
if (result > 0 && eff_rights) {
*eff_rights = tru_get_eff_rights(nwpath.volume, unixname, &stbuff);
}
}
break;
}
}
XDPRINTF((4,0,"Restore base handle id=0x%x task=%d result=0x%x", id, task, result));
return(result);
}
int nw_get_vol_number(int dir_handle)
/* Get Volume Nummmer with Handle */
{
int result = -0x9b; /* wrong handle */
if (dir_handle > 0 && --dir_handle < (int)used_dirs
&& dirs[dir_handle].inode ) {
result = dirs[dir_handle].volume;
if (result < 0 || result >= used_nw_volumes) result = -0x98; /* wrong volume */
}
XDPRINTF((5,0,"nw_get_vol_number:0x%x: von Handle=%d", result, dir_handle+1));
return(result);
}
int nw_get_eff_dir_rights(int dir_handle, uint8 *data, int len, int modus)
/* modus 0=only_dir, 1=dirs and files */
{
char unname[256];
struct stat stbuff;
NW_PATH nwpath;
int completition = conn_get_kpl_path(&nwpath, &stbuff,
dir_handle, data, len, 0);
if (completition < 0) return(completition);
xstrcpy(unname, build_unix_name(&nwpath, 0));
if (s_stat(unname, &stbuff, NULL) ||
(!modus && !S_ISDIR(stbuff.st_mode)) ) {
completition = -0x9c;
} else
completition=tru_get_eff_rights(nwpath.volume, unname, &stbuff);
return(completition);
}
int nw_creat_open_file(int dir_handle, uint8 *data, int len,
NW_FILE_INFO *info, int attrib, int access,
int creatmode, int task)
/*
* creatmode: 0 = open | 1 = creat | 2 = creatnew & 4 == save handle
* attrib ??
* access: 0x1=read, 0x2=write
*/
{
NW_PATH nwpath;
struct stat stbuff;
int completition = conn_get_kpl_path(&nwpath, &stbuff, dir_handle, data, len, 0);
if (completition > -1) {
char unixname[300];
xstrcpy(unixname, build_unix_name(&nwpath, 0));
completition=file_creat_open(nwpath.volume, (uint8*)unixname,
&stbuff, attrib, access, creatmode, task);
if (completition > -1)
get_file_attrib(info, unixname, &stbuff, &nwpath);
}
return(completition);
}
static int s_nw_scan_dir_info(int dir_handle,
uint8 *data, int len, uint8 *subnr,
uint8 *subname, uint8 *subdatetime,
uint8 *owner, uint8 *wild)
{
int volume;
int searchsequence;
int dir_id;
int rights = nw_open_dir_handle(dir_handle, data, len,
&volume, &dir_id, &searchsequence);
if (rights > -1) {
DIR_HANDLE *dh = &(dir_handles[dir_id-1]);
struct stat stbuff;
uint16 dirsequence = GET_BE16(subnr);
uint16 aktsequence = 0;
uint8 dirname[256];
if (!dirsequence) dirsequence++;
if (dh->vol_options & VOL_OPTION_DOWNSHIFT) {
down_fn(wild);
} else {
up_fn(wild);
}
xstrcpy(dirname, (char*)wild);
XDPRINTF((5,0,"SCAN_DIR: rights = 0x%x, subnr = %d",
(int)rights, (int)GET_BE16(subnr)));
if (*dirname) {
char unixname[300];
while ( get_dh_entry( dh,
dirname,
sizeof(dirname),
&searchsequence,
0x10,
unixname,
sizeof(unixname),
&stbuff) ) {
XDPRINTF((5,0,"SCAN_DIR: von %s, found %s:", dh->unixname, dirname));
if (++aktsequence == dirsequence) { /* actual found */
uint8 dosalias[14];
char parent[300];
char *slash;
uint8 *leaf = dirname;
U16_TO_BE16(aktsequence, subnr);
/*
* Do not trust dirname here. Some old DOS scan paths carry the
* raw 8 byte directory name only, which collapses colliding long
* directories to the same display name (LONG_DIR/LONG_DIR).
* Rebuild the final directory info name from the real full unixname
* returned by get_dh_entry(), where the long on-disk leaf is still
* available.
*/
if (unixname[0]) {
strmaxcpy(parent, unixname, sizeof(parent)-1);
slash = strrchr(parent, '/');
if (slash) {
leaf = (uint8*)(slash+1);
*slash = '\0';
if (!*parent) strcpy(parent, "/");
build_dos_83_alias(dh->vol_options, (uint8*)parent,
leaf, stbuff.st_ino,
dosalias, sizeof(dosalias));
} else {
build_dos_83_alias(dh->vol_options, NULL,
leaf, stbuff.st_ino,
dosalias, sizeof(dosalias));
}
} else {
build_dos_83_alias(dh->vol_options, (uint8*)dh->unixname,
dirname, stbuff.st_ino,
dosalias, sizeof(dosalias));
}
up_fn(dosalias);
strncpy((char*)subname, (char*)dosalias, 16);
U32_TO_BE32(get_file_owner(&stbuff), owner);
un_date_2_nw(stbuff.st_mtime, subdatetime, 1);
un_time_2_nw(stbuff.st_mtime, subdatetime+2, 1);
return(tru_get_inherited_mask(volume, unixname, &stbuff));
}
xstrcpy(dirname, (char*)wild);
} /* while */
} else {
*(dh->kpath) = '.';
*(dh->kpath+1) = '\0';
if (!s_stat(dh->unixname, &stbuff, NULL)) {
U16_TO_BE16(1, subnr);
memset(subname, 0, 16);
U32_TO_BE32(get_file_owner(&stbuff), owner);
un_date_2_nw(stbuff.st_mtime, subdatetime, 1);
un_time_2_nw(stbuff.st_mtime, subdatetime+2, 1);
return(tru_get_inherited_mask(volume, dh->unixname, &stbuff));
}
}
/* return(-0x9c); NO MORE INFO */
return(-0xff);
}
return(rights);
}
int nw_scan_dir_info(int dir_handle, uint8 *data, int len, uint8 *subnr,
uint8 *subname, uint8 *subdatetime, uint8 *owner)
{
int k = len;
uint8 *p = data+len;
uint8 dirname[256];
while (k) {
uint8 c = *--p;
if (c == '/' || c == '\\' || c == ':') {
p++;
break;
}
--k;
}
if (len && k < len) {
strmaxcpy(dirname, p, len-k);
len = k;
} else dirname[0] = '\0';
XDPRINTF((7, 0, "nw_scan_dir_info, dirname=`%s`, len=%d, k=%d",
dirname, len , k));
return(s_nw_scan_dir_info(dir_handle, data, len, subnr,
subname, subdatetime, owner, dirname));
}
static void build_dos_attr_name(int volume, uint8 *path, char *unixname,
struct stat *stb, uint8 *out, int out_len)
{
char parent[300];
char *slash;
uint8 *leaf = path;
int options = get_volume_options(volume);
if (!out || out_len < 2) return;
*out = '\0';
if (stb && volume == last_dos_alias_volume
&& stb->st_ino == last_dos_alias_inode
&& last_dos_alias_parent[0] && last_dos_alias_real[0]) {
if (last_dos_alias_alias[0]) {
strmaxcpy(out, last_dos_alias_alias, out_len-1);
up_fn(out);
} else {
build_dos_83_alias(options, last_dos_alias_parent,
last_dos_alias_real, stb->st_ino, out, out_len);
}
return;
}
/*
* Prefer the real unixname when it is available. Some namespace/DOS scan
* paths pass an already synthesized 8.3 name in `path`; if we return that
* blindly, colliding long directories can both be displayed as LONG_DIR.
*/
if (unixname && *unixname) {
strmaxcpy(parent, unixname, sizeof(parent)-1);
slash = strrchr(parent, '/');
if (slash) {
*slash = '\0';
if (*(slash+1)) leaf = (uint8*)(slash+1);
if (!*parent) strcpy(parent, "/");
build_dos_83_alias(options, (uint8*)parent,
leaf, stb ? stb->st_ino : 0, out, out_len);
return;
}
}
/* Fallback: keep a previously synthesized DOS alias only when there is no
* reliable real unixname to rebuild from. */
if (path && *path && dos_is_83_name(path, options)) {
strmaxcpy(out, path, out_len-1);
up_fn(out);
return;
}
build_dos_83_alias(options, NULL,
leaf, stb ? stb->st_ino : 0, out, out_len);
}
void get_dos_file_attrib(NW_DOS_FILE_INFO *f,
struct stat *stb,
int volume,
uint8 *path,
char *unixname)
{
uint8 spath[14];
uint32 nw_owner=get_file_owner(stb);
build_dos_attr_name(volume, path, unixname, stb, spath, sizeof(spath));
XDPRINTF((99,0,"DOSFILEATTR path='%s' unix='%s' alias='%s' inode=%ld", path ? (char*)path : "", unixname ? unixname : "", spath, stb ? (long)stb->st_ino : 0L));
f->namlen=min(strlen((char*)spath), 12);
strncpy((char*)f->name, (char*)spath, f->namlen);
U32_TO_32(get_nw_attrib_dword(volume, unixname, stb), f->attributes);
U16_TO_16(tru_get_inherited_mask(volume, unixname, stb),
f->inherited_rights_mask);
{
uint16 create_date = 0;
uint16 create_time = 0;
uint32 creator_id = 0;
uint8 meta_flags = 0;
mars_nwe_get_file_info(unixname, &create_date, &create_time,
&creator_id, &meta_flags);
if (meta_flags & MARS_NWE_FILEINFO_HAS_CREATE_DATE) {
U16_TO_16(create_date, f->created.date);
} else {
un_date_2_nw(stb->st_mtime, f->created.date, 0);
}
if (meta_flags & MARS_NWE_FILEINFO_HAS_CREATE_TIME) {
U16_TO_16(create_time, f->created.time);
} else {
un_time_2_nw(stb->st_mtime, f->created.time, 0);
}
if (meta_flags & MARS_NWE_FILEINFO_HAS_CREATOR) {
U32_TO_BE32(creator_id, f->created.id);
} else {
U32_TO_BE32(nw_owner, f->created.id);
}
}
{
uint16 archive_date = 0;
uint16 archive_time = 0;
uint32 archiver_id = 0;
mars_nwe_get_archive_info(unixname, &archive_date, &archive_time,
&archiver_id, NULL);
U16_TO_16(archive_date, f->archived.date);
U16_TO_16(archive_time, f->archived.time);
U32_TO_BE32(archiver_id, f->archived.id);
}
un_date_2_nw(stb->st_mtime, f->updated.date, 0);
un_time_2_nw(stb->st_mtime, f->updated.time, 0);
{
uint32 modifier_id = 0;
uint8 mod_flags = 0;
mars_nwe_get_file_modifier_info(unixname, &modifier_id, &mod_flags);
if (mod_flags & MARS_NWE_FILEINFO_HAS_MODIFIER) {
U32_TO_BE32(modifier_id, f->updated.id);
} else {
U32_TO_BE32(nw_owner, f->updated.id);
}
}
un_date_2_nw(stb->st_atime, f->last_access_date, 0);
U32_TO_32(stb->st_size, f->size);
}
void get_dos_dir_attrib(NW_DOS_DIR_INFO *f,
struct stat *stb,
int volume,
uint8 *path,
char *unixname)
{
uint8 spath[14];
build_dos_attr_name(volume, path, unixname, stb, spath, sizeof(spath));
XDPRINTF((99,0,"DOSDIRATTR path='%s' unix='%s' alias='%s' inode=%ld", path ? (char*)path : "", unixname ? unixname : "", spath, stb ? (long)stb->st_ino : 0L));
f->namlen=min(strlen((char*)spath), 12);
strncpy((char*)f->name, (char*)spath, f->namlen);
U32_TO_32(get_nw_attrib_dword(volume, unixname, stb),
f->attributes);
U16_TO_16(tru_get_inherited_mask(volume, unixname, stb),
f->inherited_rights_mask);
{
uint16 create_date = 0;
uint16 create_time = 0;
uint32 creator_id = 0;
uint8 meta_flags = 0;
mars_nwe_get_file_info(unixname, &create_date, &create_time,
&creator_id, &meta_flags);
if (meta_flags & MARS_NWE_FILEINFO_HAS_CREATE_DATE) {
U16_TO_16(create_date, f->created.date);
} else {
un_date_2_nw(stb->st_mtime, f->created.date, 0);
}
if (meta_flags & MARS_NWE_FILEINFO_HAS_CREATE_TIME) {
U16_TO_16(create_time, f->created.time);
} else {
un_time_2_nw(stb->st_mtime, f->created.time, 0);
}
if (meta_flags & MARS_NWE_FILEINFO_HAS_CREATOR) {
U32_TO_BE32(creator_id, f->created.id);
} else {
U32_TO_BE32(get_file_owner(stb), f->created.id);
}
}
{
uint16 archive_date = 0;
uint16 archive_time = 0;
uint32 archiver_id = 0;
mars_nwe_get_archive_info(unixname, &archive_date, &archive_time,
&archiver_id, NULL);
U16_TO_16(archive_date, f->archived.date);
U16_TO_16(archive_time, f->archived.time);
U32_TO_BE32(archiver_id, f->archived.id);
}
un_date_2_nw(stb->st_mtime, f->modify_date, 0);
un_time_2_nw(stb->st_mtime, f->modify_time, 0);
{
uint32 quota = MAX_U32;
uint32 inuse = 0;
if (!nw_get_vol_restrictions((uint8)volume, act_uid, &quota, &inuse)) {
U32_TO_BE32(quota, f->max_space);
} else {
U32_TO_BE32(MAX_U32, f->max_space);
}
}
}
int nw_scan_a_directory(uint8 *rdata,
int dirhandle,
uint8 *data,
int len,
int searchattrib,
uint32 searchbeg) /* 32 bit */
{
NW_PATH nwpath;
struct stat stbuff;
int completition = conn_get_kpl_path(&nwpath, &stbuff, dirhandle, data, len, 0);
XDPRINTF((5,0,"nw_scan_a_directory path:%s:, fn:%s:, completition:0x%x",
nwpath.path, nwpath.fn, completition));
if (completition > -1) {
int searchsequence = (searchbeg == MAX_U32) ? MAX_U16 : searchbeg;
completition=get_dir_entry(&nwpath,
&searchsequence,
searchattrib,
&stbuff);
if (!completition) {
char unixname[300];
NW_SCAN_DIR_INFO *scif = (NW_SCAN_DIR_INFO*)rdata;
xstrcpy(unixname, build_unix_name(&nwpath, 0));
memset(rdata, 0, sizeof(NW_SCAN_DIR_INFO));
U32_TO_BE32((uint32)searchsequence, scif->searchsequence);
XDPRINTF((5,0, "nw_scan_a_directory = %s, uid=%d, gid=%d",
conn_get_nwpath_name(&nwpath),
stbuff.st_uid, stbuff.st_gid));
if ( S_ISDIR(stbuff.st_mode)) {
get_dos_dir_attrib(&(scif->u.d), &stbuff,
nwpath.volume, nwpath.fn, unixname);
} else {
get_dos_file_attrib(&(scif->u.f), &stbuff,
nwpath.volume, nwpath.fn, unixname);
}
return(sizeof(NW_SCAN_DIR_INFO));
}
}
return(completition); /* wrong path */
}
int nw_scan_a_root_dir(uint8 *rdata,
int dirhandle)
{
NW_PATH nwpath;
struct stat stbuff;
uint8 data[2];
int completition = conn_get_kpl_path(&nwpath, &stbuff, dirhandle, data, 0, 1);
XDPRINTF((5,0,"nw_scan_a_root_directory_2 path:%s:, fn:%s:, completition:0x%x",
nwpath.path, nwpath.fn, completition));
if (completition > -1) {
char unixname[300];
xstrcpy(unixname, build_unix_name(&nwpath, 2));
if (!s_stat(unixname, &stbuff, NULL)) {
NW_DOS_DIR_INFO *d=(NW_DOS_DIR_INFO*)rdata;
memset(rdata, 0, sizeof(NW_DOS_DIR_INFO));
get_dos_dir_attrib(d, &stbuff, nwpath.volume, nwpath.fn, unixname);
return(sizeof(NW_DOS_DIR_INFO));
} else return(-0xff); /* not found */
} else return(completition); /* wrong path */
}
int nw_set_a_directory_entry(int dirhandle,
uint8 *data,
int len,
int searchattrib,
uint32 searchbeg,
NW_SET_DIR_INFO *f)
{
NW_PATH nwpath;
struct stat stbuff;
int completition = conn_get_kpl_path(&nwpath, &stbuff, dirhandle, data, len, 0);
XDPRINTF((5,0,"nw_set_a_directory_entry path:%s:, fn:%s:, completition:0x%x",
nwpath.path, nwpath.fn, completition));
if (completition > -1) {
int searchsequence = MAX_U16;
/* (searchbeg == MAX_U32) ? MAX_U16 : searchbeg; */
completition=get_dir_entry(&nwpath,
&searchsequence,
searchattrib,
&stbuff);
if (!completition) {
char unixname[300];
uint32 change_mask=GET_32(f->change_bits);
xstrcpy(unixname,build_unix_name(&nwpath, 0));
log_ncp22_25_change_bits(change_mask);
if (change_mask & DM_ATTRIBUTES) {
completition=set_nw_attrib_dword(nwpath.volume, unixname, &stbuff,
GET_32(f->u.f.attributes));
if (!completition)
s_stat(unixname, &stbuff, NULL);
}
if (!completition) {
int result=set_ncp22_25_times(nwpath.volume, unixname, &stbuff,
f, change_mask, S_ISDIR(stbuff.st_mode));
if (result)
completition=result;
else if (change_mask & DM_NCP22_25_TIME_BITS)
s_stat(unixname, &stbuff, NULL);
}
if (!completition) {
completition=set_ncp22_25_archive_info(unixname, f, change_mask,
S_ISDIR(stbuff.st_mode));
}
if (!completition) {
completition=set_ncp22_25_file_info(unixname, f, change_mask,
S_ISDIR(stbuff.st_mode));
}
if (!completition) {
completition=set_ncp22_25_maximum_space(nwpath.volume, unixname,
&stbuff, f, change_mask, S_ISDIR(stbuff.st_mode));
}
if (S_ISDIR(stbuff.st_mode)) {
if (change_mask & DM_INHERITED_RIGHTS_MASK) {
int result=tru_set_inherited_mask(nwpath.volume, unixname,
&stbuff, GET_16(f->u.d.inherited_rights_mask));
if (result)
completition=result;
}
} else {
if (change_mask & DM_INHERITED_RIGHTS_MASK) {
int result=tru_set_inherited_mask(nwpath.volume, unixname,
&stbuff, GET_16(f->u.f.inherited_rights_mask));
if (result)
completition=result;
}
}
}
}
return(completition);
}
static int my_match(uint8 *s, uint8 *p)
{
int len=0;
int dot=0;
for (; *s && *p; s++,p++) {
if (len == 12) return(0);
if (*s == '.') {
if (dot) return(0);
dot++;
} else if (dot) {
if (dot++ > 3) return(0);
} else if (len == 8) return(0);
if (!ufn_imatch(*s, *p))
return(0);
++len;
}
return( ((!*s) && (*p=='/' || *p == '\0')) ? len : 0);
}
static int get_match(uint8 *unixname, uint8 *p)
{
DIR *d;
uint8 *pp;
#if 0
uint8 *p1;
int inode=0;
#endif
if (!p || !*p) return(1);
*p = '\0';
pp=p+1;
while (*pp == '/') ++pp;
#if 0
p1=strchr(pp, '/');
if (!p1) p1=pp+strlen(pp);
if (p1 > pp+4 && *(p1-4) == '.'
&& *(p1-3) == '_'
&& *(p1-2) == '_'
&& *(p1-1) == '_' ) {
*(p1-4) = '\0';
inode=atoi(pp);
*(p1-4) = '.';
}
#endif
if (seteuid(0)) {}
d=opendir(unixname);
(void)reseteuid();
if (NULL != d) {
struct dirent *dirbuff;
XDPRINTF((10, 0, "opendir OK unixname='%s' pp='%s'", unixname, pp));
*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 (
#if 0
(dirbuff->d_ino ==inode) ||
#endif
0 != (len=my_match(dirbuff->d_name, pp))) {
memcpy(pp, dirbuff->d_name, len);
XDPRINTF((10, 0, "get match, match OK"));
closedir(d);
return(get_match(unixname, pp+len));
}
}
}
closedir(d);
} else {
XDPRINTF((3, 0, "DOS get_match opendir failed unixname='%s'", unixname));
*p='/';
}
return(0);
}
/* DOS name mangling is provided by namedos.c. */
int nw_add_trustee(int dir_handle, uint8 *data, int len,
uint32 id, int trustee, int extended)
/* extended 0=add trustee to dir, 1= add ext trustee to dirs and files */
{
char unname[256];
struct stat stbuff;
NW_PATH nwpath;
int result = conn_get_kpl_path(&nwpath, &stbuff, dir_handle, data, len, 0);
if (result < 0) return(result);
xstrcpy(unname, build_unix_name(&nwpath, 0));
if (s_stat(unname, &stbuff, NULL) ||
(!extended && !S_ISDIR(stbuff.st_mode)) ) {
result = -0x9c;
} else {
NW_OIC nwoic;
nwoic.id = id;
nwoic.trustee = trustee;
result=tru_add_trustee_set(nwpath.volume, unname,
&stbuff,
1, &nwoic);
}
return(result);
}
int nw_del_trustee(int dir_handle, uint8 *data, int len,
uint32 id, int extended)
/* extended 0=del trustee from dir, 1= del ext trustee from dirs and files */
{
char unname[256];
struct stat stbuff;
NW_PATH nwpath;
int result = conn_get_kpl_path(&nwpath, &stbuff, dir_handle, data, len, 0);
if (result < 0) return(result);
xstrcpy(unname, build_unix_name(&nwpath, 0));
if (s_stat(unname, &stbuff, NULL) ||
(!extended && !S_ISDIR(stbuff.st_mode)) ) {
result = -0x9c;
} else {
result=tru_del_trustee(nwpath.volume, unname, &stbuff, id);
}
return(result);
}
int nw_set_dir_info(int dir_handle, uint8 *data, int len,
uint32 owner_id, int max_rights,
uint8 *creationdate, uint8 *creationtime)
{
char unname[256];
struct stat stbuff;
NW_PATH nwpath;
int result = conn_get_kpl_path(&nwpath, &stbuff, dir_handle, data, len,0);
if (result < 0) return(result);
xstrcpy(unname, build_unix_name(&nwpath, 0));
if (s_stat(unname, &stbuff, NULL) || !S_ISDIR(stbuff.st_mode)) {
result = -0x9c;
} else {
result=nw_utime_node(nwpath.volume, unname, &stbuff,
nw_2_un_time(creationdate, creationtime));
if (!result)
result=tru_set_inherited_mask(nwpath.volume, unname,
&stbuff, max_rights);
}
return(result);
}
int nw_modify_max_right_mask(int dir_handle, uint8 *data, int len,
int grant_mask, int revoke_mask)
{
char unname[256];
struct stat stbuff;
NW_PATH nwpath;
int old_mask;
int new_mask;
int result = conn_get_kpl_path(&nwpath, &stbuff, dir_handle, data, len, 0);
if (result < 0) return(result);
xstrcpy(unname, build_unix_name(&nwpath, 0));
if (s_stat(unname, &stbuff, NULL) || !S_ISDIR(stbuff.st_mode))
return(-0x9c);
old_mask = tru_get_inherited_mask(nwpath.volume, unname, &stbuff);
new_mask = (old_mask | (grant_mask & 0xff)) & (~revoke_mask & 0xff);
result = tru_set_inherited_mask(nwpath.volume, unname, &stbuff, new_mask);
if (!result) {
int verify_mask = tru_get_inherited_mask(nwpath.volume, unname, &stbuff);
XDPRINTF((1, 0, "NCP22/4 Modify Max Right Mask: path=`%s`, old=0x%02x, grant=0x%02x, revoke=0x%02x, new=0x%02x, verify=0x%02x",
unname,
old_mask & 0xff,
grant_mask & 0xff,
revoke_mask & 0xff,
new_mask & 0xff,
verify_mask & 0xff));
}
return result;
}
int nw_scan_user_trustee(int volume, int *sequence, uint32 id,
int *access_mask, uint8 *path)
{
uint8 volname[100];
int result = nw_get_volume_name(volume, volname, sizeof(volname));
if (result > 0) {
if (*sequence==-1 || *sequence==0xffff)
*sequence=0;
result=get_volume_user_trustee(volume, id, 0, sequence,
access_mask, path);
}
return(result);
}
int nw_scan_for_trustee( int dir_handle,
int sequence,
uint8 *path,
int len,
int max_entries,
uint32 *ids,
int *trustees,
int extended)
{
char unname[256];
struct stat stbuff;
NW_PATH nwpath;
int result = conn_get_kpl_path(&nwpath, &stbuff, dir_handle, path, len,
(extended) ? 0 : 1);
if (result < 0) return(result);
xstrcpy(unname, build_unix_name(&nwpath, 0));
if (s_stat(unname, &stbuff, NULL) ||
(!extended && !S_ISDIR(stbuff.st_mode)) ) {
result = -0x9c;
} else {
result=tru_get_trustee_set(nwpath.volume, unname,
&stbuff,
sequence,
max_entries, ids, trustees);
}
return(result);
}
/* quick and dirty hack for 0.99.pl18, 25-Sep-99 */
int nw_log_file(int lock_flag,
int timeout,
int dir_handle,
int len,
char *data)
/*
* lock_flag
* -1 = remove lock
* -2 = remove lock + log
* 0 = log
* 1 = lock exclusive
* 3 = shared lock
*/
{
NW_PATH nwpath;
struct stat stbuff;
int completition = conn_get_kpl_path(&nwpath, &stbuff, dir_handle, data, len, 0);
if (completition > -1) {
char unixname[300];
xstrcpy(unixname, build_unix_name(&nwpath, 0));
if (seteuid(0)) {}
completition = stat(unixname, &stbuff);
(void)reseteuid();
if (!completition) {
if (lock_flag < 0) { /* remove lock */
if (lock_flag != -1)
completition =
share_set_file_add_rm(lock_flag, stbuff.st_dev, stbuff.st_ino);
if (!completition)
completition = share_file(stbuff.st_dev, stbuff.st_ino,
0x300, 0) ? -0xff : 0;
} else if (lock_flag == 0 || lock_flag == 1 || lock_flag == 3) {
completition =
share_set_file_add_rm(lock_flag, stbuff.st_dev, stbuff.st_ino);
if ((!completition) && lock_flag)
/* add lock */
completition = share_file(stbuff.st_dev, stbuff.st_ino,
lock_flag << 8, 1) ? -0xfe : 0;
} else
completition = -0xfb;
} else
completition = -0xff; /* not exist, errorcode TODO ! */
}
return(completition);
}