This commit is contained in:
119
src/nwvolume.c
119
src/nwvolume.c
@@ -64,6 +64,88 @@ char *path_trustees=NULL;
|
||||
|
||||
static int max_nw_vols=MAX_NW_VOLS;
|
||||
|
||||
|
||||
/*
|
||||
* Modern Linux filesystems can use inode numbers larger than 28 bits.
|
||||
* The classic MARS_NWE handle format uses the upper 4 bits for the
|
||||
* dev/namespace map index and the lower 28 bits for the inode. That
|
||||
* breaks for volumes using multiple namespaces, for example DOS + OS2,
|
||||
* when VOL_OPTION_ONE_DEV ('o') is not enabled.
|
||||
*
|
||||
* Keep the external 32-bit NetWare handle format, but map real Unix inode
|
||||
* numbers to small pseudo inode numbers per volume/map entry. This allows
|
||||
* OS2/NFS namespaces on large-inode filesystems without requiring the
|
||||
* small 'o' ONE_DEV option.
|
||||
*
|
||||
* VOL_OPTION_ONE_DEV keeps its old direct 32-bit inode behaviour.
|
||||
*/
|
||||
typedef struct inode_handle_map_s {
|
||||
int volume;
|
||||
int map_entry;
|
||||
ino_t inode;
|
||||
uint32 handle_inode;
|
||||
struct inode_handle_map_s *next;
|
||||
} INODE_HANDLE_MAP;
|
||||
|
||||
static INODE_HANDLE_MAP *inode_handle_maps = NULL;
|
||||
static uint32 next_handle_inode = 1;
|
||||
|
||||
static void free_inode_handle_maps(void)
|
||||
{
|
||||
INODE_HANDLE_MAP *m = inode_handle_maps;
|
||||
while (m) {
|
||||
INODE_HANDLE_MAP *n = m->next;
|
||||
xfree(m);
|
||||
m = n;
|
||||
}
|
||||
inode_handle_maps = NULL;
|
||||
next_handle_inode = 1;
|
||||
}
|
||||
|
||||
static uint32 inode_to_handle_inode(int volume, int map_entry, ino_t inode)
|
||||
{
|
||||
INODE_HANDLE_MAP *m;
|
||||
|
||||
for (m = inode_handle_maps; m; m = m->next) {
|
||||
if (m->volume == volume && m->map_entry == map_entry && m->inode == inode)
|
||||
return(m->handle_inode);
|
||||
}
|
||||
|
||||
if (next_handle_inode > 0x0fffffff) {
|
||||
XDPRINTF((1,0,
|
||||
"No free pseudo inode handle for vol=%d map=%d inode=%ld",
|
||||
volume, map_entry, (long)inode));
|
||||
return(0);
|
||||
}
|
||||
|
||||
m = (INODE_HANDLE_MAP*)xcmalloc(sizeof(INODE_HANDLE_MAP));
|
||||
m->volume = volume;
|
||||
m->map_entry = map_entry;
|
||||
m->inode = inode;
|
||||
m->handle_inode = next_handle_inode++;
|
||||
m->next = inode_handle_maps;
|
||||
inode_handle_maps = m;
|
||||
|
||||
XDPRINTF((99,0,
|
||||
"Pseudo inode map vol=%d map=%d inode=%ld to pseudo=0x%x",
|
||||
volume, map_entry, (long)inode, m->handle_inode));
|
||||
return(m->handle_inode);
|
||||
}
|
||||
|
||||
static ino_t handle_inode_to_inode(int volume, int map_entry, uint32 handle_inode)
|
||||
{
|
||||
INODE_HANDLE_MAP *m;
|
||||
|
||||
for (m = inode_handle_maps; m; m = m->next) {
|
||||
if (m->volume == volume && m->map_entry == map_entry
|
||||
&& m->handle_inode == handle_inode)
|
||||
return(m->inode);
|
||||
}
|
||||
|
||||
/* Compatibility fallback for old/direct handles. */
|
||||
return((ino_t)handle_inode);
|
||||
}
|
||||
|
||||
static void free_vol_trustee(NW_VOL *vol)
|
||||
{
|
||||
if (vol) {
|
||||
@@ -143,6 +225,7 @@ void nw_init_volumes(FILE *f)
|
||||
}
|
||||
rewind(f);
|
||||
used_nw_volumes = 0;
|
||||
free_inode_handle_maps();
|
||||
loaded_namespaces = 0;
|
||||
new_str(path_vol_inodes_cache, "/var/spool/nwserv/.volcache");
|
||||
new_str(path_attributes, "/var/nwserv/attrib");
|
||||
@@ -430,20 +513,31 @@ uint32 nw_vol_inode_to_handle(int volume, ino_t inode,
|
||||
{
|
||||
if (volume > -1 && volume < used_nw_volumes) {
|
||||
NW_VOL *v= &(nw_volumes[volume]);
|
||||
if (inode > 0 && inode <= v->high_inode) {
|
||||
if (inode > 0) {
|
||||
int result = look_name_space_map(v, dnm, 1);
|
||||
if (result > -1) {
|
||||
uint32 handle = (v->options & VOL_OPTION_ONE_DEV)
|
||||
? (uint32)inode
|
||||
: (((uint32)result) << 28) | (uint32) inode;
|
||||
XDPRINTF((3,0, "Handle map inode=%d, dev=%d, namespace=%d to handle 0x%x",
|
||||
inode, dnm->dev, dnm->namespace, handle));
|
||||
uint32 handle;
|
||||
|
||||
if (v->options & VOL_OPTION_ONE_DEV) {
|
||||
if (inode > v->high_inode)
|
||||
goto cannot_map;
|
||||
handle = (uint32)inode;
|
||||
} else {
|
||||
uint32 handle_inode = inode_to_handle_inode(volume, result, inode);
|
||||
if (!handle_inode)
|
||||
goto cannot_map;
|
||||
handle = (((uint32)result) << 28) | handle_inode;
|
||||
}
|
||||
|
||||
XDPRINTF((3,0, "Handle map inode=%ld, dev=%d, namespace=%d to handle 0x%x",
|
||||
(long)inode, dnm->dev, dnm->namespace, handle));
|
||||
return(handle);
|
||||
}
|
||||
}
|
||||
}
|
||||
XDPRINTF((1,0, "Cannot map inode=%d, dev=%d, namespace=%d to vol=%d handle",
|
||||
inode, dnm->dev, dnm->namespace, volume));
|
||||
cannot_map:
|
||||
XDPRINTF((1,0, "Cannot map inode=%ld, dev=%d, namespace=%d to vol=%d handle",
|
||||
(long)inode, dnm->dev, dnm->namespace, volume));
|
||||
return(0L);
|
||||
}
|
||||
|
||||
@@ -457,13 +551,16 @@ ino_t nw_vol_handle_to_inode(int volume, uint32 handle,
|
||||
? 0
|
||||
: (int) ((handle >> 28) & 0xF);
|
||||
if (entry > -1 && entry < v->maps_count) {
|
||||
ino_t inode = (v->options & VOL_OPTION_ONE_DEV)
|
||||
? (ino_t)(handle & v->high_inode)
|
||||
: handle_inode_to_inode(volume, entry, handle & v->high_inode);
|
||||
if (dnm) memcpy(dnm, v->dev_namespace_maps[entry],
|
||||
sizeof(DEV_NAMESPACE_MAP));
|
||||
XDPRINTF((3, 0, "vol=%d, handle=0x%x to ino=%d, dev=%d, namespace=%d",
|
||||
volume, handle, (int)(handle & v->high_inode),
|
||||
XDPRINTF((3, 0, "vol=%d, handle=0x%x to ino=%ld, dev=%d, namespace=%d",
|
||||
volume, handle, (long)inode,
|
||||
v->dev_namespace_maps[entry]->dev,
|
||||
v->dev_namespace_maps[entry]->namespace));
|
||||
return((ino_t) (handle & v->high_inode));
|
||||
return(inode);
|
||||
}
|
||||
}
|
||||
XDPRINTF((1, 0, "Can't vol=%d, handle=0x%x to inode", volume, handle));
|
||||
|
||||
Reference in New Issue
Block a user