diff --git a/src/nwconn.c b/src/nwconn.c index d56d243..4597eb2 100644 --- a/src/nwconn.c +++ b/src/nwconn.c @@ -1143,6 +1143,88 @@ static int afp_create_directory(uint8 *afp_req, int afp_len, } + +static int afp_delete_object(uint8 *afp_req, int afp_len, + const char *call_name) +/* + * WebSDK / nwafp.h call 0x03 removes an AFP file or directory. Keep the + * delete operation on existing mars_nwe paths: resolve volume/base-id/path to + * the normal NetWare path string, then call nw_mk_rd_dir(..., mode=0) for + * directories or nw_delete_files() for files. This avoids a direct + * unlink(2)/rmdir(2) AFP side path while giving the smoke suite a server-side + * cleanup path for AFP-created objects. + */ +{ + uint8 volume_number; + uint32 base_entry_id; + int path_len; + uint8 delete_path[512]; + char unixname[PATH_MAX]; + int volume; + int result; + struct stat stbuff; + + if (afp_len < 7) { + XDPRINTF((2,0, "%s rejected: short request len=%d", + call_name, afp_len)); + return(-0x7e); + } + + volume_number = afp_req[1]; + base_entry_id = GET_BE32(afp_req + 2); + path_len = (int)afp_req[6]; + if (path_len < 0 || afp_len < 7 + path_len) { + XDPRINTF((2,0, "%s rejected: boundary check len=%d path_len=%d", + call_name, afp_len, path_len)); + return(-0x7e); + } + if (!path_len) { + XDPRINTF((2,0, "%s rejected: empty path vol=%d base=0x%08x", + call_name, (int)volume_number, base_entry_id)); + return(-0x9c); + } + + result = afp_build_base_relative_path((int)volume_number, base_entry_id, + afp_req + 7, path_len, + delete_path, sizeof(delete_path)); + if (result < 0) { + XDPRINTF((2,0, "%s path build failed: vol=%d base=0x%08x path='%s' result=-0x%x", + call_name, (int)volume_number, base_entry_id, + visable_data(afp_req + 7, path_len), -result)); + return(result); + } + + volume = conn_get_kpl_unxname(unixname, sizeof(unixname), 0, + delete_path, strlen((char *)delete_path)); + if (volume < 0) return(volume); + if (stat(unixname, &stbuff)) { + XDPRINTF((2,0, "%s stat failed: vol=%d base=0x%08x path='%s' mars_path='%s' unix='%s' errno=%d", + call_name, (int)volume_number, base_entry_id, + visable_data(afp_req + 7, path_len), delete_path, unixname, + errno)); + return(-0x9c); + } + + if (S_ISDIR(stbuff.st_mode)) { + result = nw_mk_rd_dir(0, delete_path, strlen((char *)delete_path), 0); + } else { + result = nw_delete_files(0, 0, delete_path, strlen((char *)delete_path)); + } + if (result < 0) { + XDPRINTF((2,0, "%s delete failed: vol=%d base=0x%08x path='%s' mars_path='%s' unix='%s' result=-0x%x", + call_name, (int)volume_number, base_entry_id, + visable_data(afp_req + 7, path_len), delete_path, unixname, + -result)); + return(result); + } + + XDPRINTF((3,0, "%s: request_vol=%d resolved_vol=%d base=0x%08x path='%s' directory=%d", + call_name, (int)volume_number, volume, base_entry_id, + visable_data(afp_req + 7, path_len), S_ISDIR(stbuff.st_mode) ? 1 : 0)); + return(0); +} + + static int afp_get_entry_id_from_path_name(uint8 *afp_req, int afp_len, uint8 *response) { @@ -4189,6 +4271,11 @@ static int handle_ncp_serv(void) afp_call_name(ufunc)); if (result > -1) data_len = result; else completition = (uint8)-result; + } else if (ufunc == 0x03) { + int result = afp_delete_object(afp_req, + afp_len, afp_call_name(ufunc)); + if (result > -1) data_len = result; + else completition = (uint8)-result; } else if (ufunc == 0x04) { int result = afp_get_entry_id_from_name(afp_req, afp_len, responsedata);