diff --git a/flag.c b/flag.c index 8bc3837..1079031 100644 --- a/flag.c +++ b/flag.c @@ -3,6 +3,176 @@ #include "net.h" #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. + * + * 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 + * + * Full 386 byte2 flags P/CI/DI/RI need NCP 87/35 later. + */ +#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 + +typedef struct { + uint16 next_index; + char name[15]; + uint8 attr; + uint8 extattr; + uint8 raw[76]; /* file size + dates + owner + archive + reserved */ +} FLAG_NWINFO; + +static int flag_current_dhandle(uint8 *dhandle) +{ + uint8 connid = 0; + uint8 flags = 0; + int drive; + + drive = getdisk(); /* 0=A */ + 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) +{ + struct { + uint16 len; + uint8 func; + uint8 last[2]; + uint8 dhandle; + uint8 searchattr; + uint8 namelen; + uint8 name[255]; + } req; + struct { + uint16 len; + uint8 next[2]; + uint8 fname[14]; + uint8 attr; + uint8 extattr; + uint8 raw[76]; + } repl; + int nlen; + + memset(&req, 0, sizeof(req)); + memset(&repl, 0, sizeof(repl)); + + nlen = min(255, strlen(name)); + 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 = min(255, strlen(name)); + + 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; + + if (flag_current_dhandle(&dhandle)) + return(-1); + + if (!info) info = &local; + + if (flag_ncp23_scan(dhandle, name, info)) + return(-1); + + if (attrs) + *attrs = ((uint32)info->attr) | (((uint32)info->extattr) << 8); + + return(0); +} + +static int flag_set_nw_attrs(char *name, uint32 attrs) +{ + uint8 dhandle = 0; + FLAG_NWINFO info; + + if (flag_current_dhandle(&dhandle)) + return(-1); + + if (flag_ncp23_scan(dhandle, name, &info)) + return(-1); + + return(flag_ncp23_set(dhandle, name, &info, attrs)); +} + + #ifndef _A_NORMAL #define _A_NORMAL 0x00 #endif @@ -76,29 +246,43 @@ 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 |= 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; } else if (flag_same(p, "RW")) { - *clearbits |= _A_RDONLY; + *clearbits |= NWFA_RO; + } else if (flag_same(p, "S")) { + if (set) *setbits |= NWFA_S; + else *clearbits |= NWFA_S; } else if (flag_same(p, "H")) { - if (set) *setbits |= _A_HIDDEN; - else *clearbits |= _A_HIDDEN; + if (set) *setbits |= NWFA_H; + else *clearbits |= 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 |= NWFA_SY; + else *clearbits |= NWFA_SY; + } else if (flag_same(p, "T")) { + if (set) *setbits |= NWFA_T; + else *clearbits |= NWFA_T; } else if (flag_same(p, "A")) { - if (set) *setbits |= _A_ARCH; - else *clearbits |= _A_ARCH; + if (set) *setbits |= NWFA_A; + else *clearbits |= NWFA_A; + } else if (flag_same(p, "RA")) { + if (set) *setbits |= NWFA_RA; + else *clearbits |= NWFA_RA; + } else if (flag_same(p, "WA")) { + if (set) *setbits |= NWFA_WA; + else *clearbits |= NWFA_WA; } else if (flag_same(p, "N") || flag_same(p, "NORMAL")) { - *clearbits |= (_A_RDONLY | _A_HIDDEN | _A_SYSTEM | _A_ARCH); + *clearbits |= (NWFA_RO | NWFA_H | NWFA_SY | NWFA_A | + NWFA_S | NWFA_T | NWFA_RA | NWFA_WA); } 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") || + *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); @@ -113,25 +297,22 @@ static int flag_attr_mask(char *s, unsigned *setbits, unsigned *clearbits) static void flag_print_attrs(unsigned attr) { /* - * Novell FLAG display order is not the same as help order. - * Observed output: - * [ Rw - A H Sy - -- -- -- -- DI RI ] - * Order: - * RO/RW, S, A, H, Sy, T, P, RA, WA, CI, DI, RI + * 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_ARCH) ? 'A' : '-'); - fprintf(stdout, "%c ", (attr & _A_HIDDEN) ? 'H' : '-'); - fprintf(stdout, "%s ", (attr & _A_SYSTEM) ? "Sy" : "-"); - fprintf(stdout, "- "); /* T */ - fprintf(stdout, "-- "); /* P */ - 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, "-- "); /* P needs NCP87 */ + 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, "]"); } @@ -162,7 +343,12 @@ static int flag_list(char *pattern) do { if (!(ff.attrib & _A_SUBDIR)) { - flag_display_one(ff.name, ff.attrib); + uint32 nwattrs; + + if (flag_get_nw_attrs(ff.name, &nwattrs, NULL)) + nwattrs = (uint32)ff.attrib; + + flag_display_one(ff.name, (unsigned)nwattrs); found++; } } while (!_dos_findnext(&ff)); @@ -180,32 +366,36 @@ static int flag_apply(char *pattern, unsigned setbits, unsigned clearbits) 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_get_nw_attrs(fname, &attrs, NULL)) + attrs = (uint32)ff.attrib; - newattr = (attr | setbits) & ~clearbits; + newattrs = (attrs | setbits) & ~clearbits; - if (newattr != attr) { - if (_dos_setfileattr(fname, newattr)) { - fprintf(stderr, "You don't have rights to change : %s\n", fname); - continue; + if (newattrs != attrs) { + if (flag_set_nw_attrs(fname, newattrs)) { + /* + * Fallback for local/DOS-visible bits. This keeps old behavior alive. + */ + 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; + } } - attr = newattr; } - /* - * Novell FLAG prints the resulting file entry after the command. - */ - flag_display_one(fname, attr); + if (flag_get_nw_attrs(fname, &attrs, NULL)) + attrs = newattrs; + + flag_display_one(fname, (unsigned)attrs); shown++; } while (!_dos_findnext(&ff));