diff --git a/include/connect.h b/include/connect.h index b8745af..a7e6aa8 100644 --- a/include/connect.h +++ b/include/connect.h @@ -218,6 +218,9 @@ extern int conn_get_kpl_unxname(char *unixname, int dirhandle, uint8 *data, int len); +extern int conn_map_path_to_dir_entry(int dirhandle, uint8 *data, int len, + uint8 *volume, uint8 *dirnum); + extern void set_default_guid(void); extern void set_guid(int gid, int uid); extern void reset_guid(void); diff --git a/include/namspace.h b/include/namspace.h index ab494ae..7da9f10 100644 --- a/include/namspace.h +++ b/include/namspace.h @@ -111,6 +111,9 @@ extern int handle_func_0x56(uint8 *p, uint8 *responsedata, int task); extern int fill_namespace_buffer(int volume, uint8 *rdata); extern int get_namespace_dir_entry(int volume, uint32 basehandle, int namspace, uint8 *rdata); +extern int map_directory_number_to_path(int volume, uint32 dirnum, + int namspace, uint8 *rdata, + int size_rdata); extern void exit_name_space_module(void); extern void init_name_space_module(int max_baseh, int max_searchh); diff --git a/src/connect.c b/src/connect.c index f5357cb..b6d3410 100644 --- a/src/connect.c +++ b/src/connect.c @@ -2331,6 +2331,45 @@ int nw_set_dir_handle(int targetdir, int dir_handle, 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); + + if (!S_ISDIR(stbuff.st_mode)) return(-0x9c); + + { + 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; diff --git a/src/namspace.c b/src/namspace.c index f58725f..0659f81 100644 --- a/src/namspace.c +++ b/src/namspace.c @@ -2908,6 +2908,63 @@ int fill_namespace_buffer(int volume, uint8 *rdata) } else return(-0x98); } + +int map_directory_number_to_path(int volume, uint32 dirnum, + int namspace, uint8 *rdata, int size_rdata) +/* + * NCP23/F3 Map Directory Number to Path. + * Reply is a sequence of length-preceded path components, without volume. + */ +{ + int result = find_base_entry(volume, dirnum); + + XDPRINTF((5,0, + "NCP23/F3 helper: vol=%d dirnum=0x%lx namespace=%d", + volume, (unsigned long)dirnum, namspace)); + + if (result > -1) { + DIR_BASE_ENTRY *e = dir_base[result]; + char path[512]; + char *pp; + uint8 *out = rdata; + int left = size_rdata; + + if (!rdata || size_rdata < 1) return(-0xff); + + strmaxcpy((uint8*)path, e->nwpath.path, sizeof(path)-1); + if (namspace == NAME_DOS) up_fn((uint8*)path); + pp = path; + while (*pp == '/' || *pp == '\\') pp++; + + if (!*pp) + return(0); + + while (*pp) { + char *next = pp; + int len; + + while (*next && *next != '/' && *next != '\\') next++; + len = next - pp; + if (len > 255 || left < len + 1) return(-0xff); + + *out++ = (uint8)len; + memcpy(out, pp, len); + out += len; + left -= len + 1; + + while (*next == '/' || *next == '\\') next++; + pp = next; + } + + XDPRINTF((5,0, + "NCP23/F3 helper: path=`%s` reply_len=%d", + e->nwpath.path, (int)(out - rdata))); + return((int)(out - rdata)); + } + + return(result); +} + int get_namespace_dir_entry(int volume, uint32 basehandle, int namspace, uint8 *rdata) { diff --git a/src/nwconn.c b/src/nwconn.c index 5c8950a..4d8cbcf 100644 --- a/src/nwconn.c +++ b/src/nwconn.c @@ -1559,19 +1559,57 @@ static int handle_ncp_serv(void) } break; - case 0xf3: { /* Map Direktory Number TO PATH */ + case 0xf3: { /* Map Directory Number TO PATH */ int payload_len = requestlen - 3; + int result; if (payload_len < 0) payload_len = 0; ncp23_debug_dump("NCP23/F3 Map Directory Number TO PATH", rdata, payload_len); - completition = 0xff; + + /* + * Request: volume byte, directory number dword LO-HI, namespace byte. + * Reply: length-preceded path components, no volume component. + */ + if (payload_len >= 6) { + int volume = (int)rdata[0]; + uint32 dirnum = GET_32(rdata+1); + int namspace = (int)rdata[5]; + + result = map_directory_number_to_path(volume, dirnum, namspace, + responsedata, + sizeof(IPX_DATA) - sizeof(NCPRESPONSE)); + if (result > -1) data_len = result; + else completition = (uint8)(-result); + } else { + completition = 0x9c; + } } break; case 0xf4: { /* Map PATH TO Dir Entry */ int payload_len = requestlen - 3; + int result; if (payload_len < 0) payload_len = 0; ncp23_debug_dump("NCP23/F4 Map PATH TO Dir Entry", rdata, payload_len); - completition = 0xff; + + /* + * Request: dir handle byte, path length byte, path bytes. + * Reply: volume byte, directory number dword LO-HI. + */ + if (payload_len >= 2 && payload_len >= 2 + (int)rdata[1]) { + struct XDATA { + uint8 volume; + uint8 dirnum[4]; + } *xdata = (struct XDATA*)responsedata; + + result = conn_map_path_to_dir_entry((int)rdata[0], + rdata+2, (int)rdata[1], + &(xdata->volume), + xdata->dirnum); + if (result) completition = (uint8)(-result); + else data_len = sizeof(struct XDATA); + } else { + completition = 0x9c; + } } break;