Finish the c32ncp.c/c32ncp.h to ncpapi.c/ncpapi.h rename. Update the build files, include directives, dependency tracking, header guard, README references and file-level comments to use the new ncpapi naming. This matches the current split where ncpapi contains the ncpXX_YY_* protocol API wrappers and ncpcall contains the lower-level requester/transport helpers. No behavior change.
319 lines
8.7 KiB
C
319 lines
8.7 KiB
C
/*
|
|
* mars-nwe-dosutils - NetWare/DOS utility tools.
|
|
*
|
|
* Copyright (C) 2026 Mario Fetka
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version 2
|
|
* of the License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
/*
|
|
* Purpose: REMOVE utility for removing trustee rights from NetWare directories and files.
|
|
* Depends on: net.h, ncpapi.h, trustee.h/trustee.c trustee helpers, netcall.c requester helpers, tools.c shared utility routines.
|
|
*/
|
|
|
|
#include "net.h"
|
|
#include "ncpapi.h"
|
|
#include "trustee.h"
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
|
|
#ifndef _A_NORMAL
|
|
#define _A_NORMAL 0x00
|
|
#endif
|
|
|
|
static int remove_last_rc = 0;
|
|
|
|
static void remove_usage(void)
|
|
{
|
|
fprintf(stdout, "\n");
|
|
fprintf(stdout, "Usage: REMOVE [USER | GROUP] name [FROM path] [option]\n");
|
|
fprintf(stdout, "Options: /Subdirs | /Files \n");
|
|
}
|
|
|
|
static void remove_usage_after_error(void)
|
|
{
|
|
fprintf(stdout, "\007\n");
|
|
fprintf(stdout, "Usage: REMOVE [USER | GROUP] name [FROM path] [option]\n");
|
|
fprintf(stdout, "Options: /Subdirs | /Files \n");
|
|
fprintf(stdout, "\n");
|
|
}
|
|
|
|
static void remove_header_path(char *out, char *path, int max)
|
|
{
|
|
char *p;
|
|
|
|
tool_header_path(out, path, max);
|
|
|
|
/* Novell REMOVE displays server and volume as SERVER/SYS: while
|
|
* RIGHTS uses SERVER\SYS:. Keep the rest of the path with DOS
|
|
* backslashes. */
|
|
p = strchr(out, '\\');
|
|
if (p && strchr(out, ':') && p < strchr(out, ':'))
|
|
*p = '/';
|
|
}
|
|
|
|
static int remove_one(char *path, uint16 dhandle, uint32 object_id,
|
|
uint16 objtype, char *objname, int forced_is_file)
|
|
{
|
|
uint16 old_rights = 0;
|
|
int is_dir;
|
|
int rc;
|
|
|
|
/* Without /FILES, Novell REMOVE reports directory-oriented messages even
|
|
* if the specified path cannot be located. */
|
|
is_dir = forced_is_file ? 0 : 1;
|
|
|
|
rc = ncp87_05_find_trustee_rights(path, dhandle, object_id, &old_rights,
|
|
NULL, NULL, NULL);
|
|
remove_last_rc = rc;
|
|
if (rc) {
|
|
if (rc == 0xff)
|
|
fprintf(stdout, "No trustee for the specified %s.\n", is_dir ? "directory" : "file");
|
|
else
|
|
fprintf(stdout, "Error scanning trustee list.\n");
|
|
return(1);
|
|
}
|
|
|
|
rc = ncp22_2b_delete_trustee_rights(path, dhandle, object_id);
|
|
if (rc)
|
|
rc = ncp87_0b_delete_trustee_rights(path, dhandle, object_id,
|
|
NULL, NULL, NULL);
|
|
remove_last_rc = rc;
|
|
if (rc) {
|
|
fprintf(stdout, "Error deleting trustee.\n");
|
|
return(1);
|
|
}
|
|
|
|
{
|
|
char header[300];
|
|
remove_header_path(header, path, sizeof(header));
|
|
fprintf(stdout, "%s\n", header);
|
|
}
|
|
|
|
if (objtype == TRUSTEE_BINDERY_GROUP)
|
|
fprintf(stdout, "Group \"%s\" no longer a trustee to the specified %s.\n\n",
|
|
objname, is_dir ? "directory" : "file");
|
|
else
|
|
fprintf(stdout, "User \"%s\" no longer a trustee to the specified %s.\n\n",
|
|
objname, is_dir ? "directory" : "file");
|
|
|
|
return(0);
|
|
}
|
|
|
|
static int remove_subdirs_inner(char *path, uint16 dhandle, uint32 object_id,
|
|
uint16 objtype, char *objname, int *count,
|
|
int include_this)
|
|
{
|
|
struct find_t ff;
|
|
char pattern[260];
|
|
char child[260];
|
|
int rc = 0;
|
|
|
|
if (include_this) {
|
|
if (remove_one(path, dhandle, object_id, objtype, objname, 0) == 0)
|
|
(*count)++;
|
|
else
|
|
rc = 1;
|
|
}
|
|
|
|
tool_join_path(pattern, path, "*.*", sizeof(pattern));
|
|
|
|
if (_dos_findfirst(pattern, _A_SUBDIR, &ff) == 0) {
|
|
do {
|
|
if ((ff.attrib & _A_SUBDIR) && !tool_is_dot_dir(ff.name)) {
|
|
tool_join_path(child, path, ff.name, sizeof(child));
|
|
if (remove_subdirs_inner(child, dhandle, object_id, objtype, objname,
|
|
count, 1))
|
|
rc = 1;
|
|
}
|
|
} while (_dos_findnext(&ff) == 0);
|
|
}
|
|
|
|
return(rc);
|
|
}
|
|
|
|
static int remove_subdirs(char *path, uint16 dhandle, uint32 object_id,
|
|
uint16 objtype, char *objname, int *count)
|
|
{
|
|
/* Novell REMOVE /SUBDIRS affects the subdirectories under the specified
|
|
* start directory, not the start directory itself. */
|
|
return(remove_subdirs_inner(path, dhandle, object_id, objtype, objname,
|
|
count, 0));
|
|
}
|
|
|
|
static int remove_files(char *path, uint16 dhandle, uint32 object_id,
|
|
uint16 objtype, char *objname, int *count)
|
|
{
|
|
struct find_t ff;
|
|
char dir[260];
|
|
char pat[80];
|
|
char spec[260];
|
|
char target[260];
|
|
int rc = 0;
|
|
|
|
if (trustee_path_is_dir(path)) {
|
|
strmaxcpy(dir, path, sizeof(dir) - 1);
|
|
strmaxcpy(pat, "*.*", sizeof(pat) - 1);
|
|
} else if (tool_has_wildcards(path)) {
|
|
tool_parent_pattern(dir, pat, path, sizeof(dir), sizeof(pat));
|
|
} else {
|
|
if (remove_one(path, dhandle, object_id, objtype, objname, 1) == 0)
|
|
(*count)++;
|
|
else
|
|
rc = 1;
|
|
return(rc);
|
|
}
|
|
|
|
tool_join_path(spec, dir, pat, sizeof(spec));
|
|
if (_dos_findfirst(spec, _A_NORMAL | _A_HIDDEN | _A_SYSTEM | _A_ARCH, &ff) == 0) {
|
|
do {
|
|
if (!(ff.attrib & _A_SUBDIR)) {
|
|
tool_join_path(target, dir, ff.name, sizeof(target));
|
|
if (remove_one(target, dhandle, object_id, objtype, objname, 1) == 0)
|
|
(*count)++;
|
|
else
|
|
rc = 1;
|
|
}
|
|
} while (_dos_findnext(&ff) == 0);
|
|
}
|
|
|
|
return(rc);
|
|
}
|
|
|
|
int func_remove(int argc, char *argv[], int mode)
|
|
{
|
|
char *path = ".";
|
|
char *objname = NULL;
|
|
char objprint[48];
|
|
uint16 objtype = TRUSTEE_BINDERY_USER;
|
|
int objtype_given = 0;
|
|
uint8 connid = 0;
|
|
uint8 dhandle = 0;
|
|
uint32 object_id;
|
|
int use_subdirs = 0;
|
|
int use_files = 0;
|
|
int count = 0;
|
|
int i = 1;
|
|
int rc;
|
|
|
|
(void)mode;
|
|
|
|
if (argc < 2 || tool_is_help_arg(argv[1])) {
|
|
if (argc < 2) {
|
|
remove_usage_after_error();
|
|
return(1);
|
|
}
|
|
remove_usage();
|
|
return(argc < 2 ? 1 : 0);
|
|
}
|
|
|
|
if (i < argc && tool_strsame(argv[i], "USER")) {
|
|
/* Novell treats "REMOVE USER FROM path" as an object lookup for
|
|
* USER, not as a grammar error. */
|
|
if ((i + 1) < argc && tool_strsame(argv[i + 1], "FROM")) {
|
|
objtype_given = 0;
|
|
} else {
|
|
objtype = TRUSTEE_BINDERY_USER;
|
|
objtype_given = 1;
|
|
i++;
|
|
}
|
|
} else if (i < argc && tool_strsame(argv[i], "GROUP")) {
|
|
if ((i + 1) < argc && tool_strsame(argv[i + 1], "FROM")) {
|
|
objtype_given = 0;
|
|
} else {
|
|
objtype = TRUSTEE_BINDERY_GROUP;
|
|
objtype_given = 1;
|
|
i++;
|
|
}
|
|
}
|
|
|
|
if (i >= argc) {
|
|
remove_usage_after_error();
|
|
return(1);
|
|
}
|
|
|
|
objname = argv[i++];
|
|
|
|
if (i < argc && tool_strsame(argv[i], "FROM")) {
|
|
i++;
|
|
if (i >= argc) {
|
|
remove_usage_after_error();
|
|
return(1);
|
|
}
|
|
path = argv[i++];
|
|
}
|
|
|
|
while (i < argc) {
|
|
if (!tool_is_option(argv[i])) {
|
|
remove_usage_after_error();
|
|
return(1);
|
|
}
|
|
|
|
if (trustee_is_files_option(argv[i])) {
|
|
use_files = 1;
|
|
i++;
|
|
continue;
|
|
}
|
|
|
|
if (trustee_is_subdirs_option(argv[i])) {
|
|
use_subdirs = 1;
|
|
i++;
|
|
continue;
|
|
}
|
|
|
|
remove_usage_after_error();
|
|
return(1);
|
|
}
|
|
|
|
if (use_files && use_subdirs) {
|
|
fprintf(stdout, "Remove cannot do both directories and files in a single pass.\n");
|
|
return(1);
|
|
}
|
|
|
|
if (tool_current_dhandle(&connid, &dhandle)) {
|
|
fprintf(stdout, "Error: Drive not mapped to network.\n");
|
|
return(1);
|
|
}
|
|
|
|
object_id = trustee_lookup_object(objname, &objtype, objtype_given);
|
|
if (!object_id) {
|
|
if (objtype_given && objtype == TRUSTEE_BINDERY_GROUP)
|
|
fprintf(stdout, "\007Group \"%s\" not found.\n", objname);
|
|
else if (objtype_given)
|
|
fprintf(stdout, "\007User \"%s\" not found.\n", objname);
|
|
else
|
|
fprintf(stdout, "\007User or group \"%s\" not found.\n", objname);
|
|
return(1);
|
|
}
|
|
|
|
tool_upcopy(objprint, objname, sizeof(objprint));
|
|
|
|
if (use_subdirs)
|
|
rc = remove_subdirs(path, (uint16)dhandle, object_id, objtype, objprint, &count);
|
|
else if (use_files)
|
|
rc = remove_files(path, (uint16)dhandle, object_id, objtype, objprint, &count);
|
|
else {
|
|
rc = remove_one(path, (uint16)dhandle, object_id, objtype, objprint, 0);
|
|
if (!rc)
|
|
count = 1;
|
|
}
|
|
|
|
if (use_subdirs || (!use_files && !rc))
|
|
fprintf(stdout, "Trustee \"%s\" removed from %d directories.\n\n", objprint, count);
|
|
else if (use_files)
|
|
fprintf(stdout, "Trustee \"%s\" removed from %d files.\n\n", objprint, count);
|
|
|
|
return(rc ? (remove_last_rc ? remove_last_rc : 1) : 0);
|
|
}
|