Add a Client32 NCP87 helper for obtaining DOS namespace file and subdirectory information and use it in NDIR. The new helper reads the classic NCP87 subfunction 6 RIM_ALL DOS info block, including timestamps, inherited rights, directory identifiers and size metadata. Use the NCP87 inherited rights mask for the inherited-rights column while keeping the existing Client32 effective-rights path for the effective rights column. Also use the NCP87 modify, archive, last-access and creation date fields for the /DATES display, falling back to DOS findfirst timestamps when the NCP87 info request is not available. Tighten the /DATES layout so the full Created/Copied timestamp remains within an 80-column DOS screen.
804 lines
22 KiB
C
804 lines
22 KiB
C
/* ndir.c - first Novell NDIR-like directory listing utility */
|
|
|
|
#include "net.h"
|
|
#include "c32ncp.h"
|
|
#include <dos.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
|
|
#ifndef S_IFDIR
|
|
#define S_IFDIR 0040000
|
|
#endif
|
|
|
|
#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
|
|
|
|
#define NDIR_OPT_FILES_ONLY 0x0001
|
|
#define NDIR_OPT_DIRS_ONLY 0x0002
|
|
#define NDIR_OPT_RIGHTS 0x0004
|
|
#define NDIR_OPT_DATES 0x0008
|
|
#define NDIR_OPT_SUB 0x0010
|
|
#define NDIR_OPT_SHORT 0x0020
|
|
|
|
/* NCP effective-rights bits returned by NCP87 subfunction 29. */
|
|
#define NDIR_NCP_RIGHT_READ 0x0001
|
|
#define NDIR_NCP_RIGHT_WRITE 0x0002
|
|
#define NDIR_NCP_RIGHT_CREATE 0x0008
|
|
#define NDIR_NCP_RIGHT_DELETE 0x0010
|
|
#define NDIR_NCP_RIGHT_OWNER 0x0020
|
|
#define NDIR_NCP_RIGHT_SEARCH 0x0040
|
|
#define NDIR_NCP_RIGHT_MODIFY 0x0080
|
|
#define NDIR_NCP_RIGHT_SUPER 0x0100
|
|
|
|
static void ndir_dos_date(unsigned date, char *out);
|
|
static void ndir_dos_datetime(unsigned date, unsigned time, char *out);
|
|
|
|
#define NDIR_OLD_RIGHT_S 0x01
|
|
#define NDIR_OLD_RIGHT_R 0x02
|
|
#define NDIR_OLD_RIGHT_W 0x04
|
|
#define NDIR_OLD_RIGHT_C 0x08
|
|
#define NDIR_OLD_RIGHT_E 0x10
|
|
#define NDIR_OLD_RIGHT_M 0x20
|
|
#define NDIR_OLD_RIGHT_F 0x40
|
|
#define NDIR_OLD_RIGHT_A 0x80
|
|
|
|
|
|
static void ndir_usage(void)
|
|
{
|
|
fprintf(stdout, "usage: NDIR [path] [/option...]\n");
|
|
fprintf(stdout, "path: [path] [filename] [,filename, ...] (up to 16 in chain)\n");
|
|
fprintf(stdout, "options: [format], [flag], [sortspec], [restriction], [FO] (files only),\n");
|
|
fprintf(stdout, " [DO] (directories only), [SUBdirectories], [Continuous], [HELP]\n");
|
|
fprintf(stdout, "\n");
|
|
fprintf(stdout, "format: DATES, RIGHTS, MACintosh, LONGnames\n");
|
|
fprintf(stdout, "\n");
|
|
fprintf(stdout, "flag: [NOT] RO, S, A, X, H, SY, T, I, P, RA, WA, CI, DI, RI\n");
|
|
fprintf(stdout, "\n");
|
|
fprintf(stdout, "sortspec: [REVerse] SORT [OWner], [SIze], [UPdate], [CReate],\n");
|
|
fprintf(stdout, " [ACcess], [ARchive], [UNsorted]\n");
|
|
fprintf(stdout, "\n");
|
|
fprintf(stdout, "restriction: OWner <operator> <name>\n");
|
|
fprintf(stdout, " SIze <operator> <number>\n");
|
|
fprintf(stdout, " UPdate <operator> <date>\n");
|
|
fprintf(stdout, " CReate <operator> <date>\n");
|
|
fprintf(stdout, " ACcess <operator> <date>\n");
|
|
fprintf(stdout, " ARchive <operator> <date>\n");
|
|
fprintf(stdout, "\n");
|
|
fprintf(stdout, "operator: [NOT] Less than, GReater than,\n");
|
|
fprintf(stdout, " EQual to, BEfore, AFter\n");
|
|
fprintf(stdout, "\n");
|
|
fprintf(stdout, "To search filenames equivalent to any of the capitalized KEYWORD options\n");
|
|
fprintf(stdout, "shown above, the filename must be preceded by a drive letter or path.\n");
|
|
}
|
|
|
|
static int ndir_is_help(char *s)
|
|
{
|
|
if (!s) return(0);
|
|
return(tool_is_help_arg(s) || tool_strsame(s, "/HELP") ||
|
|
tool_strsame(s, "-HELP") || tool_strsame(s, "HELP"));
|
|
}
|
|
|
|
static int ndir_is_files_only(char *s)
|
|
{
|
|
if (!s) return(0);
|
|
return(tool_strsame(s, "/FO") || tool_strsame(s, "-FO") ||
|
|
tool_strsame(s, "/FILESONLY") || tool_strsame(s, "-FILESONLY") ||
|
|
tool_strsame(s, "FO") || tool_strsame(s, "FILESONLY"));
|
|
}
|
|
|
|
static int ndir_is_dirs_only(char *s)
|
|
{
|
|
if (!s) return(0);
|
|
return(tool_strsame(s, "/DO") || tool_strsame(s, "-DO") ||
|
|
tool_strsame(s, "/DIRSONLY") || tool_strsame(s, "-DIRSONLY") ||
|
|
tool_strsame(s, "/DIRECTORIES") || tool_strsame(s, "-DIRECTORIES") ||
|
|
tool_strsame(s, "DO") || tool_strsame(s, "DIRSONLY") ||
|
|
tool_strsame(s, "DIRECTORIES"));
|
|
}
|
|
|
|
static int ndir_is_continuous(char *s)
|
|
{
|
|
if (!s) return(0);
|
|
return(tool_strsame(s, "/CONTINUOUS") || tool_strsame(s, "-CONTINUOUS") ||
|
|
tool_strsame(s, "/CONTINUE") || tool_strsame(s, "-CONTINUE") ||
|
|
tool_strsame(s, "/C") || tool_strsame(s, "-C") ||
|
|
tool_strsame(s, "CONTINUOUS") || tool_strsame(s, "CONTINUE"));
|
|
}
|
|
|
|
static int ndir_is_rights(char *s)
|
|
{
|
|
if (!s) return(0);
|
|
return(tool_strsame(s, "/RIGHTS") || tool_strsame(s, "-RIGHTS") ||
|
|
tool_strsame(s, "RIGHTS"));
|
|
}
|
|
|
|
static int ndir_is_dates(char *s)
|
|
{
|
|
if (!s) return(0);
|
|
return(tool_strsame(s, "/DATES") || tool_strsame(s, "-DATES") ||
|
|
tool_strsame(s, "DATES"));
|
|
}
|
|
|
|
static int ndir_is_subdirs(char *s)
|
|
{
|
|
if (!s) return(0);
|
|
return(tool_strsame(s, "/SUB") || tool_strsame(s, "-SUB") ||
|
|
tool_strsame(s, "/SUBDIRECTORIES") || tool_strsame(s, "-SUBDIRECTORIES") ||
|
|
tool_strsame(s, "SUB") || tool_strsame(s, "SUBDIRECTORIES"));
|
|
}
|
|
|
|
static int ndir_is_short(char *s)
|
|
{
|
|
if (!s) return(0);
|
|
return(tool_strsame(s, "/SHORT") || tool_strsame(s, "-SHORT") ||
|
|
tool_strsame(s, "/BRIEF") || tool_strsame(s, "-BRIEF") ||
|
|
tool_strsame(s, "SHORT") || tool_strsame(s, "BRIEF"));
|
|
}
|
|
|
|
static int ndir_is_accepted_stub(char *s)
|
|
{
|
|
if (!s) return(0);
|
|
|
|
/*
|
|
* Keep this version tolerant of common NDIR format/options so users
|
|
* can compare command lines while unimplemented formats remain harmless.
|
|
*/
|
|
return(0);
|
|
}
|
|
|
|
static int ndir_path_is_dir(char *path)
|
|
{
|
|
struct stat st;
|
|
|
|
if (!path || !*path || tool_is_current_path(path))
|
|
return(1);
|
|
|
|
if (stat(path, &st) == 0) {
|
|
if (st.st_mode & S_IFDIR)
|
|
return(1);
|
|
}
|
|
|
|
return(0);
|
|
}
|
|
|
|
static void ndir_split_spec(char *spec, char *dir, char *pat)
|
|
{
|
|
if (!spec || !*spec || tool_is_current_path(spec)) {
|
|
strmaxcpy(dir, ".", 259);
|
|
strmaxcpy(pat, "*.*", 259);
|
|
return;
|
|
}
|
|
|
|
if (!tool_has_wildcards(spec) && ndir_path_is_dir(spec)) {
|
|
strmaxcpy(dir, spec, 259);
|
|
strmaxcpy(pat, "*.*", 259);
|
|
return;
|
|
}
|
|
|
|
tool_parent_pattern(dir, pat, spec, 260, 260);
|
|
}
|
|
|
|
static void ndir_dos_date(unsigned date, char *out)
|
|
{
|
|
int year;
|
|
int month;
|
|
int day;
|
|
|
|
year = ((date >> 9) & 0x7f) + 1980;
|
|
month = (date >> 5) & 0x0f;
|
|
day = date & 0x1f;
|
|
|
|
sprintf(out, "%02d-%02d-%02d", month, day, year % 100);
|
|
}
|
|
|
|
static void ndir_dos_datetime_or_blank(unsigned date, unsigned time, char *out)
|
|
{
|
|
if (!date) {
|
|
strcpy(out, "0-00-00 0:00 A");
|
|
return;
|
|
}
|
|
|
|
ndir_dos_datetime(date, time, out);
|
|
}
|
|
|
|
static void ndir_dos_date_or_blank(unsigned date, char *out)
|
|
{
|
|
if (!date) {
|
|
strcpy(out, "0-00-00");
|
|
return;
|
|
}
|
|
|
|
ndir_dos_date(date, out);
|
|
}
|
|
|
|
|
|
static void ndir_dos_datetime(unsigned date, unsigned time, char *out)
|
|
{
|
|
int year;
|
|
int month;
|
|
int day;
|
|
int hour;
|
|
int minute;
|
|
char ap;
|
|
|
|
year = ((date >> 9) & 0x7f) + 1980;
|
|
month = (date >> 5) & 0x0f;
|
|
day = date & 0x1f;
|
|
hour = (time >> 11) & 0x1f;
|
|
minute = (time >> 5) & 0x3f;
|
|
|
|
ap = (hour >= 12) ? 'p' : 'a';
|
|
if (hour == 0)
|
|
hour = 12;
|
|
else if (hour > 12)
|
|
hour -= 12;
|
|
|
|
sprintf(out, "%02d-%02d-%02d %2d:%02d%c",
|
|
month, day, year % 100, hour, minute, ap);
|
|
}
|
|
|
|
static unsigned long ndir_blocks_for_size(unsigned long size)
|
|
{
|
|
/*
|
|
* Novell NDIR reports allocated bytes/blocks. For this first DOS
|
|
* findfirst/findnext implementation, approximate with 4 KiB allocation
|
|
* units so small test files match the observed Novell output more closely.
|
|
*/
|
|
if (size == 0L)
|
|
return(0L);
|
|
|
|
return((size + 4095L) / 4096L);
|
|
}
|
|
|
|
static void ndir_flags(unsigned attr, char *out)
|
|
{
|
|
/*
|
|
* Keep the first positions close to Novell's default NDIR display,
|
|
* for example [RW-A------------].
|
|
*/
|
|
out[0] = '[';
|
|
out[1] = 'R';
|
|
out[2] = (attr & _A_RDONLY) ? 'O' : 'W';
|
|
out[3] = (attr & _A_SYSTEM) ? 'S' : '-';
|
|
out[4] = (attr & _A_ARCH) ? 'A' : '-';
|
|
out[5] = (attr & _A_HIDDEN) ? 'H' : '-';
|
|
memset(out + 6, '-', 11);
|
|
out[17] = ']';
|
|
out[18] = '\0';
|
|
}
|
|
|
|
static void ndir_parent_path(char *dst, char *src, int max)
|
|
{
|
|
char tmp[260];
|
|
char *p;
|
|
|
|
tool_upcopy(tmp, src, sizeof(tmp));
|
|
p = strrchr(tmp, '\\');
|
|
if (!p) p = strrchr(tmp, ':');
|
|
|
|
if (p) {
|
|
if (*p == ':') {
|
|
p[1] = '\0';
|
|
} else {
|
|
*p = '\0';
|
|
}
|
|
strmaxcpy(dst, tmp, max - 1);
|
|
} else {
|
|
dst[0] = '\0';
|
|
}
|
|
}
|
|
|
|
static void ndir_old_rights_string(uint8 old_rights, char *out)
|
|
{
|
|
out[0] = (old_rights & NDIR_OLD_RIGHT_S) ? 'S' : '-';
|
|
out[1] = (old_rights & NDIR_OLD_RIGHT_R) ? 'R' : '-';
|
|
out[2] = (old_rights & NDIR_OLD_RIGHT_W) ? 'W' : '-';
|
|
out[3] = (old_rights & NDIR_OLD_RIGHT_C) ? 'C' : '-';
|
|
out[4] = (old_rights & NDIR_OLD_RIGHT_E) ? 'E' : '-';
|
|
out[5] = (old_rights & NDIR_OLD_RIGHT_M) ? 'M' : '-';
|
|
out[6] = (old_rights & NDIR_OLD_RIGHT_F) ? 'F' : '-';
|
|
out[7] = (old_rights & NDIR_OLD_RIGHT_A) ? 'A' : '-';
|
|
out[8] = '\0';
|
|
}
|
|
|
|
static int ndir_get_ncp_info(char *path, C32_NDIR_INFO *info)
|
|
{
|
|
uint8 connid = 0;
|
|
uint8 dhandle = 0;
|
|
|
|
if (!info)
|
|
return(1);
|
|
|
|
memset(info, 0, sizeof(*info));
|
|
|
|
if (tool_current_dhandle(&connid, &dhandle))
|
|
return(1);
|
|
|
|
return(c32_ncp87_obtain_ndir_info(tool_is_current_path(path) ? "" : path,
|
|
(uint16)dhandle,
|
|
info,
|
|
NULL, NULL, NULL));
|
|
}
|
|
|
|
static void ndir_inherited_rights(char *path, char *out)
|
|
{
|
|
C32_NDIR_INFO info;
|
|
|
|
strcpy(out, "--------");
|
|
|
|
if (!ndir_get_ncp_info(path, &info))
|
|
ndir_old_rights_string((uint8)info.inherited_rights, out);
|
|
}
|
|
|
|
static void ndir_rights_string(uint16 ncp_rights, char *out)
|
|
{
|
|
out[0] = (ncp_rights & NDIR_NCP_RIGHT_SUPER) ? 'S' : '-';
|
|
out[1] = (ncp_rights & NDIR_NCP_RIGHT_READ) ? 'R' : '-';
|
|
out[2] = (ncp_rights & NDIR_NCP_RIGHT_WRITE) ? 'W' : '-';
|
|
out[3] = (ncp_rights & NDIR_NCP_RIGHT_CREATE) ? 'C' : '-';
|
|
out[4] = (ncp_rights & NDIR_NCP_RIGHT_DELETE) ? 'E' : '-';
|
|
out[5] = (ncp_rights & NDIR_NCP_RIGHT_MODIFY) ? 'M' : '-';
|
|
out[6] = (ncp_rights & NDIR_NCP_RIGHT_SEARCH) ? 'F' : '-';
|
|
out[7] = (ncp_rights & NDIR_NCP_RIGHT_OWNER) ? 'A' : '-';
|
|
out[8] = '\0';
|
|
}
|
|
|
|
static void ndir_effective_rights(char *path, char *out)
|
|
{
|
|
uint8 connid = 0;
|
|
uint8 dhandle = 0;
|
|
uint8 eff_old = 0;
|
|
uint16 ncp_rights = 0;
|
|
char usepath[260];
|
|
int newhandle;
|
|
|
|
strcpy(out, "--------");
|
|
|
|
if (tool_current_dhandle(&connid, &dhandle))
|
|
return;
|
|
|
|
/*
|
|
* Prefer Client32 NCP87 effective-rights. If that fails for a listed
|
|
* entry, fall back to the older directory-handle effective-rights path
|
|
* that RIGHTS also uses.
|
|
*/
|
|
if (!c32_ncp87_get_effective_rights(tool_is_current_path(path) ? "" : path,
|
|
(uint16)dhandle,
|
|
&ncp_rights,
|
|
NULL, NULL, NULL)) {
|
|
ndir_rights_string(ncp_rights, out);
|
|
return;
|
|
}
|
|
|
|
ndir_parent_path(usepath, path, sizeof(usepath));
|
|
newhandle = alloc_temp_dir_handle(dhandle, usepath, 0, &eff_old);
|
|
if (newhandle >= 0) {
|
|
dealloc_dir_handle(newhandle);
|
|
ndir_old_rights_string(eff_old, out);
|
|
return;
|
|
}
|
|
|
|
if (usepath[0]) {
|
|
int subdir = 1;
|
|
int r = ncp_16_02(dhandle, (uint8 *)usepath, &subdir,
|
|
NULL, NULL, NULL);
|
|
if (r >= 0)
|
|
ndir_old_rights_string((uint8)r, out);
|
|
} else {
|
|
ndir_old_rights_string(0xff, out);
|
|
}
|
|
}
|
|
|
|
static int ndir_is_dot_dir(char *name)
|
|
{
|
|
if (!name) return(0);
|
|
if (name[0] == '.' && name[1] == '\0') return(1);
|
|
if (name[0] == '.' && name[1] == '.' && name[2] == '\0') return(1);
|
|
return(0);
|
|
}
|
|
|
|
static void ndir_print_file(char *dir, struct find_t *ff, int options,
|
|
int *line_count, int *continuous)
|
|
{
|
|
char dt[24];
|
|
char d[12];
|
|
char fl[20]; /* [RW-A------------] plus NUL */
|
|
char path[260];
|
|
char eff[10];
|
|
char inh[10];
|
|
char arch[24];
|
|
char acc[12];
|
|
char crea[24];
|
|
C32_NDIR_INFO info;
|
|
int have_info = 0;
|
|
|
|
tool_join_path(path, dir, ff->name, sizeof(path));
|
|
have_info = !ndir_get_ncp_info(path, &info);
|
|
|
|
if (have_info)
|
|
ndir_dos_datetime(info.modify_date, info.modify_time, dt);
|
|
else
|
|
ndir_dos_datetime(ff->wr_date, ff->wr_time, dt);
|
|
|
|
ndir_dos_date(ff->wr_date, d);
|
|
ndir_flags(ff->attrib, fl);
|
|
|
|
if (options & NDIR_OPT_RIGHTS) {
|
|
ndir_effective_rights(path, eff);
|
|
ndir_inherited_rights(path, inh);
|
|
fprintf(stdout, "%-16.16s %-18.18s [%8.8s] [%8.8s]\n",
|
|
ff->name, fl, inh, eff);
|
|
} else if (options & NDIR_OPT_DATES) {
|
|
/*
|
|
* DOS findfirst gives us the update timestamp only. Keep the Novell
|
|
* /DATES layout and use placeholders for archive/access data until
|
|
* full NetWare namespace date fields are available.
|
|
*/
|
|
if (have_info) {
|
|
ndir_dos_datetime_or_blank(info.archive_date, info.archive_time, arch);
|
|
ndir_dos_date_or_blank(info.last_access_date, acc);
|
|
ndir_dos_datetime_or_blank(info.creation_date, info.creation_time, crea);
|
|
fprintf(stdout, "%-16.16s %-17.17s %-17.17s %-8.8s %-17.17s\n",
|
|
ff->name, dt, arch, acc, crea);
|
|
} else {
|
|
fprintf(stdout, "%-16.16s %-17.17s 0-00-00 0:00 A %-8.8s %-17.17s\n",
|
|
ff->name, dt, d, dt);
|
|
}
|
|
} else {
|
|
fprintf(stdout, "%-16.16s %12lu %-17.17s %-18.18s\n",
|
|
ff->name, (unsigned long)ff->size, dt, fl);
|
|
}
|
|
|
|
tool_page_line(line_count, continuous);
|
|
}
|
|
|
|
static void ndir_print_dir(char *dir, struct find_t *ff, int options,
|
|
int *line_count, int *continuous)
|
|
{
|
|
char dt[24];
|
|
char path[260];
|
|
char eff[10];
|
|
char inh[10];
|
|
C32_NDIR_INFO info;
|
|
|
|
tool_join_path(path, dir, ff->name, sizeof(path));
|
|
if (!ndir_get_ncp_info(path, &info))
|
|
ndir_dos_datetime(info.creation_date, info.creation_time, dt);
|
|
else
|
|
ndir_dos_datetime(ff->wr_date, ff->wr_time, dt);
|
|
|
|
if (options & (NDIR_OPT_RIGHTS | NDIR_OPT_DIRS_ONLY)) {
|
|
ndir_effective_rights(path, eff);
|
|
ndir_inherited_rights(path, inh);
|
|
fprintf(stdout, "%-16.16s [%8.8s] [%8.8s] %-17.17s\n",
|
|
ff->name, inh, eff, dt);
|
|
} else {
|
|
fprintf(stdout, "%-16.16s <DIR> %-17.17s\n", ff->name, dt);
|
|
}
|
|
|
|
tool_page_line(line_count, continuous);
|
|
}
|
|
|
|
static int ndir_scan_files(char *dir, char *search, int options,
|
|
int *line_count, int *continuous,
|
|
int *file_count, unsigned long *total_bytes,
|
|
unsigned long *total_blocks)
|
|
{
|
|
struct find_t ff;
|
|
int rc;
|
|
int shown = 0;
|
|
|
|
rc = _dos_findfirst(search, _A_NORMAL | _A_RDONLY | _A_HIDDEN |
|
|
_A_SYSTEM | _A_ARCH | _A_SUBDIR, &ff);
|
|
while (rc == 0) {
|
|
if (!(ff.attrib & _A_SUBDIR)) {
|
|
ndir_print_file(dir, &ff, options, line_count, continuous);
|
|
(*file_count)++;
|
|
*total_bytes += (unsigned long)ff.size;
|
|
*total_blocks += ndir_blocks_for_size((unsigned long)ff.size);
|
|
shown = 1;
|
|
}
|
|
|
|
rc = _dos_findnext(&ff);
|
|
}
|
|
|
|
return(shown);
|
|
}
|
|
|
|
static int ndir_scan_dirs(char *dir, char *search, int options,
|
|
int *line_count, int *continuous,
|
|
int *dir_count)
|
|
{
|
|
struct find_t ff;
|
|
int rc;
|
|
int shown = 0;
|
|
|
|
rc = _dos_findfirst(search, _A_NORMAL | _A_RDONLY | _A_HIDDEN |
|
|
_A_SYSTEM | _A_ARCH | _A_SUBDIR, &ff);
|
|
while (rc == 0) {
|
|
if ((ff.attrib & _A_SUBDIR) && !ndir_is_dot_dir(ff.name)) {
|
|
ndir_print_dir(dir, &ff, options, line_count, continuous);
|
|
(*dir_count)++;
|
|
shown = 1;
|
|
}
|
|
|
|
rc = _dos_findnext(&ff);
|
|
}
|
|
|
|
return(shown);
|
|
}
|
|
|
|
static int ndir_list_one(char *spec, int options, int *continuous)
|
|
{
|
|
char dir[260];
|
|
char pat[260];
|
|
char search[260];
|
|
char display[300];
|
|
int got = 0;
|
|
int files_shown = 0;
|
|
int dirs_shown = 0;
|
|
int file_count = 0;
|
|
int dir_count = 0;
|
|
unsigned long total_bytes = 0L;
|
|
unsigned long total_blocks = 0L;
|
|
int line_count = 0;
|
|
|
|
ndir_split_spec(spec, dir, pat);
|
|
tool_join_path(search, dir, pat, sizeof(search));
|
|
|
|
tool_header_path(display, dir, sizeof(display));
|
|
fprintf(stdout, "%s\n", display);
|
|
tool_page_line(&line_count, continuous);
|
|
|
|
if (!(options & NDIR_OPT_DIRS_ONLY)) {
|
|
if (!(options & NDIR_OPT_SHORT)) {
|
|
if (options & NDIR_OPT_RIGHTS) {
|
|
fprintf(stdout, "Files: Flags Rights Rights Owner\n");
|
|
fprintf(stdout, "---------------- ------------------ ----------- ----------- --------\n");
|
|
} else if (options & NDIR_OPT_DATES) {
|
|
fprintf(stdout, "Files: Last Updated Last Archived Accessed Created/Copied\n");
|
|
fprintf(stdout, "---------------- ----------------- ----------------- -------- -----------------\n");
|
|
} else {
|
|
fprintf(stdout, "Files: Size Last Updated Flags Owner\n");
|
|
fprintf(stdout, "---------------- ---------------- ----------------- ------------------ --------\n");
|
|
}
|
|
tool_page_line(&line_count, continuous);
|
|
tool_page_line(&line_count, continuous);
|
|
}
|
|
|
|
files_shown = ndir_scan_files(dir, search, options, &line_count,
|
|
continuous, &file_count,
|
|
&total_bytes, &total_blocks);
|
|
if (files_shown)
|
|
got = 1;
|
|
}
|
|
|
|
if (!(options & NDIR_OPT_FILES_ONLY)) {
|
|
if (!(options & NDIR_OPT_DIRS_ONLY) && !(options & NDIR_OPT_SHORT))
|
|
fprintf(stdout, "\n");
|
|
|
|
if (!(options & NDIR_OPT_SHORT)) {
|
|
if (options & (NDIR_OPT_RIGHTS | NDIR_OPT_DIRS_ONLY)) {
|
|
fprintf(stdout, "Directories: Rights Rights Owner Created/Copied\n");
|
|
fprintf(stdout, "---------------- ----------- ----------- ----------- -----------------\n");
|
|
} else {
|
|
fprintf(stdout, "Directories:\n");
|
|
fprintf(stdout, "----------------\n");
|
|
}
|
|
tool_page_line(&line_count, continuous);
|
|
tool_page_line(&line_count, continuous);
|
|
}
|
|
|
|
dirs_shown = ndir_scan_dirs(dir, search, options, &line_count,
|
|
continuous, &dir_count);
|
|
if (dirs_shown)
|
|
got = 1;
|
|
}
|
|
|
|
if (!got && (options & NDIR_OPT_DIRS_ONLY) && !(options & NDIR_OPT_SHORT))
|
|
fprintf(stdout, "No files of given specification found or directory is empty.\n");
|
|
|
|
if (!(options & NDIR_OPT_DIRS_ONLY)) {
|
|
if (options & NDIR_OPT_SHORT) {
|
|
if (file_count)
|
|
fprintf(stdout, " %lu bytes, %d files, %lu blocks\n",
|
|
total_bytes, file_count, total_blocks);
|
|
} else {
|
|
fprintf(stdout, "\n");
|
|
fprintf(stdout, "%12lu bytes in %5d files\n", total_bytes, file_count);
|
|
fprintf(stdout, "%12lu bytes in %5lu blocks\n", total_blocks * 4096L,
|
|
total_blocks);
|
|
}
|
|
}
|
|
|
|
return(got ? 0 : 1);
|
|
}
|
|
|
|
|
|
static int ndir_spec_has_output(char *spec, int options)
|
|
{
|
|
struct find_t ff;
|
|
char dir[260];
|
|
char pat[260];
|
|
char search[260];
|
|
int rc;
|
|
|
|
ndir_split_spec(spec, dir, pat);
|
|
tool_join_path(search, dir, pat, sizeof(search));
|
|
|
|
rc = _dos_findfirst(search, _A_NORMAL | _A_RDONLY | _A_HIDDEN |
|
|
_A_SYSTEM | _A_ARCH | _A_SUBDIR, &ff);
|
|
while (rc == 0) {
|
|
if (ff.attrib & _A_SUBDIR) {
|
|
if (!ndir_is_dot_dir(ff.name) && !(options & NDIR_OPT_FILES_ONLY))
|
|
return(1);
|
|
} else {
|
|
if (!(options & NDIR_OPT_DIRS_ONLY))
|
|
return(1);
|
|
}
|
|
|
|
rc = _dos_findnext(&ff);
|
|
}
|
|
|
|
return(0);
|
|
}
|
|
|
|
|
|
static int ndir_list_subdirs(char *dir, char *pattern, int options,
|
|
int *continuous)
|
|
{
|
|
struct find_t ff;
|
|
char search[260];
|
|
char subdir[260];
|
|
char subspec[260];
|
|
int rc;
|
|
int result = 0;
|
|
int had_any = 0;
|
|
|
|
tool_join_path(search, dir, "*.*", sizeof(search));
|
|
|
|
rc = _dos_findfirst(search, _A_NORMAL | _A_RDONLY | _A_HIDDEN |
|
|
_A_SYSTEM | _A_ARCH | _A_SUBDIR, &ff);
|
|
while (rc == 0) {
|
|
if ((ff.attrib & _A_SUBDIR) && !ndir_is_dot_dir(ff.name)) {
|
|
tool_join_path(subdir, dir, ff.name, sizeof(subdir));
|
|
tool_join_path(subspec, subdir, pattern, sizeof(subspec));
|
|
|
|
if (!(options & NDIR_OPT_SHORT) ||
|
|
ndir_spec_has_output(subspec, options & ~NDIR_OPT_SUB)) {
|
|
fprintf(stdout, "\n");
|
|
if (ndir_list_one(subspec, options & ~NDIR_OPT_SUB, continuous))
|
|
result = 1;
|
|
}
|
|
|
|
had_any = 1;
|
|
if (ndir_list_subdirs(subdir, pattern, options, continuous))
|
|
result = 1;
|
|
}
|
|
|
|
rc = _dos_findnext(&ff);
|
|
}
|
|
|
|
if (!had_any)
|
|
return(result);
|
|
|
|
return(result);
|
|
}
|
|
|
|
static int ndir_list(char *spec, int options, int *continuous)
|
|
{
|
|
char dir[260];
|
|
char pat[260];
|
|
int result;
|
|
|
|
result = ndir_list_one(spec, options & ~NDIR_OPT_SUB, continuous);
|
|
|
|
if (!(options & NDIR_OPT_SUB))
|
|
return(result);
|
|
|
|
ndir_split_spec(spec, dir, pat);
|
|
if (!pat[0])
|
|
strmaxcpy(pat, "*.*", sizeof(pat) - 1);
|
|
|
|
return(ndir_list_subdirs(dir, pat, options, continuous) ? 1 : result);
|
|
}
|
|
|
|
int func_ndir(int argc, char *argv[], int mode)
|
|
{
|
|
char *path = ".";
|
|
int have_path = 0;
|
|
int options = 0;
|
|
int continuous = 0;
|
|
int i;
|
|
|
|
(void)mode;
|
|
|
|
if (argc > 1 && ndir_is_help(argv[1])) {
|
|
ndir_usage();
|
|
return(0);
|
|
}
|
|
|
|
for (i = 1; i < argc; i++) {
|
|
if (ndir_is_help(argv[i])) {
|
|
ndir_usage();
|
|
return(0);
|
|
}
|
|
|
|
if (ndir_is_files_only(argv[i])) {
|
|
options |= NDIR_OPT_FILES_ONLY;
|
|
continue;
|
|
}
|
|
|
|
if (ndir_is_dirs_only(argv[i])) {
|
|
options |= NDIR_OPT_DIRS_ONLY;
|
|
continue;
|
|
}
|
|
|
|
if (ndir_is_continuous(argv[i])) {
|
|
continuous = 1;
|
|
continue;
|
|
}
|
|
|
|
if (ndir_is_rights(argv[i])) {
|
|
options |= NDIR_OPT_RIGHTS;
|
|
continue;
|
|
}
|
|
|
|
if (ndir_is_dates(argv[i])) {
|
|
options |= NDIR_OPT_DATES;
|
|
continue;
|
|
}
|
|
|
|
if (ndir_is_subdirs(argv[i])) {
|
|
options |= NDIR_OPT_SUB;
|
|
continue;
|
|
}
|
|
|
|
if (ndir_is_short(argv[i])) {
|
|
options |= NDIR_OPT_SHORT;
|
|
continue;
|
|
}
|
|
|
|
if (ndir_is_accepted_stub(argv[i])) {
|
|
continue;
|
|
}
|
|
|
|
if (tool_is_option(argv[i])) {
|
|
fprintf(stdout, "Type \"ndir /help\" on the command line for usage information.\n");
|
|
return(1);
|
|
}
|
|
|
|
if (have_path) {
|
|
fprintf(stdout, "Too many filenames in chain.\n");
|
|
return(1);
|
|
}
|
|
|
|
path = argv[i];
|
|
have_path = 1;
|
|
}
|
|
|
|
if ((options & NDIR_OPT_FILES_ONLY) && (options & NDIR_OPT_DIRS_ONLY)) {
|
|
fprintf(stdout, "No files of given specification found or directory is empty.\n");
|
|
return(1);
|
|
}
|
|
|
|
return(ndir_list(path, options, &continuous));
|
|
}
|