diff --git a/flag.c b/flag.c index b2467e2..db41cff 100644 --- a/flag.c +++ b/flag.c @@ -3,6 +3,203 @@ #include "net.h" #include +/* + * 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, ®s, ®s); /* 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); }