dosutils: match Novell paths for flags and trustees
Move FLAG, GRANT and REMOVE closer to the request paths used by the Novell tools and extend the DOS comparison tests. FLAG now reads attributes through the old NCP22 directory scan path and writes them through NCP22/25 Set Directory/File Information. This keeps extended attributes such as Delete Inhibit and Rename Inhibit intact and matches the Novell behavior observed in the server logs. GRANT now prefers NCP22/27 SetTrustee with an NCP87 fallback. Supervisor rights are expanded like Novell does, so granting S sends and reports the full SRWCEMFA mask. The visible output, path formatting and error text are adjusted to match the Novell baseline. REMOVE now prefers NCP22/2B DelTrustee with an NCP87 fallback. The DelTrustee request layout is corrected, /SUBDIRS handling is aligned with Novell, and the output/error text is matched to the baseline. The FLAG, FLAGDIR, GRANT and REMOVE tests now compare NPUBLIC baselines against the PUBLIC implementations and add delayed NOPASSUSER readback checks using DLYSTRT and the maintainer LOGIN password option.
This commit is contained in:
125
remove.c
125
remove.c
@@ -12,15 +12,33 @@
|
||||
|
||||
static int remove_last_rc = 0;
|
||||
|
||||
static void remove_usage_error(void)
|
||||
{
|
||||
fprintf(stdout, "Command line arguments violate grammar defined for REMOVE.\n\n");
|
||||
}
|
||||
|
||||
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");
|
||||
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;
|
||||
|
||||
trustee_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,
|
||||
@@ -30,7 +48,9 @@ static int remove_one(char *path, uint16 dhandle, uint32 object_id,
|
||||
int is_dir;
|
||||
int rc;
|
||||
|
||||
is_dir = forced_is_file ? 0 : trustee_path_is_dir(path);
|
||||
/* Without /FILES, Novell REMOVE reports directory-oriented messages even
|
||||
* if the specified path cannot be located. */
|
||||
is_dir = forced_is_file ? 0 : 1;
|
||||
|
||||
rc = c32_ncp87_find_trustee_rights(path, dhandle, object_id, &old_rights,
|
||||
NULL, NULL, NULL);
|
||||
@@ -43,8 +63,10 @@ static int remove_one(char *path, uint16 dhandle, uint32 object_id,
|
||||
return(1);
|
||||
}
|
||||
|
||||
rc = c32_ncp87_delete_trustee_rights(path, dhandle, object_id,
|
||||
NULL, NULL, NULL);
|
||||
rc = c32_ncp22_delete_trustee_rights(path, dhandle, object_id);
|
||||
if (rc)
|
||||
rc = c32_ncp87_delete_trustee_rights(path, dhandle, object_id,
|
||||
NULL, NULL, NULL);
|
||||
remove_last_rc = rc;
|
||||
if (rc) {
|
||||
fprintf(stdout, "Error deleting trustee.\n");
|
||||
@@ -53,32 +75,35 @@ static int remove_one(char *path, uint16 dhandle, uint32 object_id,
|
||||
|
||||
{
|
||||
char header[300];
|
||||
trustee_header_path(header, path, sizeof(header));
|
||||
fprintf(stdout, "%s\n\n", header);
|
||||
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",
|
||||
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",
|
||||
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(char *path, uint16 dhandle, uint32 object_id,
|
||||
uint16 objtype, char *objname, int *count)
|
||||
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 (remove_one(path, dhandle, object_id, objtype, objname, 0) == 0)
|
||||
(*count)++;
|
||||
else
|
||||
rc = 1;
|
||||
if (include_this) {
|
||||
if (remove_one(path, dhandle, object_id, objtype, objname, 0) == 0)
|
||||
(*count)++;
|
||||
else
|
||||
rc = 1;
|
||||
}
|
||||
|
||||
trustee_join_path(pattern, path, "*.*", sizeof(pattern));
|
||||
|
||||
@@ -86,7 +111,8 @@ static int remove_subdirs(char *path, uint16 dhandle, uint32 object_id,
|
||||
do {
|
||||
if ((ff.attrib & _A_SUBDIR) && !trustee_is_dot_dir(ff.name)) {
|
||||
trustee_join_path(child, path, ff.name, sizeof(child));
|
||||
if (remove_subdirs(child, dhandle, object_id, objtype, objname, count))
|
||||
if (remove_subdirs_inner(child, dhandle, object_id, objtype, objname,
|
||||
count, 1))
|
||||
rc = 1;
|
||||
}
|
||||
} while (_dos_findnext(&ff) == 0);
|
||||
@@ -95,6 +121,15 @@ static int remove_subdirs(char *path, uint16 dhandle, uint32 object_id,
|
||||
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)
|
||||
{
|
||||
@@ -153,25 +188,36 @@ int func_remove(int argc, char *argv[], int mode)
|
||||
(void)mode;
|
||||
|
||||
if (argc < 2 || trustee_is_help(argv[1])) {
|
||||
if (argc < 2)
|
||||
remove_usage_error();
|
||||
if (argc < 2) {
|
||||
remove_usage_after_error();
|
||||
return(1);
|
||||
}
|
||||
remove_usage();
|
||||
return(argc < 2 ? 1 : 0);
|
||||
}
|
||||
|
||||
if (i < argc && trustee_same(argv[i], "USER")) {
|
||||
objtype = TRUSTEE_BINDERY_USER;
|
||||
objtype_given = 1;
|
||||
i++;
|
||||
/* Novell treats "REMOVE USER FROM path" as an object lookup for
|
||||
* USER, not as a grammar error. */
|
||||
if ((i + 1) < argc && trustee_same(argv[i + 1], "FROM")) {
|
||||
objtype_given = 0;
|
||||
} else {
|
||||
objtype = TRUSTEE_BINDERY_USER;
|
||||
objtype_given = 1;
|
||||
i++;
|
||||
}
|
||||
} else if (i < argc && trustee_same(argv[i], "GROUP")) {
|
||||
objtype = TRUSTEE_BINDERY_GROUP;
|
||||
objtype_given = 1;
|
||||
i++;
|
||||
if ((i + 1) < argc && trustee_same(argv[i + 1], "FROM")) {
|
||||
objtype_given = 0;
|
||||
} else {
|
||||
objtype = TRUSTEE_BINDERY_GROUP;
|
||||
objtype_given = 1;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
if (i >= argc) {
|
||||
remove_usage_error();
|
||||
remove_usage();
|
||||
remove_usage_after_error();
|
||||
return(1);
|
||||
}
|
||||
|
||||
@@ -180,8 +226,7 @@ int func_remove(int argc, char *argv[], int mode)
|
||||
if (i < argc && trustee_same(argv[i], "FROM")) {
|
||||
i++;
|
||||
if (i >= argc) {
|
||||
remove_usage_error();
|
||||
remove_usage();
|
||||
remove_usage_after_error();
|
||||
return(1);
|
||||
}
|
||||
path = argv[i++];
|
||||
@@ -189,8 +234,7 @@ int func_remove(int argc, char *argv[], int mode)
|
||||
|
||||
while (i < argc) {
|
||||
if (!trustee_is_option(argv[i])) {
|
||||
remove_usage_error();
|
||||
remove_usage();
|
||||
remove_usage_after_error();
|
||||
return(1);
|
||||
}
|
||||
|
||||
@@ -206,8 +250,7 @@ int func_remove(int argc, char *argv[], int mode)
|
||||
continue;
|
||||
}
|
||||
|
||||
remove_usage_error();
|
||||
remove_usage();
|
||||
remove_usage_after_error();
|
||||
return(1);
|
||||
}
|
||||
|
||||
@@ -224,11 +267,11 @@ int func_remove(int argc, char *argv[], int mode)
|
||||
object_id = trustee_lookup_object(objname, &objtype, objtype_given);
|
||||
if (!object_id) {
|
||||
if (objtype_given && objtype == TRUSTEE_BINDERY_GROUP)
|
||||
fprintf(stdout, "Group \"%s\" not found.\n", objname);
|
||||
fprintf(stdout, "\007Group \"%s\" not found.\n", objname);
|
||||
else if (objtype_given)
|
||||
fprintf(stdout, "User \"%s\" not found.\n", objname);
|
||||
fprintf(stdout, "\007User \"%s\" not found.\n", objname);
|
||||
else
|
||||
fprintf(stdout, "User or group \"%s\" not found.\n", objname);
|
||||
fprintf(stdout, "\007User or group \"%s\" not found.\n", objname);
|
||||
return(1);
|
||||
}
|
||||
|
||||
@@ -245,9 +288,9 @@ int func_remove(int argc, char *argv[], int mode)
|
||||
}
|
||||
|
||||
if (use_subdirs || (!use_files && !rc))
|
||||
fprintf(stdout, "Trustee \"%s\" removed from %d directories.\n", objprint, count);
|
||||
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", objprint, count);
|
||||
fprintf(stdout, "Trustee \"%s\" removed from %d files.\n\n", objprint, count);
|
||||
|
||||
return(rc ? (remove_last_rc ? remove_last_rc : 1) : 0);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user