feat: implement FLAG command handling

This commit is contained in:
Mario Fetka
2026-05-23 10:19:30 +02:00
parent 8b6685c501
commit 3a5b08a4bf

330
flag.c
View File

@@ -3,6 +3,203 @@
#include "net.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_get_current_drive(void)
{
REGS regs;
regs.h.ah = 0x19; /* DOS get current default drive */
int86(0x21, &regs, &regs); /* AL = 0 for A:, 1 for B:, ... */
return((int)regs.h.al);
}
static int flag_current_dhandle(uint8 *dhandle)
{
uint8 connid = 0;
uint8 flags = 0;
int drive;
drive = flag_get_current_drive();
if (get_drive_info((uint8)drive, &connid, dhandle, &flags))
return(-1);
if (!connid || (flags & 0x80))
return(-1);
return(0);
}
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 dhandle = 0;
uint8 *p;
int hlen;
if (flag_current_dhandle(&dhandle))
return(-1);
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 dhandle = 0;
uint8 *p;
int hlen;
if (flag_current_dhandle(&dhandle))
return(-1);
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
@@ -76,32 +273,54 @@ static int flag_attr_mask(char *s, unsigned *setbits, unsigned *clearbits)
if (!*p) return(-1);
if (flag_same(p, "RO")) {
if (set) *setbits |= _A_RDONLY;
else *clearbits |= _A_RDONLY;
if (set) {
*setbits |= (unsigned)(NWFA_RO | NWFA_DI | NWFA_RI);
} else {
*clearbits |= (unsigned)(NWFA_RO | NWFA_DI | NWFA_RI);
}
} else if (flag_same(p, "RW")) {
*clearbits |= _A_RDONLY;
*clearbits |= (unsigned)(NWFA_RO | NWFA_DI | NWFA_RI);
} else if (flag_same(p, "S")) {
if (set) *setbits |= (unsigned)NWFA_S;
else *clearbits |= (unsigned)NWFA_S;
} else if (flag_same(p, "H")) {
if (set) *setbits |= _A_HIDDEN;
else *clearbits |= _A_HIDDEN;
if (set) *setbits |= (unsigned)NWFA_H;
else *clearbits |= (unsigned)NWFA_H;
} else if (flag_same(p, "SY") || flag_same(p, "SYS") || flag_same(p, "SYSTEM")) {
if (set) *setbits |= _A_SYSTEM;
else *clearbits |= _A_SYSTEM;
if (set) *setbits |= (unsigned)NWFA_SY;
else *clearbits |= (unsigned)NWFA_SY;
} else if (flag_same(p, "T")) {
if (set) *setbits |= (unsigned)NWFA_T;
else *clearbits |= (unsigned)NWFA_T;
} else if (flag_same(p, "P")) {
if (set) *setbits |= (unsigned)NWFA_P;
else *clearbits |= (unsigned)NWFA_P;
} else if (flag_same(p, "A")) {
if (set) *setbits |= _A_ARCH;
else *clearbits |= _A_ARCH;
if (set) *setbits |= (unsigned)NWFA_A;
else *clearbits |= (unsigned)NWFA_A;
} else if (flag_same(p, "RA")) {
if (set) *setbits |= (unsigned)NWFA_RA;
else *clearbits |= (unsigned)NWFA_RA;
} else if (flag_same(p, "WA")) {
if (set) *setbits |= (unsigned)NWFA_WA;
else *clearbits |= (unsigned)NWFA_WA;
} else if (flag_same(p, "CI")) {
if (set) *setbits |= (unsigned)NWFA_CI;
else *clearbits |= (unsigned)NWFA_CI;
} else if (flag_same(p, "DI")) {
if (set) *setbits |= (unsigned)NWFA_DI;
else *clearbits |= (unsigned)NWFA_DI;
} else if (flag_same(p, "RI")) {
if (set) *setbits |= (unsigned)NWFA_RI;
else *clearbits |= (unsigned)NWFA_RI;
} else if (flag_same(p, "N") || flag_same(p, "NORMAL")) {
*clearbits |= (_A_RDONLY | _A_HIDDEN | _A_SYSTEM | _A_ARCH);
*clearbits |= (unsigned)(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 (flag_same(p, "ALL")) {
/*
* Stage 1: Only DOS-visible bits are supported. NetWare-only bits
* like S/T/P/RA/WA/CI/DI/RI need NCP support later.
*/
*setbits |= (_A_RDONLY | _A_HIDDEN | _A_SYSTEM | _A_ARCH);
} else if (flag_same(p, "S") || flag_same(p, "T") || flag_same(p, "P") ||
flag_same(p, "RA") || flag_same(p, "WA") || flag_same(p, "CI") ||
flag_same(p, "DI") || flag_same(p, "RI")) {
fprintf(stderr, "Attribute not supported on this version of NetWare\n");
return(1);
*setbits |= (unsigned)(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);
@@ -112,19 +331,23 @@ static int flag_attr_mask(char *s, unsigned *setbits, unsigned *clearbits)
static void flag_print_attrs(unsigned attr)
{
/*
* Novell order:
* RO/RW S A H Sy T P RA WA CI DI RI
*/
fprintf(stdout, "[ ");
fprintf(stdout, "%s ", (attr & _A_RDONLY) ? "RO" : "Rw");
fprintf(stdout, "- "); /* S Shareable */
fprintf(stdout, "%c ", (attr & _A_HIDDEN) ? 'H' : '-');
fprintf(stdout, "%s ", (attr & _A_SYSTEM) ? "Sy" : "-");
fprintf(stdout, "- "); /* T */
fprintf(stdout, "- "); /* P */
fprintf(stdout, "%c ", (attr & _A_ARCH) ? 'A' : '-');
fprintf(stdout, "-- "); /* RA */
fprintf(stdout, "-- "); /* WA */
fprintf(stdout, "-- "); /* CI */
fprintf(stdout, "-- "); /* DI */
fprintf(stdout, "-- "); /* RI */
fprintf(stdout, "%s ", (attr & NWFA_RO) ? "RO" : "Rw");
fprintf(stdout, "%c ", (attr & NWFA_S) ? 'S' : '-');
fprintf(stdout, "%c ", (attr & NWFA_A) ? 'A' : '-');
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, "]");
}
@@ -155,7 +378,12 @@ static int flag_list(char *pattern)
do {
if (!(ff.attrib & _A_SUBDIR)) {
flag_display_one(ff.name, ff.attrib);
uint32 nwattrs;
if (flag_ncp87_obtain_attrs(ff.name, &nwattrs))
nwattrs = (uint32)ff.attrib;
flag_display_one(ff.name, (unsigned)nwattrs);
found++;
}
} while (!_dos_findnext(&ff));
@@ -167,36 +395,44 @@ static int flag_apply(char *pattern, unsigned setbits, unsigned clearbits)
{
struct find_t ff;
unsigned findattr = _A_RDONLY | _A_HIDDEN | _A_SYSTEM | _A_ARCH;
int changed = 0;
int shown = 0;
if (_dos_findfirst(pattern, findattr, &ff))
return(-1);
do {
unsigned attr;
unsigned newattr;
uint32 attrs;
uint32 newattrs;
char fname[260];
if (ff.attrib & _A_SUBDIR) continue;
strmaxcpy(fname, ff.name, sizeof(fname) - 1);
if (_dos_getfileattr(fname, &attr)) {
attr = ff.attrib;
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 = (unsigned)(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;
}
}
}
newattr = (attr | setbits) & ~clearbits;
if (flag_ncp87_obtain_attrs(fname, &attrs))
attrs = newattrs;
if (newattr != attr) {
if (!_dos_setfileattr(fname, newattr))
changed++;
else
fprintf(stderr, "You don't have rights to change : %s\n", fname);
}
flag_display_one(fname, (unsigned)attrs);
shown++;
} while (!_dos_findnext(&ff));
return(changed);
return(shown);
}
int func_flag(int argc, char *argv[], int mode)
@@ -237,8 +473,6 @@ int func_flag(int argc, char *argv[], int mode)
return(1);
}
if (rc) fprintf(stdout, "Changed some\n");
else fprintf(stdout, "None changed\n");
return(0);
}