diff --git a/include/namspace.h b/include/namspace.h index cfa3eac..df98dff 100644 --- a/include/namspace.h +++ b/include/namspace.h @@ -111,6 +111,14 @@ extern int handle_func_0x57_salvage_scan(uint8 *p, int request_len, uint8 *responsedata, int task); extern int handle_func_0x57_salvage_recover(uint8 *p, int request_len, uint8 *responsedata, int task); +extern int handle_func_0x57_salvage_purge(uint8 *p, int request_len, + uint8 *responsedata, int task); +extern int handle_func_0x16_salvage_scan(uint8 *p, int request_len, + uint8 *responsedata, int task); +extern int handle_func_0x16_salvage_recover(uint8 *p, int request_len, + uint8 *responsedata, int task); +extern int handle_func_0x16_salvage_purge(uint8 *p, int request_len, + uint8 *responsedata, int task); extern int handle_func_0x56(uint8 *p, uint8 *responsedata, int task); extern int fill_namespace_buffer(int volume, uint8 *rdata); diff --git a/include/nwsalvage.h b/include/nwsalvage.h index f31b836..791198c 100644 --- a/include/nwsalvage.h +++ b/include/nwsalvage.h @@ -204,6 +204,7 @@ int nwsalvage_scan_directory(int volume, const char *relative_dir, int nwsalvage_recover_scan_result(int volume, const struct nwsalvage_scan_result *scan, const char *dest_unixname, int task); +int nwsalvage_purge_scan_result(const struct nwsalvage_scan_result *scan); /* * Capture a server-side delete before nw_unlink_node() would remove it. * Returns 0 when the file was moved to the recycle repository and metadata diff --git a/src/namspace.c b/src/namspace.c index 9268d9c..2588941 100644 --- a/src/namspace.c +++ b/src/namspace.c @@ -2852,6 +2852,238 @@ int handle_func_0x57_salvage_scan(uint8 *q, int request_len, } +static void nsp_salvage_datetime_lh(time_t t, uint8 *p) +{ + uint8 b[2]; + uint16 tmv; + uint16 dtv; + + un_time_2_nw(t, b, 0); + tmv = GET_16(b); + un_date_2_nw(t, b, 0); + dtv = GET_16(b); + U32_TO_32(((uint32)dtv << 16) | tmv, p); +} + +static int nsp_salvage_dbe_from_short_handle(int dir_handle, DIR_BASE_ENTRY **out) +{ + NW_HPATH nwp; + int result; + + if (!out) + return(-0x9c); + + memset(&nwp, 0, sizeof(nwp)); + nwp.base[0] = (uint8)dir_handle; + nwp.flag = 0; + nwp.components = 0; + + result = build_base(NAME_DOS, &nwp, nwp.pathes, 0, NULL, 0); + if (result < 0) + return(result); + + *out = dir_base[result]; + nwp_stat(&((*out)->nwpath), "nsp_salvage_dbe_from_short_handle"); + if (!S_ISDIR((*out)->nwpath.statb.st_mode)) + return(-0x9c); + return(result); +} + +static int nsp_salvage_scan_by_dbe(DIR_BASE_ENTRY *dbe, + unsigned long sequence, + struct nwsalvage_scan_result *scan) +{ + int result; + + if (!dbe || !scan) + return(-0x9c); + + memset(scan, 0, sizeof(*scan)); + result = nwsalvage_scan_directory(dbe->nwpath.volume, + (char *)dbe->nwpath.path, + dbe->basehandle, sequence, scan); + if (result < 0) + return(-0x98); + if (result == 0) + return(-0xff); + return(0); +} + +static int nsp_salvage_find_current_by_dbe(DIR_BASE_ENTRY *dbe, + unsigned long sequence, + struct nwsalvage_scan_result *scan) +{ + unsigned long previous_sequence; + int result; + + previous_sequence = sequence ? sequence - 1 : 0xffffffffUL; + result = nsp_salvage_scan_by_dbe(dbe, previous_sequence, scan); + if (result) + return(result); + if (scan->scan_sequence != sequence || + scan->scan_directory_base != dbe->basehandle) + return(-0xff); + return(0); +} + +static int nsp_salvage_build_old_info(const struct nwsalvage_scan_result *scan, + uint8 *p) +{ + const struct nwsalvage_metadata_entry *entry = &scan->metadata; + const char *name = entry->original_name[0] ? entry->original_name : ""; + int namelen = min((int)strlen(name), 12); + + memset(p, 0, 130); + U32_TO_32((uint32)scan->scan_sequence, p + 0); + U16_TO_16((uint16)scan->scan_directory_base, p + 4); + U32_TO_32((uint32)entry->attributes, p + 6); + p[10] = 0; + p[11] = 0; + p[12] = NAME_DOS; + p[13] = (uint8)namelen; + memcpy(p + 14, name, namelen); + nsp_salvage_datetime_lh((time_t)entry->mtime, p + 26); + U32_TO_BE32(0, p + 30); + nsp_salvage_datetime_lh((time_t)entry->mtime, p + 34); + U32_TO_BE32((uint32)entry->netware_archiver_id, p + 38); + nsp_salvage_datetime_lh((time_t)entry->mtime, p + 42); + U32_TO_BE32((uint32)entry->netware_modifier_id, p + 46); + U32_TO_BE32((uint32)entry->size, p + 50); + U16_TO_16((uint16)entry->inherited_rights_mask, p + 98); + un_date_2_nw((time_t)entry->atime, p + 100, 0); + nsp_salvage_datetime_lh((time_t)entry->deleted_at, p + 102); + nsp_salvage_datetime_lh((time_t)entry->deleted_at, p + 106); + U32_TO_BE32(nsp_salvage_deletor_id(entry->deleted_by), p + 110); + return(130); +} + +int handle_func_0x16_salvage_scan(uint8 *q, int request_len, + uint8 *responsedata, int task) +{ + int dir_handle; + uint32 sequence; + DIR_BASE_ENTRY *dbe = NULL; + struct nwsalvage_scan_result scan; + int result; + + (void)task; + + if (!q || request_len < 6 || q[0] != 0x1b) + return(-0xfb); + + dir_handle = (int)q[1]; + sequence = GET_32(q + 2); + + result = nsp_salvage_dbe_from_short_handle(dir_handle, &dbe); + if (result < 0) + return(result); + + result = nsp_salvage_scan_by_dbe(dbe, sequence, &scan); + if (result) + return(result); + + result = nsp_salvage_build_old_info(&scan, responsedata); + XDPRINTF((3, 0, + "INFO SALVAGE 22/27 DONE fn=0x16 sub=0x1b dh=0x%02x seq=0x%08lx next=0x%08lx name=\"%s\"", + dir_handle, (unsigned long)sequence, + (unsigned long)scan.scan_sequence, scan.metadata.original_name)); + return(result); +} + +int handle_func_0x16_salvage_recover(uint8 *q, int request_len, + uint8 *responsedata, int task) +{ + int dir_handle; + uint32 sequence; + int file_len; + int new_len; + DIR_BASE_ENTRY *dbe = NULL; + struct nwsalvage_scan_result scan; + char *dest_unixname; + int result; + + (void)responsedata; + + if (!q || request_len < 8 || q[0] != 0x1c) + return(-0xfb); + + dir_handle = (int)q[1]; + sequence = GET_BE32(q + 2); + file_len = (int)q[6]; + if (request_len < 8 + file_len) + return(-0xfb); + new_len = (int)q[7 + file_len]; + if (request_len < 8 + file_len + new_len) + return(-0xfb); + + result = nsp_salvage_dbe_from_short_handle(dir_handle, &dbe); + if (result < 0) + return(result); + + result = nsp_salvage_find_current_by_dbe(dbe, sequence, &scan); + if (result) + return(result); + + dest_unixname = alloc_nwpath2unix_extra(&(dbe->nwpath), 0, + scan.metadata.original_name); + if (!dest_unixname) + return(-0x96); + + result = nwsalvage_recover_scan_result(dbe->nwpath.volume, &scan, + dest_unixname, task); + xfree(dest_unixname); + if (result < 0) { + if (errno == EEXIST) + return(-0xfe); + return(-0x98); + } + if (result == 0) + return(-0xff); + + XDPRINTF((3, 0, + "INFO SALVAGE 22/28 DONE fn=0x16 sub=0x1c dh=0x%02x seq=0x%08lx name=\"%s\"", + dir_handle, (unsigned long)sequence, scan.metadata.original_name)); + return(0); +} + +int handle_func_0x16_salvage_purge(uint8 *q, int request_len, + uint8 *responsedata, int task) +{ + int dir_handle; + uint32 sequence; + DIR_BASE_ENTRY *dbe = NULL; + struct nwsalvage_scan_result scan; + int result; + + (void)responsedata; + (void)task; + + if (!q || request_len < 6 || q[0] != 0x1d) + return(-0xfb); + + dir_handle = (int)q[1]; + sequence = GET_BE32(q + 2); + + result = nsp_salvage_dbe_from_short_handle(dir_handle, &dbe); + if (result < 0) + return(result); + + result = nsp_salvage_find_current_by_dbe(dbe, sequence, &scan); + if (result) + return(result); + + result = nwsalvage_purge_scan_result(&scan); + if (result < 0) + return(-0x98); + if (result == 0) + return(-0xff); + + XDPRINTF((3, 0, + "INFO SALVAGE 22/29 DONE fn=0x16 sub=0x1d dh=0x%02x seq=0x%08lx name=\"%s\"", + dir_handle, (unsigned long)sequence, scan.metadata.original_name)); + return(0); +} + int handle_func_0x57_salvage_recover(uint8 *q, int request_len, uint8 *responsedata, int task) { @@ -2932,6 +3164,57 @@ int handle_func_0x57_salvage_recover(uint8 *q, int request_len, return(0); } +int handle_func_0x57_salvage_purge(uint8 *q, int request_len, + uint8 *responsedata, int task) +{ + int namespace; + uint32 scan_sequence; + uint32 volume; + uint32 directory_base; + DIR_BASE_ENTRY *dbe; + struct nwsalvage_scan_result scan; + int result; + + (void)responsedata; + (void)task; + + if (!q || request_len < 15 || q[0] != 0x12) + return(-0xfb); + + namespace = (int)q[1]; + scan_sequence = GET_32(q + 3); + volume = GET_32(q + 7); + directory_base = GET_32(q + 11); + + if (volume >= (uint32)used_nw_volumes) + return(-0x98); + + result = find_base_entry((int)volume, directory_base); + if (result < 0) + return(result); + + dbe = dir_base[result]; + nwp_stat(&(dbe->nwpath), "nsp_handle_salvage_purge"); + if (!S_ISDIR(dbe->nwpath.statb.st_mode)) + return(-0x9c); + + result = nsp_salvage_find_current_by_dbe(dbe, scan_sequence, &scan); + if (result) + return(result); + + result = nwsalvage_purge_scan_result(&scan); + if (result < 0) + return(-0x98); + if (result == 0) + return(-0xff); + + XDPRINTF((3, 0, + "INFO SALVAGE 87/18 DONE fn=0x57 sub=0x12 ns=0x%02x seq=0x%08lx vol=0x%08lx base=0x%08lx name=\"%s\"", + namespace, (unsigned long)scan_sequence, (unsigned long)volume, + (unsigned long)directory_base, scan.metadata.original_name)); + return(0); +} + int handle_func_0x57(uint8 *p, int request_len, uint8 *responsedata, int task) { @@ -3165,7 +3448,7 @@ static int code = 0; break; case 0x12 : /* 87/18 Purge Salvageable File */ - result = -0xfb; + result = handle_func_0x57_salvage_purge(p - 1, request_len, responsedata, task); break; case 0x14 : /* Search for File or Subdir Set */ diff --git a/src/nwconn.c b/src/nwconn.c index 258d1de..b8ad45b 100644 --- a/src/nwconn.c +++ b/src/nwconn.c @@ -3349,6 +3349,33 @@ static int handle_ncp_serv(void) } break; + case 0x1b : { /* Scan Salvageable Files, old 22/27 */ + int result = handle_func_0x16_salvage_scan(p, requestlen - 2, + responsedata, + (int)(ncprequest->task)); + if (result > -1) data_len = result; + else completition = (uint8)(-result); + } + break; + + case 0x1c : { /* Recover Salvageable File, old 22/28 */ + int result = handle_func_0x16_salvage_recover(p, requestlen - 2, + responsedata, + (int)(ncprequest->task)); + if (result > -1) data_len = result; + else completition = (uint8)(-result); + } + break; + + case 0x1d : { /* Purge Salvageable File, old 22/29 */ + int result = handle_func_0x16_salvage_purge(p, requestlen - 2, + responsedata, + (int)(ncprequest->task)); + if (result > -1) data_len = result; + else completition = (uint8)(-result); + } + break; + case 0x1e : { /* SCAN a Directory, e.g. used by ndir.exe */ struct INPUT { uint8 header[7]; /* Requestheader */ diff --git a/src/nwsalvage.c b/src/nwsalvage.c index 09021f0..6c7d95f 100644 --- a/src/nwsalvage.c +++ b/src/nwsalvage.c @@ -2161,6 +2161,25 @@ static int nwsalvage_copy_payload_with_novell_io(int volume, return(result); } +int nwsalvage_purge_scan_result(const struct nwsalvage_scan_result *scan) +{ + int failed = 0; + + if (!scan) { + errno = EINVAL; + return(-1); + } + + if (scan->recycle_path[0] && unlink(scan->recycle_path) < 0 && errno != ENOENT) + failed = 1; + if (scan->metadata_path[0] && unlink(scan->metadata_path) < 0 && errno != ENOENT) + failed = 1; + + if (failed) + return(-1); + return(1); +} + int nwsalvage_recover_scan_result(int volume, const struct nwsalvage_scan_result *scan, const char *dest_unixname, int task)