Files
mars-dosutils/flag.c
Mario Fetka c50202e93b dosutils: factor shared helpers and update README
Move common DOS utility helper code into tools.c and expose it through
net.h.  This removes duplicated command-local helpers from GRANT,
RIGHTS, FLAG, FLAGDIR and the trustee helper layer.

The shared helpers cover case-insensitive argument comparison, help and
option detection, /FILES and /SUBDIRS parsing, current network directory
handle lookup, current volume prefix formatting, uppercase DOS path
copying, basename/header-path handling, wildcard detection and simple
path joining/splitting.

Keep the command frontends smaller and less coupled so the current
multicall utility can later be split into smaller grouped multicall
binaries, such as trustee tools, login/session tools and file/flag
tools.

Update the DOS utilities README for the newer Client32 and trustee
commands.  Document RIGHTS, GRANT, REVOKE and REMOVE in the status,
feature, command and install sections.  Add command reference entries
for the trustee tools, including Novell-style syntax, supported rights,
recursive/file options and missing-trustee behavior.

Also mention the shared trustee helper layer and common tools.c helpers
used by the newer command frontends.
2026-05-24 20:45:56 +02:00

475 lines
12 KiB
C

/* flag.c - Novell FLAG-like DOS utility, stage 1 */
#include "net.h"
#include "c32ncp.h"
#include <dos.h>
/*
* FLAG v4b: NCP 87 namespace DOS info.
*
* ncpfs reference:
* ncp_ns_modify_entry_dos_info():
* subfunction 7, namespace DOS, search attrs SA_ALL,
* ModifyInformationMask, struct ncp_dos_info, handle/path.
*
* We use dirstyle=0 (short directory handle) against the current DOS
* directory handle and a one-component DOS filename.
*/
#define FLAG_NW_NS_DOS 0x00
#define FLAG_SA_ALL 0x0006
#define FLAG_RIM_ATTRIBUTES 0x00000004UL
#define NWFA_RO 0x00000001UL
#define NWFA_H 0x00000002UL
#define NWFA_SY 0x00000004UL
#define NWFA_A 0x00000020UL
#define NWFA_S 0x00000080UL
#define NWFA_T 0x00001000UL
#define NWFA_RA 0x00004000UL
#define NWFA_WA 0x00008000UL
#define NWFA_P 0x00010000UL
#define NWFA_RI 0x00020000UL
#define NWFA_DI 0x00040000UL
#define NWFA_CI 0x00080000UL
static void flag_put_word_lh(uint8 *p, uint16 v)
{
p[0] = (uint8)(v & 0xff);
p[1] = (uint8)((v >> 8) & 0xff);
}
static void flag_put_dword_lh(uint8 *p, uint32 v)
{
p[0] = (uint8)(v & 0xff);
p[1] = (uint8)((v >> 8) & 0xff);
p[2] = (uint8)((v >> 16) & 0xff);
p[3] = (uint8)((v >> 24) & 0xff);
}
static uint32 flag_get_dword_lh(uint8 *p)
{
return((uint32)p[0] |
((uint32)p[1] << 8) |
((uint32)p[2] << 16) |
((uint32)p[3] << 24));
}
static int flag_add_handle_path(uint8 *p, uint8 dhandle, char *name)
{
int nlen;
nlen = strlen(name);
if (nlen > 255) nlen = 255;
/*
* handle/path:
* volume/handle byte
* dir base dword
* dirstyle byte (0 = short dir handle)
* path components: 1 component, length, bytes
*/
*p++ = dhandle;
flag_put_dword_lh(p, 0L); p += 4;
*p++ = 0; /* dirstyle = handle */
*p++ = 1; /* one path component */
*p++ = (uint8)nlen;
memcpy(p, name, nlen);
p += nlen;
return(1 + 4 + 1 + 1 + 1 + nlen);
}
static int flag_ncp87_obtain_attrs(char *name, uint32 *attrs)
{
struct {
uint16 len;
uint8 data[320];
} req;
struct {
uint16 len;
uint8 data[128];
} repl;
uint8 connid = 0;
uint8 dhandle = 0;
uint8 *p;
int hlen;
if (tool_current_dhandle(&connid, &dhandle))
return(-1);
/*
* Prefer the verified Client32 NCP87 path. If it is not available,
* fall back to the historical INT 21h/Net_Call path below.
*/
if (c32_ncp87_obtain_rim_attributes(name, (uint16)dhandle,
attrs, NULL, NULL, NULL) == 0)
return(0);
memset(&req, 0, sizeof(req));
memset(&repl, 0, sizeof(repl));
p = req.data;
*p++ = 6; /* subfunction: obtain file/subdir info */
*p++ = FLAG_NW_NS_DOS; /* source namespace */
*p++ = FLAG_NW_NS_DOS; /* target namespace */
flag_put_word_lh(p, FLAG_SA_ALL); p += 2;
flag_put_dword_lh(p, FLAG_RIM_ATTRIBUTES); p += 4;
hlen = flag_add_handle_path(p, dhandle, name);
p += hlen;
req.len = (uint16)(p - req.data);
repl.len = sizeof(repl.data);
neterrno = Net_Call(0xF257, &req, &repl);
if (neterrno)
return(-1);
/*
* With RIM_ATTRIBUTES only, ncpfs expects NSI_Attributes first.
* First dword is the 32-bit Attributes field.
*/
if (attrs)
*attrs = flag_get_dword_lh(repl.data);
return(0);
}
static int flag_ncp87_modify_attrs(char *name, uint32 attrs)
{
struct {
uint16 len;
uint8 data[384];
} req;
struct {
uint16 len;
uint8 data[8];
} repl;
uint8 connid = 0;
uint8 dhandle = 0;
uint8 *p;
int hlen;
if (tool_current_dhandle(&connid, &dhandle))
return(-1);
/*
* Prefer verified Client32 modify path. The old INT 21h/F257 modify path
* can hang under DOS Client32 for high FLAG bits such as T/P/DI/RI.
*/
{
uint16 actual = 0;
uint16 hlo = 0;
uint16 hhi = 0;
if (!c32_ncp87_modify_dos_attributes(name, (uint16)dhandle, attrs,
&actual, &hlo, &hhi))
return(0);
}
memset(&req, 0, sizeof(req));
memset(&repl, 0, sizeof(repl));
p = req.data;
*p++ = 7; /* subfunction: modify DOS info */
*p++ = FLAG_NW_NS_DOS;
*p++ = 0; /* reserved */
flag_put_word_lh(p, FLAG_SA_ALL); p += 2;
flag_put_dword_lh(p, FLAG_RIM_ATTRIBUTES); p += 4; /* modify mask */
flag_put_dword_lh(p, attrs); p += 4; /* Attributes */
/*
* Remaining ncp_dos_info fields. Mask says only Attributes is valid,
* so these should be ignored, but ncpfs still sends the full structure.
*/
memset(p, 0, 34);
p += 34;
hlen = flag_add_handle_path(p, dhandle, name);
p += hlen;
req.len = (uint16)(p - req.data);
repl.len = sizeof(repl.data);
neterrno = Net_Call(0xF257, &req, &repl);
if (neterrno)
return(-1);
return(0);
}
#ifndef _A_NORMAL
#define _A_NORMAL 0x00
#endif
#ifndef _A_RDONLY
#define _A_RDONLY 0x01
#endif
#ifndef _A_HIDDEN
#define _A_HIDDEN 0x02
#endif
#ifndef _A_SYSTEM
#define _A_SYSTEM 0x04
#endif
#ifndef _A_SUBDIR
#define _A_SUBDIR 0x10
#endif
#ifndef _A_ARCH
#define _A_ARCH 0x20
#endif
static void flag_help(void)
{
fprintf(stdout, "USAGE: FLAG [path [ option | [+|-] attribute(s) ] [SUB]]\n");
fprintf(stdout, "\n");
fprintf(stdout, "386 Attributes:\n");
fprintf(stdout, "--------------\n");
fprintf(stdout, "\n");
fprintf(stdout, "RO Read Only\n");
fprintf(stdout, "RW Read Write\n");
fprintf(stdout, "S Sharable\n");
fprintf(stdout, "H Hidden\n");
fprintf(stdout, "Sy System\n");
fprintf(stdout, "T Transactional\n");
fprintf(stdout, "P Purge\n");
fprintf(stdout, "A Archive Needed\n");
fprintf(stdout, "RA Read Audit\n");
fprintf(stdout, "WA Write Audit\n");
fprintf(stdout, "CI Copy Inhibit\n");
fprintf(stdout, "DI Delete Inhibit\n");
fprintf(stdout, "RI Rename Inhibit\n");
fprintf(stdout, "\n");
fprintf(stdout, "All All\n");
fprintf(stdout, "N Normal\n");
fprintf(stdout, "SUB\n");
}
static int flag_attr_mask(char *s, uint32 *setbits, uint32 *clearbits)
{
int set = 1;
char *p = s;
if (*p == '+') {
set = 1;
p++;
} else if (*p == '-') {
set = 0;
p++;
}
if (!*p) return(-1);
if (tool_strsame(p, "RO")) {
if (set) {
*setbits |= (NWFA_RO | NWFA_DI | NWFA_RI);
} else {
*clearbits |= (NWFA_RO | NWFA_DI | NWFA_RI);
}
} else if (tool_strsame(p, "RW")) {
*clearbits |= (NWFA_RO | NWFA_DI | NWFA_RI);
} else if (tool_strsame(p, "S")) {
if (set) *setbits |= NWFA_S;
else *clearbits |= NWFA_S;
} else if (tool_strsame(p, "H")) {
if (set) *setbits |= NWFA_H;
else *clearbits |= NWFA_H;
} else if (tool_strsame(p, "SY") || tool_strsame(p, "SYS") || tool_strsame(p, "SYSTEM")) {
if (set) *setbits |= NWFA_SY;
else *clearbits |= NWFA_SY;
} else if (tool_strsame(p, "T")) {
if (set) *setbits |= NWFA_T;
else *clearbits |= NWFA_T;
} else if (tool_strsame(p, "P")) {
if (set) *setbits |= NWFA_P;
else *clearbits |= NWFA_P;
} else if (tool_strsame(p, "A")) {
if (set) *setbits |= NWFA_A;
else *clearbits |= NWFA_A;
} else if (tool_strsame(p, "RA")) {
if (set) *setbits |= NWFA_RA;
else *clearbits |= NWFA_RA;
} else if (tool_strsame(p, "WA")) {
if (set) *setbits |= NWFA_WA;
else *clearbits |= NWFA_WA;
} else if (tool_strsame(p, "CI")) {
if (set) *setbits |= NWFA_CI;
else *clearbits |= NWFA_CI;
} else if (tool_strsame(p, "DI")) {
if (set) *setbits |= NWFA_DI;
else *clearbits |= NWFA_DI;
} else if (tool_strsame(p, "RI")) {
if (set) *setbits |= NWFA_RI;
else *clearbits |= NWFA_RI;
} else if (tool_strsame(p, "N") || tool_strsame(p, "NORMAL")) {
*clearbits |= (NWFA_RO | NWFA_H | NWFA_SY | NWFA_A |
NWFA_S | NWFA_T | NWFA_P |
NWFA_RA | NWFA_WA | NWFA_CI | NWFA_DI | NWFA_RI);
} else if (tool_strsame(p, "ALL")) {
*setbits |= (NWFA_RO | NWFA_H | NWFA_SY | NWFA_A |
NWFA_S | NWFA_T | NWFA_P |
NWFA_RA | NWFA_WA | NWFA_CI | NWFA_DI | NWFA_RI);
} else {
fprintf(stderr, "Unknown attribute encountered in command line.\n");
return(-1);
}
return(0);
}
static void flag_print_attrs(uint32 attr)
{
/*
* Novell order:
* Ro/Rw S A - H Sy T P Ra Wa CI DI RI
*/
fprintf(stdout, "[ ");
fprintf(stdout, "%s ", (attr & NWFA_RO) ? "Ro" : "Rw");
fprintf(stdout, "%c ", (attr & NWFA_S) ? 'S' : '-');
fprintf(stdout, "%c ", (attr & NWFA_A) ? 'A' : '-');
fprintf(stdout, "- ");
fprintf(stdout, "%c ", (attr & NWFA_H) ? 'H' : '-');
fprintf(stdout, "%s ", (attr & NWFA_SY) ? "Sy" : "--");
fprintf(stdout, "%c ", (attr & NWFA_T) ? 'T' : '-');
fprintf(stdout, "%c ", (attr & NWFA_P) ? 'P' : '-');
fprintf(stdout, "%s ", (attr & NWFA_RA) ? "Ra" : "--");
fprintf(stdout, "%s ", (attr & NWFA_WA) ? "Wa" : "--");
fprintf(stdout, "%s ", (attr & NWFA_CI) ? "CI" : "--");
fprintf(stdout, "%s ", (attr & NWFA_DI) ? "DI" : "--");
fprintf(stdout, "%s ", (attr & NWFA_RI) ? "RI" : "--");
fprintf(stdout, "]");
}
static void flag_display_one(char *name, uint32 attr)
{
fprintf(stdout, " %-23s ", name);
flag_print_attrs(attr);
fprintf(stdout, "\n");
}
static void flag_display_one_paged(char *name, uint32 attr,
int *line_count, int *continuous)
{
flag_display_one(name, attr);
tool_page_line(line_count, continuous);
}
static int flag_list(char *pattern)
{
struct find_t ff;
unsigned findattr = _A_RDONLY | _A_HIDDEN | _A_SYSTEM | _A_ARCH;
int found = 0;
int line_count = 0;
int continuous = 0;
if (_dos_findfirst(pattern, findattr, &ff))
return(-1);
do {
if (!(ff.attrib & _A_SUBDIR)) {
uint32 nwattrs;
if (flag_ncp87_obtain_attrs(ff.name, &nwattrs))
nwattrs = (uint32)ff.attrib;
flag_display_one_paged(ff.name, nwattrs, &line_count, &continuous);
found++;
}
} while (!_dos_findnext(&ff));
return(found);
}
static int flag_apply(char *pattern, uint32 setbits, uint32 clearbits)
{
struct find_t ff;
unsigned findattr = _A_RDONLY | _A_HIDDEN | _A_SYSTEM | _A_ARCH;
int shown = 0;
if (_dos_findfirst(pattern, findattr, &ff))
return(-1);
do {
uint32 attrs;
uint32 newattrs;
char fname[260];
if (ff.attrib & _A_SUBDIR) continue;
strmaxcpy(fname, ff.name, sizeof(fname) - 1);
if (flag_ncp87_obtain_attrs(fname, &attrs))
attrs = (uint32)ff.attrib;
newattrs = (attrs | (uint32)setbits) & ~((uint32)clearbits);
if (newattrs != attrs) {
if (flag_ncp87_modify_attrs(fname, newattrs)) {
unsigned dosattr = (newattrs & (_A_RDONLY|_A_HIDDEN|_A_SYSTEM|_A_ARCH));
if (_dos_setfileattr(fname, dosattr)) {
fprintf(stderr, "You don't have rights to change : %s\n", fname);
continue;
}
}
}
if (flag_ncp87_obtain_attrs(fname, &attrs))
attrs = newattrs;
flag_display_one(fname, newattrs);
shown++;
} while (!_dos_findnext(&ff));
return(shown);
}
int func_flag(int argc, char *argv[], int mode)
{
char *path = "*.*";
int i;
uint32 setbits = 0;
uint32 clearbits = 0;
int have_change = 0;
int rc;
(void)mode;
if (argc > 1 && (tool_strsame(argv[1], "/?") || tool_strsame(argv[1], "-?") ||
tool_strsame(argv[1], "?"))) {
flag_help();
return(0);
}
if (argc > 1) {
path = argv[1];
if (tool_strsame(path, "SUB")) path = "*.*";
}
for (i = 2; i < argc; i++) {
if (tool_strsame(argv[i], "SUB")) continue;
rc = flag_attr_mask(argv[i], &setbits, &clearbits);
if (rc < 0) return(1);
if (rc > 0) continue;
have_change = 1;
}
if (have_change) {
rc = flag_apply(path, setbits, clearbits);
if (rc < 0) {
fprintf(stderr, "Files could not be found with pattern \"%s\"\n", path);
return(1);
}
return(0);
}
rc = flag_list(path);
if (rc < 0) {
fprintf(stderr, "Files could not be found with pattern \"%s\"\n", path);
return(1);
}
return(0);
}