From ae2e1c306220158e005d51f7686cd0eeffb49ad7 Mon Sep 17 00:00:00 2001 From: Mario Fetka Date: Sat, 23 May 2026 11:38:07 +0200 Subject: [PATCH] flag --- flag.c | 343 ++++++++++++++++++++++++++++++--------------------------- 1 file changed, 182 insertions(+), 161 deletions(-) diff --git a/flag.c b/flag.c index ce59f2e..e1f7e23 100644 --- a/flag.c +++ b/flag.c @@ -4,35 +4,54 @@ #include /* - * NetWare old file-info attributes. - * NCP 23/15 returns FileAttributes byte and ExtendedFileAttributes byte. - * NCP 23/16 writes them back while preserving the rest of the scanned info. + * FLAG v4b: NCP 87 namespace DOS info. * - * This gives us real NetWare flags for: - * S Shareable byte0 bit7 - * T Transactional byte1 bit4 - * RA Read Audit byte1 bit6 - * WA Write Audit byte1 bit7 + * ncpfs reference: + * ncp_ns_modify_entry_dos_info(): + * subfunction 7, namespace DOS, search attrs SA_ALL, + * ModifyInformationMask, struct ncp_dos_info, handle/path. * - * Full 386 byte2 flags P/CI/DI/RI need NCP 87/35 later. + * We use dirstyle=0 (short directory handle) against the current DOS + * directory handle and a one-component DOS filename. */ -#define NWFA_RO 0x0001UL -#define NWFA_H 0x0002UL -#define NWFA_SY 0x0004UL -#define NWFA_A 0x0020UL -#define NWFA_S 0x0080UL -#define NWFA_T 0x1000UL -#define NWFA_RA 0x4000UL -#define NWFA_WA 0x8000UL +#define FLAG_NW_NS_DOS 0x00 +#define FLAG_SA_ALL 0x0006 +#define FLAG_RIM_ATTRIBUTES 0x00000004UL -typedef struct { - uint16 next_index; - char name[15]; - uint8 attr; - uint8 extattr; - uint8 raw[76]; /* file size + dates + owner + archive + reserved */ -} FLAG_NWINFO; +#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) { @@ -50,137 +69,134 @@ static int flag_current_dhandle(uint8 *dhandle) uint8 flags = 0; int drive; - drive = flag_get_current_drive(); /* 0=A */ + 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_ncp23_scan(uint8 dhandle, char *name, FLAG_NWINFO *info) +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 func; - uint8 last[2]; - uint8 dhandle; - uint8 searchattr; - uint8 namelen; - uint8 name[255]; + uint8 data[320]; } req; struct { uint16 len; - uint8 next[2]; - uint8 fname[14]; - uint8 attr; - uint8 extattr; - uint8 raw[76]; + uint8 data[128]; } repl; - int nlen; - - memset(&req, 0, sizeof(req)); - memset(&repl, 0, sizeof(repl)); - - nlen = strlen(name); if (nlen > 255) nlen = 255; - req.func = 0x0f; - req.last[0] = 0xff; - req.last[1] = 0xff; - req.dhandle = dhandle; - req.searchattr = 0x06; /* include hidden/system */ - req.namelen = (uint8)nlen; - memcpy(req.name, name, nlen); - req.len = 6 + nlen; - - repl.len = sizeof(repl) - sizeof(uint16); - - neterrno = Net_Call(0xE300, &req, &repl); - if (neterrno) return(-1); - - if (info) { - info->next_index = GET_16(repl.next); - memcpy(info->name, repl.fname, 14); - info->name[14] = '\0'; - info->attr = repl.attr; - info->extattr = repl.extattr; - memcpy(info->raw, repl.raw, sizeof(info->raw)); - } - - return(0); -} - -static int flag_ncp23_set(uint8 dhandle, char *name, FLAG_NWINFO *info, uint32 attrs) -{ - struct { - uint16 len; - uint8 func; - uint8 attr; - uint8 extattr; - uint8 raw[76]; - uint8 dhandle; - uint8 searchattr; - uint8 namelen; - uint8 name[255]; - } req; - struct { - uint16 len; - } repl; - int nlen; - - memset(&req, 0, sizeof(req)); - memset(&repl, 0, sizeof(repl)); - - nlen = strlen(name); if (nlen > 255) nlen = 255; - - req.func = 0x10; - req.attr = (uint8)(attrs & 0xff); - req.extattr = (uint8)((attrs >> 8) & 0xff); - memcpy(req.raw, info->raw, sizeof(req.raw)); - req.dhandle = dhandle; - req.searchattr = 0x06; - req.namelen = (uint8)nlen; - memcpy(req.name, name, nlen); - req.len = 82 + nlen; - - repl.len = 0; - - neterrno = Net_Call(0xE300, &req, &repl); - if (neterrno) return(-1); - - return(0); -} - -static int flag_get_nw_attrs(char *name, uint32 *attrs, FLAG_NWINFO *info) -{ uint8 dhandle = 0; - FLAG_NWINFO local; + uint8 *p; + int hlen; if (flag_current_dhandle(&dhandle)) return(-1); - if (!info) info = &local; + memset(&req, 0, sizeof(req)); + memset(&repl, 0, sizeof(repl)); - if (flag_ncp23_scan(dhandle, name, info)) + 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(0x5700, &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 = ((uint32)info->attr) | (((uint32)info->extattr) << 8); + *attrs = flag_get_dword_lh(repl.data); return(0); } -static int flag_set_nw_attrs(char *name, uint32 attrs) +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; - FLAG_NWINFO info; + uint8 *p; + int hlen; if (flag_current_dhandle(&dhandle)) return(-1); - if (flag_ncp23_scan(dhandle, name, &info)) + 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(0x5700, &req, &repl); + if (neterrno) return(-1); - return(flag_ncp23_set(dhandle, name, &info, attrs)); + return(0); } @@ -258,45 +274,53 @@ static int flag_attr_mask(char *s, unsigned *setbits, unsigned *clearbits) if (flag_same(p, "RO")) { if (set) { - *setbits |= NWFA_RO; - /* - * Novell FLAG also shows DI/RI for +RO on real NetWare. - * Those are byte2 flags and need NCP87/35 later. - */ - } else *clearbits |= NWFA_RO; + *setbits |= (unsigned)(NWFA_RO | NWFA_DI | NWFA_RI); + } else { + *clearbits |= (unsigned)(NWFA_RO | NWFA_DI | NWFA_RI); + } } else if (flag_same(p, "RW")) { - *clearbits |= NWFA_RO; + *clearbits |= (unsigned)(NWFA_RO | NWFA_DI | NWFA_RI); } else if (flag_same(p, "S")) { - if (set) *setbits |= NWFA_S; - else *clearbits |= NWFA_S; + if (set) *setbits |= (unsigned)NWFA_S; + else *clearbits |= (unsigned)NWFA_S; } else if (flag_same(p, "H")) { - if (set) *setbits |= NWFA_H; - else *clearbits |= NWFA_H; + 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 |= NWFA_SY; - else *clearbits |= NWFA_SY; + if (set) *setbits |= (unsigned)NWFA_SY; + else *clearbits |= (unsigned)NWFA_SY; } else if (flag_same(p, "T")) { - if (set) *setbits |= NWFA_T; - else *clearbits |= NWFA_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 |= NWFA_A; - else *clearbits |= NWFA_A; + if (set) *setbits |= (unsigned)NWFA_A; + else *clearbits |= (unsigned)NWFA_A; } else if (flag_same(p, "RA")) { - if (set) *setbits |= NWFA_RA; - else *clearbits |= NWFA_RA; + if (set) *setbits |= (unsigned)NWFA_RA; + else *clearbits |= (unsigned)NWFA_RA; } else if (flag_same(p, "WA")) { - if (set) *setbits |= NWFA_WA; - else *clearbits |= NWFA_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 |= (NWFA_RO | NWFA_H | NWFA_SY | NWFA_A | - NWFA_S | NWFA_T | NWFA_RA | NWFA_WA); + *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")) { - *setbits |= (NWFA_RO | NWFA_H | NWFA_SY | NWFA_A | - NWFA_S | NWFA_T | NWFA_RA | NWFA_WA); - } else if (flag_same(p, "P") || 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); @@ -318,12 +342,12 @@ static void flag_print_attrs(unsigned attr) fprintf(stdout, "%c ", (attr & NWFA_H) ? 'H' : '-'); fprintf(stdout, "%s ", (attr & NWFA_SY) ? "Sy" : "-"); fprintf(stdout, "%c ", (attr & NWFA_T) ? 'T' : '-'); - fprintf(stdout, "-- "); /* P needs NCP87 */ + fprintf(stdout, "%c ", (attr & NWFA_P) ? 'P' : '-'); fprintf(stdout, "%s ", (attr & NWFA_RA) ? "Ra" : "--"); fprintf(stdout, "%s ", (attr & NWFA_WA) ? "Wa" : "--"); - fprintf(stdout, "-- "); /* CI needs NCP87 */ - fprintf(stdout, "-- "); /* DI needs NCP87 */ - fprintf(stdout, "-- "); /* RI needs NCP87 */ + fprintf(stdout, "%s ", (attr & NWFA_CI) ? "CI" : "--"); + fprintf(stdout, "%s ", (attr & NWFA_DI) ? "DI" : "--"); + fprintf(stdout, "%s ", (attr & NWFA_RI) ? "RI" : "--"); fprintf(stdout, "]"); } @@ -356,7 +380,7 @@ static int flag_list(char *pattern) if (!(ff.attrib & _A_SUBDIR)) { uint32 nwattrs; - if (flag_get_nw_attrs(ff.name, &nwattrs, NULL)) + if (flag_ncp87_obtain_attrs(ff.name, &nwattrs)) nwattrs = (uint32)ff.attrib; flag_display_one(ff.name, (unsigned)nwattrs); @@ -385,16 +409,13 @@ static int flag_apply(char *pattern, unsigned setbits, unsigned clearbits) strmaxcpy(fname, ff.name, sizeof(fname) - 1); - if (flag_get_nw_attrs(fname, &attrs, NULL)) + if (flag_ncp87_obtain_attrs(fname, &attrs)) attrs = (uint32)ff.attrib; - newattrs = (attrs | setbits) & ~clearbits; + newattrs = (attrs | (uint32)setbits) & ~((uint32)clearbits); if (newattrs != attrs) { - if (flag_set_nw_attrs(fname, newattrs)) { - /* - * Fallback for local/DOS-visible bits. This keeps old behavior alive. - */ + 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); @@ -403,7 +424,7 @@ static int flag_apply(char *pattern, unsigned setbits, unsigned clearbits) } } - if (flag_get_nw_attrs(fname, &attrs, NULL)) + if (flag_ncp87_obtain_attrs(fname, &attrs)) attrs = newattrs; flag_display_one(fname, (unsigned)attrs);