freebsd-dev/usr.bin/doscmd/cwd.c
1998-07-01 23:31:53 +00:00

971 lines
21 KiB
C

/*
* Copyright (c) 1992, 1993, 1996
* Berkeley Software Design, Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Berkeley Software
* Design, Inc.
*
* THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design, Inc. BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* BSDI cwd.c,v 2.2 1996/04/08 19:32:25 bostic Exp
*
* $Id: cwd.c,v 1.2 1998/07/01 19:56:13 imp Exp $
*/
#include <sys/types.h>
#include <sys/param.h>
#include <sys/mount.h>
#include <dirent.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stdio.h>
#include "doscmd.h"
#define D_REDIR 0x0080000 /* XXX - ack */
#define D_TRAPS3 0x0200000
typedef struct {
u_char *path;
u_char *cwd;
int len;
int maxlen;
int read_only:1;
} Path_t;
typedef struct Name_t {
u_char *real;
struct Name_t *next;
u_char name[9];
u_char ext[4];
} Name_t;
#define MAX_DRIVE 26
static Path_t paths[MAX_DRIVE] = { 0, };
static Name_t *names;
extern int diskdrive;
/*
* Initialize the drive to be based at 'base' in the BSD filesystem
*/
void
init_path(int drive, u_char *base, u_char *dir)
{
Path_t *d;
if (drive < 0 || drive >= MAX_DRIVE)
return;
debug(D_TRAPS3, "init_path(%d, %s, %s)\n", drive, base, dir);
d = &paths[drive];
if (d->path)
free(d->path);
if ((d->path = ustrdup(base)) == NULL)
fatal("strdup in init_path for %c:%s: %s", drntol(drive), base,
strerror(errno));
if (d->maxlen < 2) {
d->maxlen = 128;
if ((d->cwd = (u_char *)malloc(d->maxlen)) == NULL)
fatal("malloc in init_path for %c:%s: %s", drntol(drive), base,
strerror(errno));
}
d->cwd[0] = '\\';
d->cwd[1] = 0;
d->len = 1;
if (dir) {
if (ustrncmp(base, dir, ustrlen(base)) == 0)
dir += ustrlen(base);
while (*dir == '/')
++dir;
while (*dir) {
u_char dosname[15];
u_char realname[256];
u_char *r = realname;;
while ((*r = *dir) && *dir++ != '/') {
++r;
}
*r = 0;
while (*dir == '/')
++dir;
dosname[0] = drntol(drive);
dosname[1] = ':';
real_to_dos(realname, &dosname[2]);
if (dos_setcwd(dosname)) {
fprintf(stderr, "Failed to CD to directory %s in %s\n",
dosname, d->cwd);
}
}
}
}
/*
* Mark this drive as read only
*/
void
dos_makereadonly(int drive)
{
if (drive < 0 || drive >= MAX_DRIVE)
return;
paths[drive].read_only = 1;
}
/*
* Return read-only status of drive
*/
int
dos_readonly(int drive)
{
if (drive < 0 || drive >= MAX_DRIVE)
return (0);
debug(D_REDIR, "dos_readonly(%d) -> %d\n", drive, paths[drive].read_only);
return (paths[drive].read_only);
}
/*
* Return DOS's idea of the CWD for drive
* Return 0 if the drive specified is not mapped (or bad)
*/
u_char *
dos_getcwd(int drive)
{
if (drive < 0 || drive >= MAX_DRIVE)
return (0);
debug(D_REDIR, "dos_getcwd(%d) -> %s\n", drive, paths[drive].cwd);
return (paths[drive].cwd);
}
/*
* Return DOS's idea of the CWD for drive
* Return 0 if the drive specified is not mapped (or bad)
*/
u_char *
dos_getpath(int drive)
{
if (drive < 0 || drive >= MAX_DRIVE)
return (0);
debug(D_REDIR, "dos_getpath(%d) -> %s\n", drive, paths[drive].path);
return (paths[drive].path);
}
/*
* Fix up a DOS path name. Strip out all '.' and '..' entries, turn
* '/' into '\\' and convert all lowercase to uppercase.
* Returns 0 on success or DOS errno
*/
int
dos_makepath(u_char *where, u_char *newpath)
{
int drive;
u_char **dirs;
u_char *np;
Path_t *d;
u_char tmppath[1024];
if (where[0] != '\0' && where[1] == ':') {
drive = drlton(*where);
*newpath++ = *where++;
*newpath++ = *where++;
} else {
drive = diskdrive;
*newpath++ = drntol(diskdrive);
*newpath++ = ':';
}
if (drive < 0 || drive >= MAX_DRIVE) {
debug(D_REDIR,"drive %c invalid\n", drntol(drive));
return (DISK_DRIVE_INVALID);
}
d = &paths[drive];
if (d->cwd == NULL) {
debug(D_REDIR,"no cwd for drive %c\n",drntol(drive));
return (DISK_DRIVE_INVALID);
}
debug(D_REDIR, "dos_makepath(%d, %s)\n", drive, where);
np = newpath;
if (*where != '\\' && *where != '/') {
ustrcpy(tmppath, d->cwd);
if (d->cwd[1])
ustrcat(tmppath, (u_char *)"/");
ustrcat(tmppath, where);
} else {
ustrcpy(tmppath, where);
}
dirs = get_entries(tmppath);
if (dirs == NULL)
return (PATH_NOT_FOUND);
np = newpath;
while (*dirs) {
u_char *dir = *dirs++;
if (*dir == '/' || *dir == '\\') {
np = newpath + 1;
newpath[0] = '\\';
} else if (dir[0] == '.' && dir[1] == 0) {
;
} else if (dir[0] == '.' && dir[1] == '.' && dir[2] == '\0') {
while (np[-1] != '/' && np[-1] != '\\')
--np;
if (np - 1 > newpath)
--np;
} else {
if (np[-1] != '\\')
*np++ = '\\';
while (*np = *dir++)
++np;
}
}
*np = 0;
return (0);
}
/*
* Set DOS's idea of the CWD for drive to be where.
* Returns DOS errno on failuer.
*/
int
dos_setcwd(u_char *where)
{
u_char newpath[1024];
u_char realpath[1024];
int drive;
struct stat sb;
Path_t *d;
int error;
debug(D_REDIR, "dos_setcwd(%s)\n", where);
error = dos_makepath(where, newpath);
if (error)
return (error);
error = dos_to_real_path(newpath, realpath, &drive);
if (error)
return (error);
if (ustat(realpath, &sb) < 0 || !S_ISDIR(sb.st_mode))
return (PATH_NOT_FOUND);
if (uaccess(realpath, R_OK | X_OK))
return (PATH_NOT_FOUND);
d = &paths[drive];
d->len = ustrlen(newpath + 2);
if (d->len + 1 > d->maxlen) {
free(d->cwd);
d->maxlen = d->len + 1 + 32;
d->cwd = (u_char *)malloc(d->maxlen);
if (d->cwd == NULL)
fatal("malloc in dos_setcwd for %c:%s: %s", drntol(drive),
newpath, strerror(errno));
}
ustrcpy(d->cwd, newpath + 2);
return (0);
}
/*
* Given a DOS path dospath and a drive, convert it to a BSD pathname
* and store the result in realpath.
* Return DOS errno on failure.
*/
int
dos_to_real_path(u_char *dospath, u_char *realpath, int *drivep)
{
Path_t *d;
u_char newpath[1024];
u_char *rp;
int error;
u_char **dirs;
u_char *dir;
int drive;
debug(D_REDIR, "dos_to_real_path(%s)\n", dospath);
if (dospath[0] != '\0' && dospath[1] == ':') {
drive = drlton(*dospath);
dospath++;
dospath++;
} else {
drive = diskdrive;
}
d = &paths[drive];
if (d->cwd == NULL)
return (DISK_DRIVE_INVALID);
ustrcpy(realpath, d->path);
rp = realpath;
while (*rp)
++rp;
ustrcpy(newpath, dospath);
dirs = get_entries(newpath);
if (dirs == NULL)
return (PATH_NOT_FOUND);
/*
* Skip the leading /
* There are no . or .. entries to worry about either
*/
while (dir = *++dirs) {
*rp++ = '/';
dos_to_real(dir, rp);
while (*rp)
++rp;
}
*drivep = drive;
return (0);
}
/*
* Provide a few istype() style functions.
* isvalid: True if the character is a valid DOS filename character
* isdot: True if '.'
* isslash: True if '/' or '\'
*
* 0 - invalid
* 1 - okay
* 2 - *
* 3 - dot
* 4 - slash
* 5 - colon
* 6 - ?
* 7 - lowercase
*/
u_char cattr[256] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10 */
0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 2, 0, 0, 1, 3, 4, /* 0x20 */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 0, 0, 0, 0, 6, /* 0x30 */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x40 */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 4, 0, 1, 1, /* 0x50 */
1, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, /* 0x60 */
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 1, 0, 1, 1, 0, /* 0x70 */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x80 */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
};
inline
isvalid(unsigned c)
{
return (cattr[c & 0xff] == 1);
}
inline
isdot(unsigned c)
{
return (cattr[c & 0xff] == 3);
}
inline
isslash(unsigned c)
{
return (cattr[c & 0xff] == 4);
}
/*
* Given a real component, compute the DOS component.
*/
void
real_to_dos(u_char *real, u_char *dos)
{
Name_t *n;
Name_t *nn;
u_char *p;
u_char nm[9], ex[4];
int ncnt, ecnt;
int echar = '0';
int nchar = '0';
if (real[0] == '.' && (real[1] == '\0'
|| (real[1] == '.' && real[2] == '\0'))) {
sprintf((char *)dos, "%.8s", real);
return;
}
n = names;
while (n) {
if (ustrcmp(real, n->real) == 0) {
if (n->ext[0])
sprintf((char *)dos, "%.8s.%.3s", n->name, n->ext);
else
sprintf((char *)dos, "%.8s", n->name);
return;
}
n = n->next;
}
p = real;
ncnt = ecnt = 0;
while (isvalid(*p) && ncnt < 8) {
nm[ncnt] = *p;
++ncnt;
++p;
}
if (isdot(*p)) {
++p;
while (isvalid(*p) && ecnt < 3) {
ex[ecnt] = *p;
++ecnt;
++p;
}
}
nm[ncnt] = '\0';
ex[ecnt] = '\0';
if (!*p && ncnt <= 8 && ecnt <= 3) {
n = names;
while (n) {
if (ustrncmp(n->name, nm, 8) == 0 && ustrncmp(n->ext, ex, 3) == 0) {
break;
}
n = n->next;
}
if (n == 0) {
ustrcpy(dos, real);
return;
}
}
n = (Name_t *)malloc(sizeof(Name_t));
if (!n)
fatal("malloc in real_to_dos: %s\n", strerror(errno));
n->real = ustrdup(real);
if (!n->real)
fatal("strdup in real_to_dos: %s\n", strerror(errno));
p = real;
ncnt = ecnt = 0;
while (*p && ncnt < 8) {
if (isvalid(*p))
n->name[ncnt] = *p;
else if (islower(*p))
n->name[ncnt] = toupper(*p);
else if (isdot(*p))
break;
else
n->name[ncnt] = (*p |= 0x80);
++ncnt;
++p;
}
if (isdot(*p)) {
++p;
while (*p && ecnt < 3) {
if (isvalid(*p))
n->ext[ecnt] = *p;
else if (islower(*p))
n->ext[ecnt] = toupper(*p);
#if 0
else if (isdot(*p))
ERROR
#endif
else
n->ext[ecnt] = (*p |= 0x80);
++ecnt;
++p;
}
}
n->name[ncnt] = '\0';
n->ext[ecnt] = '\0';
for (;;) {
nn = names;
while (nn) {
if (ustrncmp(n->name, nn->name, 8) == 0 &&
ustrncmp(n->ext, nn->ext, 3) == 0) {
break;
}
nn = nn->next;
}
if (!nn)
break;
/*
* Dang, this name was already in the cache.
* Let's munge it a little and try again.
*/
if (ecnt < 3) {
n->ext[ecnt] = echar;
if (echar == '9') {
echar = 'A';
} else if (echar == 'Z') {
++ecnt;
echar = '0';
} else {
++echar;
}
} else if (ncnt < 8) {
n->name[ncnt] = nchar;
if (nchar == '9') {
nchar = 'A';
} else if (nchar == 'Z') {
++ncnt;
nchar = '0';
} else {
++nchar;
}
} else if (n->ext[2] < 'Z')
n->ext[2]++;
else if (n->ext[1] < 'Z')
n->ext[1]++;
else if (n->ext[0] < 'Z')
n->ext[0]++;
else if (n->name[7] < 'Z')
n->name[7]++;
else if (n->name[6] < 'Z')
n->name[6]++;
else if (n->name[5] < 'Z')
n->name[5]++;
else if (n->name[4] < 'Z')
n->name[4]++;
else if (n->name[3] < 'Z')
n->name[3]++;
else if (n->name[2] < 'Z')
n->name[2]++;
else if (n->name[1] < 'Z')
n->name[1]++;
else if (n->name[0] < 'Z')
n->name[0]++;
else
break;
}
if (n->ext[0])
sprintf((char *)dos, "%.8s.%.3s", n->name, n->ext);
else
sprintf((char *)dos, "%.8s", n->name);
n->next = names;
names = n;
}
/*
* Given a DOS component, compute the REAL component.
*/
void
dos_to_real(u_char *dos, u_char *real)
{
int ncnt = 0;
int ecnt = 0;
u_char name[8];
u_char ext[3];
Name_t *n = names;
while (ncnt < 8 && (isvalid(*dos) || islower(*dos))) {
name[ncnt++] = islower(*dos) ? toupper(*dos) : *dos;
++dos;
}
if (ncnt < 8)
name[ncnt] = 0;
if (isdot(*dos)) {
while (ecnt < 3 && (isvalid(*++dos) || islower(*dos))) {
ext[ecnt++] = islower(*dos) ? toupper(*dos) : *dos;
}
}
if (ecnt < 3)
ext[ecnt] = 0;
while (n) {
if (!ustrncmp(name, n->name, 8) && !ustrncmp(ext, n->ext, 3)) {
ustrcpy(real, n->real);
return;
}
n = n->next;
}
if (ext[0])
sprintf((char *)real, "%-.8s.%-.3s", name, ext);
else
sprintf((char *)real, "%-.8s", name);
while (*real) {
if (isupper(*real))
*real = tolower(*real);
++real;
}
}
/*
* convert a path into an argv[] like vector of components.
* If the path starts with a '/' or '\' then the first entry
* will be "/" or "\". This is the only case in which a "/"
* or "\" may appear in an entry.
* Also convert all lowercase to uppercase.
* The data returned is in a static area, so a second call will
* erase the data of the first.
*/
u_char **
get_entries(u_char *path)
{
static u_char *entries[128]; /* Maximum depth... */
static u_char mypath[1024];
u_char **e = entries;
u_char *p = mypath;
ustrncpy(mypath+1, path, 1022);
p = mypath+1;
mypath[1023] = 0;
if (path[0] == '/' || path[0] == '\\') {
mypath[0] = path[0];
*e++ = mypath;
*p++ = 0;
}
while (*p && e < entries + 127) {
while (*p && (*p == '/' || *p == '\\')) {
++p;
}
if (!*p)
break;
*e++ = p;
while (*p && (*p != '/' && *p != '\\')) {
if (islower(*p))
*p = tolower(*p);
++p;
}
/*
* skip over the '/' or '\'
*/
if (*p)
*p++ = 0;
}
*e = 0;
return (entries);
}
/*
* Return file system statistics for drive.
* Return the DOS errno on failure.
*/
get_space(int drive, fsstat_t *fs)
{
Path_t *d;
struct statfs *buf;
int nfs;
int i;
struct statfs *me = 0;
if (drive < 0 || drive >= MAX_DRIVE)
return (DISK_DRIVE_INVALID);
d = &paths[drive];
if (!d->path)
return (DISK_DRIVE_INVALID);
nfs = getfsstat(0, 0, MNT_WAIT);
buf = (struct statfs *)malloc(sizeof(struct statfs) * nfs);
if (buf == NULL) {
perror("get_space");
return (DISK_DRIVE_INVALID);
}
nfs = getfsstat(buf, sizeof(struct statfs) * nfs, MNT_WAIT);
for (i = 0; i < nfs; ++i) {
if (strncmp(buf[i].f_mntonname, (char *)d->path, strlen(buf[i].f_mntonname)))
continue;
if (me && strlen(me->f_mntonname) > strlen(buf[i].f_mntonname))
continue;
me = buf + i;
}
if (!me) {
free(buf);
return (3);
}
fs->bytes_sector = 512;
fs->sectors_cluster = me->f_bsize / fs->bytes_sector;
fs->total_clusters = me->f_blocks / fs->sectors_cluster;
while (fs->total_clusters > 0xFFFF) {
fs->sectors_cluster *= 2;
fs->total_clusters = me->f_blocks / fs->sectors_cluster;
}
fs->avail_clusters = me->f_bavail / fs->sectors_cluster;
free(buf);
return (0);
}
#if 0
DIR *dp = 0;
u_char searchdir[1024];
u_char *searchend;
#endif
/*
* Convert a dos filename into normal form (8.3 format, space padded)
*/
void
to_dos_fcb(u_char *p, u_char *expr)
{
int i;
if (expr[0] == '.') {
p[0] = '.';
if (expr[1] == '\0') {
for (i = 1; i < 11; i++)
p[i] = ' ';
return;
}
if (expr[1] == '.') {
p[1] = '.';
if (expr[2] == '\0') {
for (i = 2; i < 11; i++)
p[i] = ' ';
return;
}
}
}
for (i = 8; i > 0; i--) {
switch (*expr) {
case '\0':
case '.':
for (; i > 0; i--)
*p++ = ' ';
break;
case '*':
for (; i > 0; i--)
*p++ = '?';
break;
default:
if (islower(*expr)) {
*p++ = toupper(*expr++);
break;
}
case '?':
*p++ = *expr++;
break;
}
}
while (*expr != '\0' && *expr != '.')
++expr;
if (*expr)
++expr;
for (i = 3; i > 0; i--) {
switch (*expr) {
case '\0':
case '.':
for (; i > 0; i--)
*p++ = ' ';
break;
case '*':
for (; i > 0; i--)
*p++ = '?';
break;
default:
if (islower(*expr)) {
*p++ = toupper(*expr++);
break;
}
case '?':
*p++ = *expr++;
break;
}
}
}
/*
** DOS can't handle multiple concurrent searches, and if we leave the
** search instance in the DTA we get screwed as soon as someone starts lots
** of searches without finishing them properly.
** We allocate a single search structure, and recycle it if find_first()
** is called before a search ends.
*/
static search_t dir_search = {dp : NULL};
/*
* Find the first file on drive which matches the path with the given
* attributes attr.
* If found, the result is placed in dir (32 bytes).
* The DTA is populated as required by DOS, but the state area is ignored.
* Returns DOS errno on failure.
*/
find_first(u_char *path, int attr, dosdir_t *dir, find_block_t *dta)
{
u_char newpath[1024], realpath[1024];
u_char *expr, *slash;
int drive;
int error;
search_t *search = &dir_search;
debug(D_REDIR, "find_first(%s, %x, %x)\n", path, attr, dta);
error = dos_makepath(path, newpath);
if (error)
return (error);
expr = newpath;
slash = 0;
while (*expr != '\0') {
if (*expr == '\\' || *expr == '/')
slash = expr;
expr++;
}
*slash++ = '\0';
error = dos_to_real_path(newpath, realpath, &drive);
if (error)
return (error);
if (attr == VOLUME_LABEL) /* never find a volume label */
return (NO_MORE_FILES);
if (search->dp) /* stale search? */
closedir(search->dp);
search->dp = opendir(realpath);
if (search->dp == NULL)
return (PATH_NOT_FOUND);
ustrcpy(search->searchdir, realpath);
search->searchend = search->searchdir;
while (*search->searchend)
++search->searchend;
*search->searchend++ = '/';
search->dp->dd_fd = squirrel_fd(search->dp->dd_fd);
dta->drive = drive | 0x80;
to_dos_fcb(dta->pattern, slash);
dta->flag = attr;
return (find_next(dir, dta));
}
/*
* Continue on where find_first left off.
* The results will be placed in dir.
* DTA state area is ignored.
*/
int
find_next(dosdir_t *dir, find_block_t *dta)
{
search_t *search = &dir_search;
struct dirent *d;
struct stat sb;
u_char name[16];
if (!search->dp)
return (NO_MORE_FILES);
#if 0
debug(D_REDIR, "find_next()\n");
#endif
while (d = readdir(search->dp)) {
real_to_dos((u_char *)d->d_name, name);
to_dos_fcb(dir->name, name);
#if 0
printf("find_next: |%-11.11s| |%-11.11s| |%s| |%s|\n", dta->pattern, dir->name, d->d_name, name);
#endif
if (dos_match(dta->pattern, dir->name) == 0)
continue;
ustrcpy(search->searchend, (u_char *)d->d_name);
if (ustat(search->searchdir, &sb) < 0)
continue;
#if 0
printf("find_next: %x\n", sb.st_mode);
#endif
if (S_ISDIR(sb.st_mode)) {
if (!(dta->flag & DIRECTORY)) {
continue;
}
}
dir->attr = (S_ISDIR(sb.st_mode) ? DIRECTORY : 0) |
(uaccess(search->searchdir, W_OK) < 0 ? READ_ONLY_FILE : 0);
encode_dos_file_time(sb.st_mtime, &dir->date, &dir->time);
dir->start = 1;
dir->size = sb.st_size;
#if 0
printf("find_next: found %s\n",name);
#endif
return (0);
}
closedir(search->dp);
search->dp = NULL;
return (NO_MORE_FILES);
}
/*
* perfrom hokey DOS pattern matching. pattern may contain the wild cards
* '*' and '?' only. Follow the DOS convention that '?*', '*?' and '**' all
* are the same as '*'. Also, allow '?' to match the blank padding in a
* name (hence, ???? matchs all of "a", "ab", "abc" and "abcd" but not "abcde")
* Return 1 if a match is found, 0 if not.
*
* XXX This appears to be severely busted! (no * handling - normal?)
*/
int
dos_match(u_char *pattern, u_char *string)
{
int i;
/*
* Check the base part first
*/
for (i = 11; i > 0; i--) {
if (*pattern != '?' && *string != *pattern)
return (0);
pattern++, string++;
}
return (1);
}