/* flag.c - Novell FLAG-like DOS utility, stage 1 */ #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 #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 int flag_same(char *a, char *b) { while (*a || *b) { int ca = *a++; int cb = *b++; if (ca >= 'a' && ca <= 'z') ca -= 32; if (cb >= 'a' && cb <= 'z') cb -= 32; if (ca != cb) return(0); } return(1); } 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, unsigned *setbits, unsigned *clearbits) { int set = 1; char *p = s; if (*p == '+') { set = 1; p++; } else if (*p == '-') { set = 0; p++; } if (!*p) return(-1); 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; } else if (flag_same(p, "RW")) { *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 |= NWFA_H; else *clearbits |= 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; } else if (flag_same(p, "T")) { if (set) *setbits |= NWFA_T; else *clearbits |= NWFA_T; } else if (flag_same(p, "A")) { 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 |= (NWFA_RO | NWFA_H | NWFA_SY | NWFA_A | NWFA_S | NWFA_T | NWFA_RA | NWFA_WA); } 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); } else { fprintf(stderr, "Unknown attribute encountered in command line.\n"); return(-1); } return(0); } 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 & 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, "]"); } static void flag_display_one(char *name, unsigned attr) { fprintf(stdout, " %-23s ", name); flag_print_attrs(attr); fprintf(stdout, "\n"); } static int flag_has_wildcards(char *s) { while (*s) { if (*s == '*' || *s == '?') return(1); s++; } return(0); } static int flag_list(char *pattern) { struct find_t ff; unsigned findattr = _A_RDONLY | _A_HIDDEN | _A_SYSTEM | _A_ARCH; int found = 0; if (_dos_findfirst(pattern, findattr, &ff)) return(-1); do { if (!(ff.attrib & _A_SUBDIR)) { 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)); return(found); } 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 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_get_nw_attrs(fname, &attrs, NULL)) attrs = (uint32)ff.attrib; newattrs = (attrs | setbits) & ~clearbits; 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; } } } if (flag_get_nw_attrs(fname, &attrs, NULL)) attrs = newattrs; flag_display_one(fname, (unsigned)attrs); shown++; } while (!_dos_findnext(&ff)); return(shown); } int func_flag(int argc, char *argv[], int mode) { char *path = "*.*"; int i; unsigned setbits = 0; unsigned clearbits = 0; int have_change = 0; int rc; (void)mode; if (argc > 1 && (flag_same(argv[1], "/?") || flag_same(argv[1], "-?") || flag_same(argv[1], "?"))) { flag_help(); return(0); } if (argc > 1) { path = argv[1]; if (flag_same(path, "SUB")) path = "*.*"; } for (i = 2; i < argc; i++) { if (flag_same(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); }