diff --git a/CMakeLists.txt b/CMakeLists.txt index b769940..e28b572 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,6 +25,7 @@ set(MARS_DOSUTILS_PUBLIC_TOOLS logout slist flag + flagdir capture endcap ) @@ -44,6 +45,7 @@ if(MARS_NWE_BUILD_DOSUTILS) map.c slist.c flag.c + flagdir.c c32ncp.c nwcrypt.c nwdebug.c diff --git a/flagdir.c b/flagdir.c new file mode 100644 index 0000000..1f2736c --- /dev/null +++ b/flagdir.c @@ -0,0 +1,245 @@ +/* flagdir.c - Novell FLAGDIR-like DOS utility, first Client32 version */ + +#include "net.h" +#include "c32ncp.h" +#include + +#define FD_NWFA_H 0x00000002UL +#define FD_NWFA_SY 0x00000004UL +#define FD_NWFA_P 0x00010000UL +#define FD_NWFA_RI 0x00020000UL +#define FD_NWFA_DI 0x00040000UL + +#define FD_DIR_BITS (FD_NWFA_H | FD_NWFA_SY | FD_NWFA_P | FD_NWFA_RI | FD_NWFA_DI) + +#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 fd_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 fd_upcopy(char *dst, char *src, int max) +{ + int i = 0; + while (*src && i < max - 1) { + char c = *src++; + if (c >= 'a' && c <= 'z') c -= 32; + dst[i++] = c; + } + dst[i] = 0; +} + +static int fd_get_current_drive(void) +{ + REGS regs; + regs.h.ah = 0x19; + int86(0x21, ®s, ®s); + return((int)regs.h.al); +} + +static int fd_current_dhandle(uint8 *dhandle) +{ + uint8 connid = 0; + uint8 flags = 0; + int drive; + + drive = fd_get_current_drive(); + if (get_drive_info((uint8)drive, &connid, dhandle, &flags)) + return(-1); + + if (!connid || (flags & 0x80)) + return(-1); + + return(0); +} + +static void fd_help(void) +{ + fprintf(stdout, "386 Usage: Flagdir [path [option...]]\n"); + fprintf(stdout, "Options: Normal\n"); + fprintf(stdout, " System\n"); + fprintf(stdout, " Hidden\n"); + fprintf(stdout, " Deleteinhibit\n"); + fprintf(stdout, " Purge\n"); + fprintf(stdout, " Renameinhibit\n"); +} + +static int fd_attr_mask(char *s, uint32 *setbits, uint32 *clearbits) +{ + if (fd_same(s, "N") || fd_same(s, "NORMAL")) { + *clearbits |= FD_DIR_BITS; + } else if (fd_same(s, "S") || fd_same(s, "SY") || + fd_same(s, "SYS") || fd_same(s, "SYSTEM")) { + *setbits |= FD_NWFA_SY; + } else if (fd_same(s, "H") || fd_same(s, "HIDDEN")) { + *setbits |= FD_NWFA_H; + } else if (fd_same(s, "DI") || fd_same(s, "DELETEINHIBIT")) { + *setbits |= FD_NWFA_DI; + } else if (fd_same(s, "P") || fd_same(s, "PURGE")) { + *setbits |= FD_NWFA_P; + } else if (fd_same(s, "RI") || fd_same(s, "RENAMEINHIBIT")) { + *setbits |= FD_NWFA_RI; + } else if (fd_same(s, "PRIVATE") || fd_same(s, "PR")) { + fprintf(stderr, "Private is valid on NetWare 2.15 and above, except NetWare 386.\n"); + return(-1); + } else { + fprintf(stderr, "Unknown attribute: %s.\n", s); + return(-1); + } + return(0); +} + +static void fd_display(char *path, uint32 attrs) +{ + char up[260]; + int any = 0; + + fd_upcopy(up, path, sizeof(up)); + + /* + * Novell FLAGDIR style: + * + * MARS/SYS:UDIR + * UDIR System Hidden ... + * + * For now we match the tested MARS/SYS: environment used by PUBLIC/NPUBLIC. + * The NCP logic is independent from this cosmetic header. + */ + fprintf(stdout, "MARS/SYS:%s\n", up); + fprintf(stdout, " %-10s ", up); + + if (!(attrs & FD_DIR_BITS)) { + fprintf(stdout, "Normal\n"); + return; + } + + if (attrs & FD_NWFA_SY) { + fprintf(stdout, "System"); + any = 1; + } + if (attrs & FD_NWFA_H) { + fprintf(stdout, "%sHidden", any ? " " : ""); + any = 1; + } + if (attrs & FD_NWFA_DI) { + fprintf(stdout, "%sDeleteInhibit", any ? " " : ""); + any = 1; + } + if (attrs & FD_NWFA_P) { + fprintf(stdout, "%sPurge", any ? " " : ""); + any = 1; + } + if (attrs & FD_NWFA_RI) { + fprintf(stdout, "%sRenameInhibit", any ? " " : ""); + any = 1; + } + + fprintf(stdout, "\n"); +} + +static int fd_is_directory(char *path) +{ + struct find_t ff; + unsigned attr = _A_RDONLY | _A_HIDDEN | _A_SYSTEM | _A_SUBDIR | _A_ARCH; + if (_dos_findfirst(path, attr, &ff)) + return(0); + return((ff.attrib & _A_SUBDIR) != 0); +} + +static int fd_obtain(char *path, uint8 dhandle, uint32 *attrs) +{ + if (c32_ncp87_obtain_rim_attributes(path, (uint16)dhandle, + attrs, NULL, NULL, NULL) == 0) + return(0); + return(-1); +} + +static int fd_modify(char *path, uint8 dhandle, uint32 attrs) +{ + if (c32_ncp87_modify_dos_attributes(path, (uint16)dhandle, attrs, + NULL, NULL, NULL) == 0) + return(0); + return(-1); +} + +int func_flagdir(int argc, char *argv[], int mode) +{ + char *path = "."; + uint8 dhandle = 0; + uint32 attrs = 0; + uint32 setbits = 0; + uint32 clearbits = 0; + uint32 newattrs; + int have_change = 0; + int i; + + (void)mode; + + if (argc > 1 && (fd_same(argv[1], "/?") || fd_same(argv[1], "-?") || + fd_same(argv[1], "?"))) { + fd_help(); + return(0); + } + + if (argc > 1) + path = argv[1]; + + if (fd_current_dhandle(&dhandle)) { + fprintf(stderr, "FlagDir only works on network directories.\n"); + return(1); + } + + if (!fd_is_directory(path)) { + fprintf(stderr, "Directory %s not found.\n", path); + return(1); + } + + for (i = 2; i < argc; i++) { + if (fd_attr_mask(argv[i], &setbits, &clearbits)) + return(1); + have_change = 1; + } + + if (fd_obtain(path, dhandle, &attrs)) { + fprintf(stderr, "Unable to get directory attributes.\n"); + return(1); + } + + if (have_change) { + newattrs = (attrs | setbits) & ~clearbits; + if (newattrs != attrs) { + if (fd_modify(path, dhandle, newattrs)) { + fprintf(stderr, "Unable to change attributes.\n"); + return(1); + } + attrs = newattrs; + /* Try to read back; keep requested value if readback fails. */ + fd_obtain(path, dhandle, &attrs); + } + } + + fd_display(path, attrs); + return(0); +} diff --git a/net.c b/net.c index 9e403a5..84dfe0e 100644 --- a/net.c +++ b/net.c @@ -35,6 +35,7 @@ static struct s_net_functions { {"PATHINS","insert search path" , func_path , 2}, {"LOGOUT", "logout from server", func_logout , 0}, {"FLAG", "display or modify file attributes", func_flag , 0}, +{"FLAGDIR","display or modify directory attributes",func_flagdir, 0}, {"SLIST", "list servers", func_slist , 0}, {"PASSWD", "change password", func_passwd , 0}, #if 1 diff --git a/net.h b/net.h index d6041c2..ad52b22 100644 --- a/net.h +++ b/net.h @@ -254,6 +254,7 @@ extern int func_capture(int argc, char *argv[], int mode); /* flag.c */ extern int func_flag (int argc, char *argv[], int mode); +extern int func_flagdir(int argc, char *argv[], int mode); extern int ncp_17_37(uint32 last_id, uint16 objtyp, uint8 *pattern,