Move common little-endian and big-endian buffer helpers into tools.c and declare them in net.h. Replace local duplicate implementations in FLAG, FLAGDIR and NDIR with the shared helpers. This keeps the existing packet layouts unchanged while reducing copy/paste code across the DOS utilities. NCOPY and the experimental NCP copy code are intentionally left untouched for now.
715 lines
17 KiB
C
715 lines
17 KiB
C
/*
|
|
* mars-nwe-dosutils - NetWare/DOS utility tools.
|
|
*
|
|
* Copyright (C) 2026 Mario Fetka
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version 2
|
|
* of the License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
/*
|
|
* Purpose: FLAG utility for displaying and changing NetWare DOS file attributes.
|
|
* Depends on: net.h, c32ncp.h, netcall.c requester helpers, c32ncp.c namespace/NCP helpers, tools.c shared utility routines.
|
|
*/
|
|
/* flag.c - Novell FLAG-like DOS utility, stage 1 */
|
|
|
|
#include "net.h"
|
|
#include "c32ncp.h"
|
|
#include <dos.h>
|
|
|
|
/*
|
|
* 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 FLAG_DM_ATTRIBUTES 0x00000002UL
|
|
|
|
#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 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;
|
|
tool_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 connid = 0;
|
|
uint8 dhandle = 0;
|
|
uint8 *p;
|
|
int hlen;
|
|
|
|
if (tool_current_dhandle(&connid, &dhandle))
|
|
return(-1);
|
|
|
|
/*
|
|
* Prefer the verified Client32 NCP87 path. If it is not available,
|
|
* fall back to the historical INT 21h/Net_Call path below.
|
|
*/
|
|
if (c32_ncp87_obtain_rim_attributes(name, (uint16)dhandle,
|
|
attrs, NULL, NULL, NULL) == 0)
|
|
return(0);
|
|
|
|
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 */
|
|
tool_put_word_lh(p, FLAG_SA_ALL); p += 2;
|
|
tool_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 = tool_get_dword_lh(repl.data);
|
|
|
|
return(0);
|
|
}
|
|
|
|
|
|
static int flag_copy_ncp22_name(uint8 *dst, char *src, uint8 *len_out)
|
|
{
|
|
char tmp[260];
|
|
int len;
|
|
|
|
if (!dst || !len_out)
|
|
return(-1);
|
|
if (!src)
|
|
src = "";
|
|
|
|
tool_upcopy(tmp, src, sizeof(tmp));
|
|
if (strchr(tmp, '\\') || strchr(tmp, '/') || strchr(tmp, ':'))
|
|
return(-1);
|
|
|
|
len = strlen(tmp);
|
|
if (len < 1 || len > 12)
|
|
return(-1);
|
|
|
|
memcpy(dst, tmp, len);
|
|
*len_out = (uint8)len;
|
|
return(0);
|
|
}
|
|
|
|
|
|
static int flag_ncp22_1e_obtain_attrs(char *name, uint32 *attrs)
|
|
{
|
|
struct {
|
|
uint16 len;
|
|
uint8 func;
|
|
uint8 dirhandle;
|
|
uint8 search_attributes;
|
|
uint8 searchsequence[4];
|
|
uint8 namlen;
|
|
uint8 name[12];
|
|
} req;
|
|
struct {
|
|
uint16 len;
|
|
uint8 data[128];
|
|
} repl;
|
|
uint8 connid = 0;
|
|
uint8 dhandle = 0;
|
|
uint8 namlen = 0;
|
|
|
|
if (tool_current_dhandle(&connid, &dhandle))
|
|
return(-1);
|
|
|
|
memset(&req, 0, sizeof(req));
|
|
memset(&repl, 0, sizeof(repl));
|
|
|
|
if (flag_copy_ncp22_name(req.name, name, &namlen))
|
|
return(-1);
|
|
|
|
req.func = 0x1e; /* Scan directory */
|
|
req.dirhandle = dhandle;
|
|
req.search_attributes = 0x06; /* hidden/system */
|
|
U32_TO_BE32(0xffffffffUL, req.searchsequence);
|
|
req.namlen = namlen;
|
|
req.len = (uint16)(1 + 1 + 1 + 4 + 1 + namlen);
|
|
repl.len = sizeof(repl.data);
|
|
|
|
neterrno = Net_Call(0xE200, &req, &repl);
|
|
if (neterrno)
|
|
return(-1);
|
|
|
|
/*
|
|
* NCP22/30 Scan Directory returns:
|
|
* dword searchsequence
|
|
* dword subdir
|
|
* dword attributes
|
|
* ...
|
|
*/
|
|
if (attrs)
|
|
*attrs = tool_get_dword_lh(repl.data + 8);
|
|
|
|
return(0);
|
|
}
|
|
|
|
static int flag_ncp22_25_modify_attrs(char *name, uint32 attrs)
|
|
{
|
|
struct {
|
|
uint16 len;
|
|
uint8 func;
|
|
uint8 dirhandle;
|
|
uint8 search_attributes;
|
|
uint8 searchsequence[4];
|
|
uint8 change_bits[4];
|
|
uint8 subdir[4];
|
|
uint8 attributes[4];
|
|
uint8 uniqueid;
|
|
uint8 flags;
|
|
uint8 namespace;
|
|
uint8 namlen;
|
|
uint8 name[12];
|
|
uint8 rest[104];
|
|
} req;
|
|
struct {
|
|
uint16 len;
|
|
} repl;
|
|
uint8 connid = 0;
|
|
uint8 dhandle = 0;
|
|
|
|
if (tool_current_dhandle(&connid, &dhandle))
|
|
return(-1);
|
|
|
|
memset(&req, 0, sizeof(req));
|
|
memset(&repl, 0, sizeof(repl));
|
|
|
|
req.func = 0x25; /* Set directory/file information */
|
|
req.dirhandle = dhandle;
|
|
req.search_attributes = 0x06; /* hidden/system */
|
|
U32_TO_BE32(0xffffffffUL, req.searchsequence);
|
|
U32_TO_32(FLAG_DM_ATTRIBUTES, req.change_bits);
|
|
U32_TO_32(attrs, req.attributes);
|
|
|
|
if (flag_copy_ncp22_name(req.name, name, &req.namlen))
|
|
return(-1);
|
|
|
|
req.len = sizeof(req) - sizeof(req.len);
|
|
|
|
neterrno = Net_Call(0xE200, &req, &repl);
|
|
if (neterrno)
|
|
return(-1);
|
|
|
|
return(0);
|
|
}
|
|
|
|
|
|
static int flag_obtain_attrs(char *name, uint32 *attrs)
|
|
{
|
|
if (!flag_ncp22_1e_obtain_attrs(name, attrs))
|
|
return(0);
|
|
|
|
return(flag_ncp87_obtain_attrs(name, 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 connid = 0;
|
|
uint8 dhandle = 0;
|
|
uint8 *p;
|
|
int hlen;
|
|
|
|
if (tool_current_dhandle(&connid, &dhandle))
|
|
return(-1);
|
|
|
|
/*
|
|
* Prefer verified Client32 modify path. The old INT 21h/F257 modify path
|
|
* can hang under DOS Client32 for high FLAG bits such as T/P/DI/RI.
|
|
*/
|
|
{
|
|
uint16 actual = 0;
|
|
uint16 hlo = 0;
|
|
uint16 hhi = 0;
|
|
if (!c32_ncp87_modify_dos_attributes(name, (uint16)dhandle, attrs,
|
|
&actual, &hlo, &hhi))
|
|
return(0);
|
|
}
|
|
|
|
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 */
|
|
tool_put_word_lh(p, FLAG_SA_ALL); p += 2;
|
|
|
|
tool_put_dword_lh(p, FLAG_DM_ATTRIBUTES); p += 4; /* modify mask: DM_ATTRIBUTES */
|
|
tool_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
|
|
#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 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, uint32 *setbits, uint32 *clearbits)
|
|
{
|
|
int set = 1;
|
|
char *p = s;
|
|
|
|
if (*p == '+') {
|
|
set = 1;
|
|
p++;
|
|
} else if (*p == '-') {
|
|
set = 0;
|
|
p++;
|
|
}
|
|
|
|
if (!*p) return(-1);
|
|
|
|
if (tool_strsame(p, "RO")) {
|
|
if (set) {
|
|
*setbits |= (NWFA_RO | NWFA_DI | NWFA_RI);
|
|
} else {
|
|
*clearbits |= (NWFA_RO | NWFA_DI | NWFA_RI);
|
|
}
|
|
} else if (tool_strsame(p, "RW")) {
|
|
*clearbits |= (NWFA_RO | NWFA_DI | NWFA_RI);
|
|
} else if (tool_strsame(p, "S")) {
|
|
if (set) *setbits |= NWFA_S;
|
|
else *clearbits |= NWFA_S;
|
|
} else if (tool_strsame(p, "H")) {
|
|
if (set) *setbits |= NWFA_H;
|
|
else *clearbits |= NWFA_H;
|
|
} else if (tool_strsame(p, "SY") || tool_strsame(p, "SYS") || tool_strsame(p, "SYSTEM")) {
|
|
if (set) *setbits |= NWFA_SY;
|
|
else *clearbits |= NWFA_SY;
|
|
} else if (tool_strsame(p, "T")) {
|
|
if (set) *setbits |= NWFA_T;
|
|
else *clearbits |= NWFA_T;
|
|
} else if (tool_strsame(p, "P")) {
|
|
if (set) *setbits |= NWFA_P;
|
|
else *clearbits |= NWFA_P;
|
|
} else if (tool_strsame(p, "A")) {
|
|
if (set) *setbits |= NWFA_A;
|
|
else *clearbits |= NWFA_A;
|
|
} else if (tool_strsame(p, "RA")) {
|
|
if (set) *setbits |= NWFA_RA;
|
|
else *clearbits |= NWFA_RA;
|
|
} else if (tool_strsame(p, "WA")) {
|
|
if (set) *setbits |= NWFA_WA;
|
|
else *clearbits |= NWFA_WA;
|
|
} else if (tool_strsame(p, "CI")) {
|
|
if (set) *setbits |= NWFA_CI;
|
|
else *clearbits |= NWFA_CI;
|
|
} else if (tool_strsame(p, "DI")) {
|
|
if (set) *setbits |= NWFA_DI;
|
|
else *clearbits |= NWFA_DI;
|
|
} else if (tool_strsame(p, "RI")) {
|
|
if (set) *setbits |= NWFA_RI;
|
|
else *clearbits |= NWFA_RI;
|
|
} else if (tool_strsame(p, "N") || tool_strsame(p, "NORMAL")) {
|
|
*clearbits |= (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 (tool_strsame(p, "ALL")) {
|
|
*setbits |= (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);
|
|
}
|
|
|
|
return(0);
|
|
}
|
|
|
|
static void flag_print_attrs(uint32 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, "- ");
|
|
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, "]");
|
|
}
|
|
|
|
static void flag_display_one(char *name, uint32 attr)
|
|
{
|
|
fprintf(stdout, " %-23s ", name);
|
|
flag_print_attrs(attr);
|
|
fprintf(stdout, " \n");
|
|
}
|
|
|
|
static void flag_display_one_paged(char *name, uint32 attr,
|
|
int *line_count, int *continuous)
|
|
{
|
|
flag_display_one(name, attr);
|
|
tool_page_line(line_count, continuous);
|
|
}
|
|
|
|
|
|
static char *flag_last_sep(char *s)
|
|
{
|
|
char *last = NULL;
|
|
char *p;
|
|
|
|
for (p = s; *p; p++) {
|
|
if (*p == '\\' || *p == '/' || *p == ':')
|
|
last = p;
|
|
}
|
|
|
|
return(last);
|
|
}
|
|
|
|
static void flag_split_pattern(char *pattern, char *parent, int parent_size,
|
|
char *leaf, int leaf_size)
|
|
{
|
|
char temp[260];
|
|
char *sep;
|
|
int plen;
|
|
|
|
parent[0] = '\0';
|
|
leaf[0] = '\0';
|
|
|
|
strmaxcpy(temp, pattern, sizeof(temp) - 1);
|
|
sep = flag_last_sep(temp);
|
|
|
|
if (!sep) {
|
|
strmaxcpy(leaf, temp, leaf_size - 1);
|
|
return;
|
|
}
|
|
|
|
if (*(sep + 1)) {
|
|
strmaxcpy(leaf, sep + 1, leaf_size - 1);
|
|
} else {
|
|
strmaxcpy(leaf, "*.*", leaf_size - 1);
|
|
}
|
|
|
|
plen = (int)(sep - temp);
|
|
|
|
/*
|
|
* Keep drive-root paths as "F:\" rather than "F:".
|
|
*/
|
|
if (*sep == ':' && (*(sep + 1) == '\\' || *(sep + 1) == '/'))
|
|
plen += 2;
|
|
else if (*sep == ':' || *sep == '\\' || *sep == '/')
|
|
plen += 1;
|
|
|
|
if (plen >= parent_size)
|
|
plen = parent_size - 1;
|
|
|
|
memcpy(parent, temp, plen);
|
|
parent[plen] = '\0';
|
|
}
|
|
|
|
static int flag_enter_parent(char *pattern, char *leaf, int leaf_size,
|
|
char *oldcwd, int oldcwd_size)
|
|
{
|
|
char parent[260];
|
|
|
|
oldcwd[0] = '\0';
|
|
flag_split_pattern(pattern, parent, sizeof(parent), leaf, leaf_size);
|
|
|
|
if (!leaf[0])
|
|
strmaxcpy(leaf, "*.*", leaf_size - 1);
|
|
|
|
if (!parent[0])
|
|
return(0);
|
|
|
|
if (!getcwd(oldcwd, oldcwd_size))
|
|
oldcwd[0] = '\0';
|
|
|
|
if (chdir(parent)) {
|
|
if (oldcwd[0])
|
|
chdir(oldcwd);
|
|
return(-1);
|
|
}
|
|
|
|
return(0);
|
|
}
|
|
|
|
static void flag_leave_parent(char *oldcwd)
|
|
{
|
|
if (oldcwd[0])
|
|
chdir(oldcwd);
|
|
}
|
|
|
|
|
|
static int flag_list(char *pattern)
|
|
{
|
|
struct find_t ff;
|
|
unsigned findattr = _A_RDONLY | _A_HIDDEN | _A_SYSTEM | _A_ARCH;
|
|
int found = 0;
|
|
int line_count = 0;
|
|
int continuous = 0;
|
|
|
|
if (_dos_findfirst(pattern, findattr, &ff))
|
|
return(-1);
|
|
|
|
do {
|
|
if (!(ff.attrib & _A_SUBDIR)) {
|
|
uint32 nwattrs;
|
|
|
|
if (flag_obtain_attrs(ff.name, &nwattrs))
|
|
nwattrs = (uint32)ff.attrib;
|
|
|
|
flag_display_one_paged(ff.name, nwattrs, &line_count, &continuous);
|
|
found++;
|
|
}
|
|
} while (!_dos_findnext(&ff));
|
|
|
|
return(found);
|
|
}
|
|
|
|
static int flag_apply(char *pattern, uint32 setbits, uint32 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_obtain_attrs(fname, &attrs))
|
|
attrs = (uint32)ff.attrib;
|
|
|
|
newattrs = (attrs | (uint32)setbits) & ~((uint32)clearbits);
|
|
|
|
if (newattrs != attrs) {
|
|
if (flag_ncp22_25_modify_attrs(fname, newattrs) &&
|
|
flag_ncp87_modify_attrs(fname, newattrs)) {
|
|
unsigned dosattr = (newattrs & (_A_RDONLY|_A_HIDDEN|_A_SYSTEM|_A_ARCH));
|
|
if (_dos_setfileattr(fname, dosattr)) {
|
|
fprintf(stdout, "You don't have rights to change : %s\n", fname);
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (flag_obtain_attrs(fname, &attrs))
|
|
attrs = newattrs;
|
|
|
|
flag_display_one(fname, newattrs);
|
|
shown++;
|
|
|
|
} while (!_dos_findnext(&ff));
|
|
|
|
return(shown);
|
|
}
|
|
|
|
int func_flag(int argc, char *argv[], int mode)
|
|
{
|
|
char *path = "*.*";
|
|
int i;
|
|
uint32 setbits = 0;
|
|
uint32 clearbits = 0;
|
|
int have_change = 0;
|
|
int rc;
|
|
|
|
(void)mode;
|
|
|
|
if (argc > 1 && (tool_strsame(argv[1], "/?") || tool_strsame(argv[1], "-?") ||
|
|
tool_strsame(argv[1], "?"))) {
|
|
flag_help();
|
|
return(0);
|
|
}
|
|
|
|
if (argc > 1) {
|
|
path = argv[1];
|
|
if (tool_strsame(path, "SUB")) path = "*.*";
|
|
}
|
|
|
|
for (i = 2; i < argc; i++) {
|
|
if (tool_strsame(argv[i], "SUB")) continue;
|
|
|
|
rc = flag_attr_mask(argv[i], &setbits, &clearbits);
|
|
if (rc < 0) return(1);
|
|
if (rc > 0) continue;
|
|
have_change = 1;
|
|
}
|
|
|
|
{
|
|
char leaf[260];
|
|
char oldcwd[260];
|
|
|
|
if (flag_enter_parent(path, leaf, sizeof(leaf), oldcwd, sizeof(oldcwd))) {
|
|
flag_split_pattern(path, oldcwd, sizeof(oldcwd), leaf, sizeof(leaf));
|
|
fprintf(stdout, "Files could not be found with pattern \"%s\"\a", leaf);
|
|
return(1);
|
|
}
|
|
|
|
if (have_change) {
|
|
rc = flag_apply(leaf, setbits, clearbits);
|
|
flag_leave_parent(oldcwd);
|
|
if (rc < 0) {
|
|
fprintf(stdout, "Files could not be found with pattern \"%s\"\a", leaf);
|
|
return(1);
|
|
}
|
|
|
|
return(0);
|
|
}
|
|
|
|
rc = flag_list(leaf);
|
|
flag_leave_parent(oldcwd);
|
|
if (rc < 0) {
|
|
fprintf(stdout, "Files could not be found with pattern \"%s\"\a", leaf);
|
|
return(1);
|
|
}
|
|
}
|
|
|
|
return(0);
|
|
}
|