salvage: hook delete path through nwsalvage
All checks were successful
Source release / source-package (push) Successful in 55s

This commit is contained in:
ChatGPT
2026-05-31 11:35:17 +00:00
committed by Mario Fetka
parent 5fc5a5218f
commit 3fb45fd624
7 changed files with 1017 additions and 5 deletions

View File

@@ -24,6 +24,7 @@
#include "net.h"
#include "unxfile.h"
#include "nwsalvage.h"
#include <dirent.h>
#include <utime.h>
@@ -1976,6 +1977,7 @@ static int nw_rmdir(uint8 *unname)
int nw_unlink_node(int volume, uint8 *unname, struct stat *stb)
{
int result=-1;
int salvaged=0;
uint32 attrib=get_nw_attrib_dword(volume, unname, stb);
/* first we look for attributes */
if (attrib & (FILE_ATTR_R|FILE_ATTR_DELETE_INH))
@@ -2000,13 +2002,20 @@ int nw_unlink_node(int volume, uint8 *unname, struct stat *stb)
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();
result = nwsalvage_capture_node_delete(volume, (const char *)unname, stb);
if (!result) {
salvaged = 1;
} else if (result > 0) {
if (0 != (result=unlink(unname))){
if (seteuid(0)) {}
result=unlink(unname) ? -0x8a : 0;
(void)reseteuid();
}
} else if (result < 0) {
result = -0x8a;
}
}
if (!result) {
if (!result && !salvaged) {
free_nw_ext_inode(volume, unname, stb->st_dev, stb->st_ino);
}
return(result);

View File

@@ -1,6 +1,15 @@
/* nwsalvage.c - NetWare salvage/recycle backend helpers */
#include "nwsalvage.h"
#include "net.h"
#include "nwvolume.h"
#include "nwarchive.h"
#include "nwatalk.h"
#include "nwattrib.h"
#include "trustee.h"
#include "tools.h"
#include "connect.h"
#include <ctype.h>
#include <errno.h>
#include <limits.h>
@@ -12,6 +21,7 @@
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <time.h>
#include <unistd.h>
int nwsalvage_repository_name_valid(const char *name)
@@ -999,3 +1009,408 @@ int nwsalvage_read_metadata(const char *metadata_path,
return(0);
}
#endif
#ifdef MARS_NWE_HAVE_YYJSON
static int nwsalvage_move_deleted_file(const char *live_path,
const char *recycle_path,
const char *metadata_path,
const struct nwsalvage_deleted_entry *entry)
{
int saved_errno;
if (!live_path || !*live_path ||
!recycle_path || !*recycle_path ||
!metadata_path || !*metadata_path ||
!entry) {
errno = EINVAL;
return(-1);
}
if (!strcmp(live_path, recycle_path) ||
!strcmp(live_path, metadata_path) ||
!strcmp(recycle_path, metadata_path)) {
errno = EINVAL;
return(-1);
}
if (access(recycle_path, F_OK) == 0) {
errno = EEXIST;
return(-1);
}
if (errno != ENOENT)
return(-1);
if (access(metadata_path, F_OK) == 0) {
errno = EEXIST;
return(-1);
}
if (errno != ENOENT)
return(-1);
if (make_parent_dirs(recycle_path) < 0 || make_parent_dirs(metadata_path) < 0)
return(-1);
if (rename(live_path, recycle_path) < 0)
return(-1);
if (nwsalvage_write_metadata(metadata_path, entry) == 0)
return(0);
saved_errno = errno;
unlink(metadata_path);
if (rename(recycle_path, live_path) < 0) {
errno = saved_errno;
return(-1);
}
errno = saved_errno;
return(-1);
}
#endif
static int nwsalvage_ini_get(int entry, char *str, size_t strsize, void *data)
{
(void)data;
return(get_ini_entry(NULL, entry, (uint8 *)str, (int)strsize));
}
static int nwsalvage_copy_volume_root(int volume, char *root, size_t root_len)
{
size_t len;
if (volume < 0 || volume >= used_nw_volumes ||
!nw_volumes[volume].unixname || !nw_volumes[volume].unixnamlen ||
!root || !root_len) {
errno = EINVAL;
return(-1);
}
len = (size_t)nw_volumes[volume].unixnamlen;
if (len >= root_len) {
errno = ENAMETOOLONG;
return(-1);
}
memcpy(root, nw_volumes[volume].unixname, len);
root[len] = '\0';
while (len > 1 && root[len - 1] == '/') {
root[--len] = '\0';
}
return(0);
}
static int nwsalvage_relative_from_unix(int volume, const char *unixname,
char *relative, size_t relative_len)
{
char root[NWSALVAGE_PATH_MAX];
size_t root_len;
const char *p;
size_t len;
if (!unixname || !*unixname || !relative || !relative_len) {
errno = EINVAL;
return(-1);
}
if (nwsalvage_copy_volume_root(volume, root, sizeof(root)) < 0)
return(-1);
root_len = strlen(root);
if (strncmp(unixname, root, root_len)) {
errno = EINVAL;
return(-1);
}
p = unixname + root_len;
if (*p == '/')
p++;
if (!*p) {
errno = EINVAL;
return(-1);
}
len = strlen(p);
if (len >= relative_len) {
errno = ENAMETOOLONG;
return(-1);
}
memcpy(relative, p, len + 1);
return(0);
}
static int nwsalvage_relative_is_repo_path(const char *relative,
const char *repository)
{
size_t len;
if (!relative || !repository)
return(0);
len = strlen(repository);
return(!strcmp(relative, repository) ||
(!strncmp(relative, repository, len) && relative[len] == '/'));
}
static const char *nwsalvage_basename(const char *path)
{
const char *p;
if (!path)
return("");
p = strrchr(path, '/');
return(p ? p + 1 : path);
}
static void nwsalvage_format_deleted_by(char *out, size_t out_len)
{
if (!out || !out_len)
return;
if (act_obj_id == 1)
strmaxcpy((uint8 *)out, "SUPERVISOR", (int)out_len - 1);
else
slprintf(out, (int)out_len - 1, "0x%08x", act_obj_id);
}
static void nwsalvage_format_hex(char *out, size_t out_len,
const uint8 *data, size_t data_len)
{
static const char hex[] = "0123456789abcdef";
size_t i;
if (!out || out_len < data_len * 2 + 1)
return;
for (i = 0; i < data_len; i++) {
out[i * 2] = hex[(data[i] >> 4) & 0xf];
out[i * 2 + 1] = hex[data[i] & 0xf];
}
out[data_len * 2] = '\0';
}
static unsigned long nwsalvage_parent_entry_id(const char *unixname)
{
char parent[NWSALVAGE_PATH_MAX];
char *slash;
uint32 entry_id = 0;
size_t len;
if (!unixname || !*unixname)
return(0);
len = strlen(unixname);
if (len >= sizeof(parent))
return(0);
memcpy(parent, unixname, len + 1);
slash = strrchr(parent, '/');
if (!slash || slash == parent)
return(0);
*slash = '\0';
if (nwatalk_get_entry_id(parent, &entry_id) == 0)
return((unsigned long)entry_id);
return(0);
}
static void nwsalvage_fill_afp_metadata(const char *unixname,
struct nwsalvage_deleted_entry *entry,
char *finder_info_hex,
size_t finder_info_hex_len,
char *afp_entry_id,
size_t afp_entry_id_len)
{
uint8 finder_info[NWATALK_FINDER_INFO_LEN];
uint16 afp_attributes = 0;
uint32 entry_id = 0;
uint32 resource_size = 0;
memset(finder_info, 0, sizeof(finder_info));
if (nwatalk_get_finder_info(unixname, finder_info, sizeof(finder_info)) != 0)
memset(finder_info, 0, sizeof(finder_info));
nwsalvage_format_hex(finder_info_hex, finder_info_hex_len,
finder_info, sizeof(finder_info));
entry->finder_info_hex = finder_info_hex;
if (nwatalk_get_entry_id(unixname, &entry_id) == 0)
slprintf(afp_entry_id, (int)afp_entry_id_len - 1, "0x%08x", entry_id);
else
afp_entry_id[0] = '\0';
entry->afp_entry_id = afp_entry_id;
if (nwatalk_get_afp_attributes(unixname, &afp_attributes) == 0)
entry->afp_attributes = afp_attributes;
if (nwatalk_get_resource_fork_size(unixname, &resource_size) == 0)
entry->resource_fork_size = resource_size;
}
static void nwsalvage_fill_netware_xattrs(const char *unixname,
struct nwsalvage_deleted_entry *entry)
{
uint16 archive_date = 0;
uint16 archive_time = 0;
uint32 archiver_id = 0;
uint8 archive_flags = 0;
uint16 create_date = 0;
uint16 create_time = 0;
uint32 creator_id = 0;
uint32 modifier_id = 0;
uint8 fileinfo_flags = 0;
uint8 modifier_flags = 0;
mars_nwe_get_archive_info((char *)unixname, &archive_date, &archive_time,
&archiver_id, &archive_flags);
mars_nwe_get_file_info((char *)unixname, &create_date, &create_time,
&creator_id, &fileinfo_flags);
mars_nwe_get_file_modifier_info((char *)unixname, &modifier_id,
&modifier_flags);
entry->netware_archive_flags = archive_flags;
entry->netware_archive_date = archive_date;
entry->netware_archive_time = archive_time;
entry->netware_archiver_id = archiver_id;
entry->netware_fileinfo_flags = fileinfo_flags | modifier_flags;
entry->netware_create_date = create_date;
entry->netware_create_time = create_time;
entry->netware_creator_id = creator_id;
entry->netware_modifier_id = modifier_id;
}
static void nwsalvage_fill_trustees(int volume, const char *unixname,
const struct stat *stb,
struct nwsalvage_deleted_entry *entry)
{
uint32 ids[NWSALVAGE_TRUSTEE_MAX];
int trustees[NWSALVAGE_TRUSTEE_MAX];
int count;
int i;
entry->inherited_rights_mask =
(unsigned int)tru_get_inherited_mask(volume, (uint8 *)unixname,
(struct stat *)stb);
count = tru_get_trustee_set(volume, (uint8 *)unixname, (struct stat *)stb,
0, NWSALVAGE_TRUSTEE_MAX, ids, trustees);
if (count <= 0)
return;
if (count > NWSALVAGE_TRUSTEE_MAX)
count = NWSALVAGE_TRUSTEE_MAX;
entry->trustee_count = (unsigned int)count;
for (i = 0; i < count; i++) {
entry->trustees[i].object_id = ids[i];
entry->trustees[i].rights = (unsigned int)trustees[i];
}
}
int nwsalvage_capture_node_delete(int volume, const char *unixname,
const struct stat *stb)
{
#ifndef MARS_NWE_HAVE_YYJSON
(void)volume;
(void)unixname;
(void)stb;
return(1);
#else
struct nwsalvage_config config;
struct nwsalvage_deleted_entry entry;
char volume_root[NWSALVAGE_PATH_MAX];
char relative_path[NWSALVAGE_PATH_MAX];
char recycle_path[NWSALVAGE_PATH_MAX];
char metadata_path[NWSALVAGE_PATH_MAX];
char salvage_relative_path[NWSALVAGE_PATH_MAX];
char recycle_relative_path[NWSALVAGE_PATH_MAX];
char metadata_relative_path[NWSALVAGE_PATH_MAX];
char original_path[NWSALVAGE_PATH_MAX];
char volume_name[NWSALVAGE_REPOSITORY_NAME_MAX];
char deleted_by[NWSALVAGE_USER_NAME_MAX];
char finder_info_hex[NWSALVAGE_FINDER_INFO_HEX_LEN + 1];
char afp_entry_id[NWSALVAGE_AFP_ENTRY_ID_MAX];
if (!unixname || !*unixname || !stb) {
errno = EINVAL;
return(-1);
}
if (!S_ISREG(stb->st_mode))
return(1);
if (nwsalvage_config_load_from_ini(&config, nwsalvage_ini_get, NULL) < 0)
return(-1);
if (!config.enabled)
return(1);
if (nwsalvage_copy_volume_root(volume, volume_root, sizeof(volume_root)) < 0 ||
nwsalvage_relative_from_unix(volume, unixname,
relative_path, sizeof(relative_path)) < 0)
return(-1);
if (nwsalvage_relative_is_repo_path(relative_path,
config.recycle_repository) ||
nwsalvage_relative_is_repo_path(relative_path,
config.metadata_repository))
return(1);
nwsalvage_format_deleted_by(deleted_by, sizeof(deleted_by));
if (slprintf(salvage_relative_path, sizeof(salvage_relative_path) - 1,
"%s/%s", deleted_by, relative_path) < 0) {
errno = ENAMETOOLONG;
return(-1);
}
if (nwsalvage_build_recycle_path(recycle_path, sizeof(recycle_path),
&config, volume_root,
salvage_relative_path) < 0 ||
nwsalvage_build_metadata_path(metadata_path, sizeof(metadata_path),
&config, volume_root,
salvage_relative_path) < 0 ||
nwsalvage_build_recycle_relative_path(recycle_relative_path,
sizeof(recycle_relative_path),
&config,
salvage_relative_path) < 0 ||
nwsalvage_build_metadata_relative_path(metadata_relative_path,
sizeof(metadata_relative_path),
&config,
salvage_relative_path) < 0)
return(-1);
if (nw_get_volume_name(volume, (uint8 *)volume_name,
sizeof(volume_name)) < 1)
return(-1);
if (slprintf(original_path, sizeof(original_path) - 1, "%s:%s",
volume_name, relative_path) < 0) {
errno = ENAMETOOLONG;
return(-1);
}
memset(&entry, 0, sizeof(entry));
memset(finder_info_hex, '0', NWSALVAGE_FINDER_INFO_HEX_LEN);
finder_info_hex[NWSALVAGE_FINDER_INFO_HEX_LEN] = '\0';
afp_entry_id[0] = '\0';
entry.source = "mars_nwe";
entry.volume_name = volume_name;
entry.deleted_by = deleted_by;
entry.deleted_at = (long)time(NULL);
entry.original_path = original_path;
entry.original_parent_entry_id = nwsalvage_parent_entry_id(unixname);
entry.original_name = nwsalvage_basename(relative_path);
entry.recycle_relative_path = recycle_relative_path;
entry.salvage_relative_path = metadata_relative_path;
entry.attributes = get_nw_attrib_dword(volume, (char *)unixname,
(struct stat *)stb);
entry.mode = (unsigned long)stb->st_mode;
entry.size = (unsigned long long)stb->st_size;
entry.atime = (long)stb->st_atime;
entry.mtime = (long)stb->st_mtime;
entry.ctime = (long)stb->st_ctime;
nwsalvage_fill_afp_metadata(unixname, &entry, finder_info_hex,
sizeof(finder_info_hex), afp_entry_id,
sizeof(afp_entry_id));
nwsalvage_fill_netware_xattrs(unixname, &entry);
nwsalvage_fill_trustees(volume, unixname, stb, &entry);
if (nwsalvage_move_deleted_file(unixname, recycle_path,
metadata_path, &entry) < 0)
return(-1);
return(0);
#endif
}