mirror of
https://github.com/Interlisp/maiko.git
synced 2026-03-23 17:13:14 +00:00
* Correct warning: cast to smaller integer type -- X_init/lispbitmap * Fixes to INTRSAFE, INTRSAFE0 and ensure TIMEOUT, TIMEOUT0 used appropriately INTRSAFE and INTRSAFE0 must clear errno before executing the library or system call because not all library calls set errno on success. Avoid casting pointers or larger integer values down to smaller ints before comparing to 0 or -1, and use NULL (a pointer) rather than 0. Fix cases where the result of the library call is a pointer rather than an int to use TIMEOUT0 instead of TIMEOUT, testing for NULL rather than -1 on timeout (errno == EINTR) * Remove useless validity check of LASTVMEMFILEPAGE_word pointer * Convert pointer arithmetic type in drawline from int to ptrdiff_t * Add NOTE warning about a 32-bit vs 64-bit issue affecting currently unused GET_NATIVE_ADDR_FROM_LISP_PTR
2288 lines
63 KiB
C
2288 lines
63 KiB
C
/* $Id: dir.c,v 1.4 2001/12/26 22:17:01 sybalsky Exp $ (C) Copyright Venue, All Rights Reserved */
|
|
|
|
/************************************************************************/
|
|
/* */
|
|
/* (C) Copyright 1989-99 Venue. All Rights Reserved. */
|
|
/* Manufactured in the United States of America. */
|
|
/* */
|
|
/************************************************************************/
|
|
|
|
#include "version.h"
|
|
|
|
#include <errno.h>
|
|
#include <setjmp.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/types.h>
|
|
#include <unistd.h>
|
|
|
|
#ifndef DOS
|
|
#include <dirent.h>
|
|
#include <pwd.h>
|
|
#include <sys/param.h>
|
|
#else /* DOS, now */
|
|
#include <dos.h>
|
|
#define MAXPATHLEN _MAX_PATH
|
|
#define MAXNAMLEN _MAX_PATH
|
|
#define alarm(x) 1
|
|
#endif /* DOS */
|
|
|
|
#include "lispemul.h"
|
|
#include "lispmap.h"
|
|
#include "adr68k.h"
|
|
#include "lsptypes.h"
|
|
#include "arith.h"
|
|
#include "lspglob.h"
|
|
#include "timeout.h"
|
|
#include "locfile.h"
|
|
|
|
extern int *Lisp_errno;
|
|
extern int Dummy_errno;
|
|
|
|
#define DIRCHAR '>'
|
|
|
|
/************************************************************************
|
|
SUBROUTINES
|
|
For pattern matching check
|
|
************************************************************************/
|
|
|
|
/*
|
|
* Name: SetupMatch
|
|
*
|
|
* Argument: char *tname Target name including name ,extension and version.
|
|
* char *pname Pattern including name and extension.
|
|
* char *text The place where separated target extension will be
|
|
* stored.
|
|
* char *pext The place where separated pattern extension will be
|
|
* stored.
|
|
* char *tver The place where separated target version will be
|
|
* stored.
|
|
*
|
|
* Value: N/A
|
|
*
|
|
* Side Effect: The string tname and pname points are destructively modified.
|
|
*
|
|
* Description:
|
|
*
|
|
* Split target and pattern to each component for the convenience of match_pattern
|
|
* routine.
|
|
*/
|
|
|
|
#define SetupMatch(tname, pname, text, pext, tver) \
|
|
{ \
|
|
register char *pp; \
|
|
\
|
|
separate_version(tname, tver, 0); \
|
|
\
|
|
if ((pp = (char *)strrchr(tname, '.')) == NULL) { \
|
|
*(text) = '\0'; \
|
|
} else { \
|
|
*pp = '\0'; \
|
|
strcpy(text, pp + 1); \
|
|
} \
|
|
\
|
|
if ((pp = (char *)strrchr(pname, '.')) == NULL) { \
|
|
*(pext) = '\0'; \
|
|
} else { \
|
|
*pp = '\0'; \
|
|
strcpy(pext, pp + 1); \
|
|
} \
|
|
}
|
|
|
|
#define MatchP(target, name, ver, matchtag, unmatchtag) \
|
|
{ \
|
|
char tname[MAXNAMLEN], text[MAXNAMLEN], tver[VERSIONLEN]; \
|
|
char pname[MAXNAMLEN], pext[MAXNAMLEN]; \
|
|
\
|
|
strcpy(tname, target); \
|
|
DOWNCASE(tname); \
|
|
strcpy(pname, name); \
|
|
DOWNCASE(pname); \
|
|
\
|
|
SetupMatch(tname, pname, text, pext, tver); \
|
|
\
|
|
if (match_pattern(tname, pname) && match_pattern(text, pext) && match_pattern(tver, ver)) \
|
|
goto matchtag; /* NOLINT(bugprone-macro-parentheses) */ \
|
|
else \
|
|
goto unmatchtag; /* NOLINT(bugprone-macro-parentheses) */ \
|
|
}
|
|
|
|
#define MatchP_Case(target, name, ver, matchtag, unmatchtag) \
|
|
{ \
|
|
char tname[MAXNAMLEN], text[MAXNAMLEN], tver[VERSIONLEN]; \
|
|
char pname[MAXNAMLEN], pext[MAXNAMLEN]; \
|
|
\
|
|
strcpy(tname, target); \
|
|
strcpy(pname, name); \
|
|
\
|
|
SetupMatch(tname, pname, text, pext, tver); \
|
|
\
|
|
if (match_pattern(tname, pname) && match_pattern(text, pext) && match_pattern(tver, ver)) \
|
|
goto matchtag; /* NOLINT(bugprone-macro-parentheses) */ \
|
|
else \
|
|
goto unmatchtag; /* NOLINT(bugprone-macro-parentheses) */ \
|
|
}
|
|
|
|
/*
|
|
* Name: match_pattern
|
|
*
|
|
* Argument: char *tp String which is matched against pattern.
|
|
* char *pp String represents a pattern.
|
|
*
|
|
* Value: If target is regarded to match with pattern, returns 1, otherwise 0.
|
|
*
|
|
* Side Effect: None.
|
|
*
|
|
* Description:
|
|
*
|
|
* Matches string against pattern. Wild character is '*', it matches to arbitrary
|
|
* number of characters.
|
|
*/
|
|
|
|
static int match_pattern(char *tp, char *pp)
|
|
{
|
|
register char *tsp, *psp;
|
|
register int inastr;
|
|
|
|
#ifdef DOS
|
|
/* % is not allowed in DOS names for Medley. */
|
|
if (strchr(tp, '%')) return 0;
|
|
|
|
#endif /* DOS */
|
|
|
|
for (tsp = tp, psp = pp, inastr = 0;; tp++, pp++) {
|
|
switch (*pp) {
|
|
case '\0': return ((*tp == '\0') ? 1 : 0);
|
|
|
|
case '*':
|
|
while (*pp == '*') pp++; /* Skip successive '*'s. */
|
|
if (*pp == '\0') return (1);
|
|
|
|
psp = pp;
|
|
while (*tp != *pp && *tp != '\0') tp++;
|
|
|
|
if (*tp == '\0') return (0);
|
|
|
|
tsp = tp;
|
|
inastr = 1;
|
|
|
|
continue;
|
|
|
|
default:
|
|
if (*tp == *pp) continue;
|
|
|
|
if (inastr) {
|
|
/*
|
|
* Try to find a character which match to
|
|
* a character psp points from a character
|
|
* next to tsp. If found retry from there.
|
|
*/
|
|
for (tp = tsp + 1; *tp != '\0' && *tp != *psp; tp++) {}
|
|
if (*tp == '\0') return (0);
|
|
pp = psp;
|
|
tsp = tp;
|
|
continue;
|
|
} else {
|
|
return (0);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#ifdef DOS
|
|
|
|
int make_old_version(char *old, char *file)
|
|
{
|
|
int len = (int)strlen(file) - 1;
|
|
if (file[len] == DIRCHAR) return 0;
|
|
/* look up old versions of files for version # 0's */
|
|
strcpy(old, file);
|
|
|
|
if (old[len] == '.')
|
|
strcat(old, "%");
|
|
else if ((len > 0) && old[len - 1] == '.')
|
|
strcat(old, "%");
|
|
else if ((len > 1) && old[len - 2] == '.')
|
|
strcat(old, "%");
|
|
else if ((len > 2) && old[len - 3] == '.')
|
|
old[len] = '%';
|
|
else
|
|
strcat(old, ".%");
|
|
return 1;
|
|
}
|
|
#endif /* DOS */
|
|
|
|
/************************************************************************/
|
|
/******** E N D O F P A T T E R N - M A T C H I N G C O D E *******/
|
|
/************************************************************************/
|
|
|
|
/************************************************************************/
|
|
/************ B E G I N O F F I L E - I N F O C O D E **************/
|
|
/************************************************************************/
|
|
|
|
/*
|
|
* FINFO and FPROP are used to store the information of the enumerated files
|
|
* and directories. They are arranged in a form of linked list. Each list is
|
|
* corresponding to the each directory enumeration. All of the informations
|
|
* Lisp needs are stored in the list. This list is in the emulator's address space
|
|
* and can be specified by "ID" which is the interface between the emulator and Lisp
|
|
* code. In this implementation, ID is represented as an integer and is actually
|
|
* an index of the array of the lists.
|
|
*
|
|
* To avoid the overhead of the FINFO and FPROP structure dynamic allocation and
|
|
* deallocation, some number of their instances are pre-allocated when the emulator
|
|
* starts and managed in a free list. If all of the pre-allocated instances are in
|
|
* use, new instances are allocated. The new instances are linked to the free list
|
|
* when it is freed.
|
|
*
|
|
* As described above, the linked list result of the enumeration is stored in a
|
|
* array for the subsequent request from Lisp. Lisp code requests the emulator to
|
|
* release the list when it enumerated all of the entries in the list or the
|
|
* enumerating operation is aborted.
|
|
*/
|
|
|
|
typedef struct fprop {
|
|
unsigned length; /* Byte length of this file. */
|
|
unsigned wdate; /* Written (Creation) date in Lisp sense. */
|
|
unsigned rdate; /* Read date in Lisp sense. */
|
|
unsigned protect; /* Protect mode of this file. */
|
|
char author[256]; /* Author in Lisp sense. */
|
|
u_short au_len; /* Byte length of author. */
|
|
unsigned long nil; /* padding to 8-byte multiple */
|
|
} FPROP;
|
|
|
|
/* This structure has a pointer at each end to force alignment to
|
|
be correct when a pointer is 8 bytes long. */
|
|
typedef struct finfo {
|
|
FPROP *prop; /* File properties Lisp needs. */
|
|
char lname[MAXNAMLEN]; /* Name in Lisp Format. */
|
|
u_short lname_len; /* Byte length of lname. */
|
|
char no_ver_name[MAXNAMLEN];
|
|
/*
|
|
* Name in UNIX Format. Does not
|
|
* include Version field.
|
|
* All lower case.
|
|
*/
|
|
ino_t ino; /* I-node number of this file. */
|
|
unsigned version; /* Version in Lisp sense. */
|
|
u_short dirp; /* If 1, this file is a directory. */
|
|
struct finfo *next; /*
|
|
* Link to a next entry. Last entry is
|
|
* indicated by NULL pointer.
|
|
*/
|
|
} FINFO;
|
|
|
|
typedef struct dfinfo {
|
|
FINFO *head; /* Head of the linked FINFO structures. */
|
|
FINFO *next; /* FINFO structure generated next time. */
|
|
} DFINFO;
|
|
|
|
FINFO *FreeFinfoList;
|
|
#define INITFINFONUM 1024
|
|
|
|
DFINFO *FinfoArray;
|
|
#define INITFINFOARRAY 32
|
|
|
|
int MAXFINFO;
|
|
|
|
#define FINFOARRAYRSIZE 16
|
|
|
|
#define AllocFinfo(fp) \
|
|
{ \
|
|
if (FreeFinfoList != (FINFO *)NULL) { \
|
|
(fp) = FreeFinfoList; \
|
|
FreeFinfoList = (fp)->next; \
|
|
} else if (((fp) = (FINFO *)calloc(1, sizeof(FINFO))) == NULL) { \
|
|
(fp) = (FINFO *)NULL; \
|
|
} else if (((fp)->prop = (FPROP *)calloc(1, sizeof(FPROP))) == NULL) { \
|
|
free(fp); \
|
|
(fp) = (FINFO *)NULL; \
|
|
} \
|
|
}
|
|
|
|
#define FreeFinfo(fp) \
|
|
{ \
|
|
register FINFO *lastp; \
|
|
for (lastp = fp; lastp->next != (FINFO *)NULL; lastp = lastp->next) {} \
|
|
lastp->next = FreeFinfoList; \
|
|
FreeFinfoList = fp; \
|
|
}
|
|
|
|
/* XXX: the datatypes need to go into dirdefs.h so that one could include it elsewhere */
|
|
#include "dirdefs.h"
|
|
#include "commondefs.h"
|
|
#include "dskdefs.h"
|
|
#include "ufsdefs.h"
|
|
|
|
/*
|
|
* For debug aid.
|
|
*/
|
|
|
|
#ifdef FSDEBUG
|
|
void print_finfo(FINFO *fp)
|
|
{
|
|
FINFO *sp;
|
|
sp = fp;
|
|
|
|
if (fp != (FINFO *)NULL) {
|
|
do {
|
|
printf("%s -> ", fp->lname);
|
|
printf("%u\n", fp->version);
|
|
fp = fp->next;
|
|
} while (fp != (FINFO *)NULL && fp != sp);
|
|
|
|
if (fp = sp) printf("Circular detected!\n");
|
|
}
|
|
}
|
|
#endif /* FSDEBUG */
|
|
|
|
/*
|
|
* Name: init_finfo
|
|
*
|
|
* Argument: None.
|
|
*
|
|
* Value: If succeed, returns 1, otherwise 0.
|
|
*
|
|
* Side Effect: FreeFinfoList will point to the alloced area. MAXFINFO will hold
|
|
* the total number of allocated instances of FINFO structure.
|
|
*
|
|
* Description:
|
|
*
|
|
* Allocates the storage for the instances of FINFO and FPROP structure and arrange
|
|
* them to build a linked list.
|
|
* This routine is invoked at very first stage of emulator start up.
|
|
*/
|
|
|
|
int init_finfo() {
|
|
register FINFO *cp;
|
|
register int n;
|
|
|
|
if ((FreeFinfoList = (FINFO *)calloc(sizeof(FINFO) + sizeof(FPROP), INITFINFONUM)) ==
|
|
(FINFO *)NULL) {
|
|
*Lisp_errno = errno;
|
|
return (0);
|
|
}
|
|
for (cp = FreeFinfoList, n = INITFINFONUM; n > 1; n--) {
|
|
cp->prop = (FPROP *)(cp + 1);
|
|
cp->next = (FINFO *)((char *)cp + sizeof(FINFO) + sizeof(FPROP));
|
|
cp = cp->next;
|
|
}
|
|
cp->prop = (FPROP *)(cp + 1);
|
|
cp->next = (FINFO *)NULL;
|
|
|
|
if ((FinfoArray = (DFINFO *)calloc(sizeof(DFINFO), INITFINFOARRAY)) == (DFINFO *)NULL) {
|
|
*Lisp_errno = errno;
|
|
return (0);
|
|
}
|
|
MAXFINFO = INITFINFOARRAY;
|
|
|
|
return (1);
|
|
}
|
|
|
|
/*
|
|
* Name: get_finfo_id
|
|
*
|
|
* Argument: None.
|
|
*
|
|
* Value: If succeed, returns the id of linked list of FINFO structures,
|
|
* otherwise -1.
|
|
*
|
|
* Side Effect: If needed, FinfoArray will be extended according to the value of
|
|
* FINFOARRAYRSIZE.
|
|
*
|
|
* Description:
|
|
*
|
|
* Get an ID which can be used to name a linked list of FINFO structure. ID is
|
|
* represented as an integer, and it is actually an index of an array FinfoArray.
|
|
*
|
|
* If all entries of FinfoArray is occupied by linked lists of FINFO structures,
|
|
* extended storage is allocated and old contents of the array are copied to the
|
|
* new area. The size of the extended part is decided by the value of
|
|
* FINFOARRAYRSIZE.
|
|
*/
|
|
|
|
static int get_finfo_id() {
|
|
register int i;
|
|
DFINFO *dfap;
|
|
|
|
for (i = 0; i < MAXFINFO; i++)
|
|
if (FinfoArray[i].head == (FINFO *)0) return (i);
|
|
|
|
if ((dfap = (DFINFO *)calloc(sizeof(DFINFO), MAXFINFO + FINFOARRAYRSIZE)) == (DFINFO *)NULL) {
|
|
*Lisp_errno = errno;
|
|
return (-1);
|
|
}
|
|
for (i = 0; i < MAXFINFO; i++) {
|
|
dfap[i].head = FinfoArray[i].head;
|
|
dfap[i].next = FinfoArray[i].next;
|
|
}
|
|
free(FinfoArray);
|
|
MAXFINFO += FINFOARRAYRSIZE;
|
|
FinfoArray = dfap;
|
|
return (i);
|
|
}
|
|
|
|
/*
|
|
* Name: enum_dsk_prop
|
|
*
|
|
* Argument: char *dir Absolute path of directory in UNIX format.
|
|
* char *name Pattern specify the files to be enumerated.
|
|
* char *ver String representation of version should be
|
|
* enumerated.
|
|
* FINFO **finfo_buf
|
|
* The place where linked list of FINFO structures
|
|
* result of the enumeration will be stored.
|
|
*
|
|
* Value: If succeed, returns the number of enumerated files, otherwise -1.
|
|
*
|
|
* Side Effect: None.
|
|
*
|
|
* Description:
|
|
*
|
|
* Enumerates files and directories matching to the pattern on the specified
|
|
* directory. The pattern matching is done in case insensitive manner.
|
|
* File properties Lisp will need later are also stored in the result linked list
|
|
* of FINFO structures.
|
|
*/
|
|
|
|
#ifdef DOS
|
|
static int enum_dsk_prop(char *dir, char *name, char *ver, FINFO **finfo_buf)
|
|
{
|
|
register struct direct *dp;
|
|
register FINFO *prevp;
|
|
register FINFO *nextp;
|
|
int n, len, rval, res, isslash = 0, drive = 0;
|
|
struct find_t dirp;
|
|
register struct passwd *pwd;
|
|
struct stat sbuf;
|
|
char namebuf[MAXPATHLEN];
|
|
char fver[VERSIONLEN];
|
|
char old[MAXNAMLEN];
|
|
|
|
/* The null directory has to be special cased */
|
|
/* because adjacent \'s in the pathname don't match anything */
|
|
if (dir[1] == DRIVESEP) drive = dir[0];
|
|
|
|
if (strcmp(dir, "\\") == 0)
|
|
isslash = 1;
|
|
else if (drive && (strcmp(dir + 2, "\\") == 0))
|
|
isslash = 1;
|
|
|
|
if (!isslash)
|
|
strcpy(namebuf, dir); /* Only add the dir if it's real */
|
|
else if (drive) {
|
|
namebuf[0] = drive;
|
|
namebuf[1] = DRIVESEP;
|
|
namebuf[2] = '\0';
|
|
} else
|
|
*namebuf = '\0';
|
|
|
|
strcat(namebuf, DIRSEPSTR);
|
|
strcat(namebuf, name);
|
|
|
|
TIMEOUT(res = _dos_findfirst(namebuf, _A_NORMAL | _A_SUBDIR, &dirp));
|
|
if (res < 0) {
|
|
*Lisp_errno = errno;
|
|
return (-1);
|
|
}
|
|
|
|
for (nextp = prevp = (FINFO *)NULL, n = 0; res == 0;
|
|
S_TOUT(res = _dos_findnext(&dirp)), prevp = nextp) {
|
|
if (strcmp(dirp.name, ".") == 0 || strcmp(dirp.name, "..") == 0) continue;
|
|
MatchP(dirp.name, name, ver, match, unmatch);
|
|
unmatch:
|
|
continue;
|
|
match:
|
|
AllocFinfo(nextp);
|
|
if (nextp == (FINFO *)NULL) {
|
|
FreeFinfo(prevp);
|
|
*Lisp_errno = errno;
|
|
return (-1);
|
|
}
|
|
nextp->next = prevp;
|
|
if (isslash) {
|
|
if (drive)
|
|
sprintf(namebuf, "%c:\\%s", drive, dirp.name);
|
|
else
|
|
sprintf(namebuf, "\\%s", dirp.name);
|
|
} else
|
|
sprintf(namebuf, "%s\\%s", dir, dirp.name);
|
|
|
|
TIMEOUT(rval = stat(namebuf, &sbuf));
|
|
if (rval == -1 && errno != ENOENT) {
|
|
/*
|
|
* ENOENT error might be caused by missing symbolic
|
|
* link. We should ignore such error here.
|
|
*/
|
|
FreeFinfo(nextp);
|
|
*Lisp_errno = errno;
|
|
return (-1);
|
|
}
|
|
|
|
strcpy(namebuf, dirp.name);
|
|
if (sbuf.st_mode & S_IFDIR) {
|
|
nextp->dirp = 1;
|
|
quote_dname(namebuf);
|
|
strcpy(nextp->lname, namebuf);
|
|
len = strlen(namebuf);
|
|
*(nextp->lname + len) = DIRCHAR;
|
|
*(nextp->lname + len + 1) = '\0';
|
|
nextp->lname_len = len + 1;
|
|
} else {
|
|
/* All other types than directory. */
|
|
nextp->dirp = 0;
|
|
strcat(namebuf, ".~1~");
|
|
quote_fname(namebuf);
|
|
len = strlen(namebuf);
|
|
strcpy(nextp->lname, namebuf);
|
|
*(nextp->lname + len) = '\0';
|
|
nextp->lname_len = len;
|
|
}
|
|
|
|
strcpy(namebuf, dirp.name);
|
|
len = strlen(namebuf);
|
|
DOWNCASE(namebuf);
|
|
strcpy(nextp->no_ver_name, namebuf);
|
|
nextp->version = 1;
|
|
nextp->ino = sbuf.st_ino;
|
|
nextp->prop->length = (unsigned)sbuf.st_size;
|
|
nextp->prop->wdate = (unsigned)ToLispTime(sbuf.st_mtime);
|
|
nextp->prop->rdate = (unsigned)ToLispTime(sbuf.st_atime);
|
|
nextp->prop->protect = (unsigned)sbuf.st_mode;
|
|
/* TIMEOUT(pwd = getpwuid(sbuf.st_uid));
|
|
if (pwd == (struct passwd *)NULL) {
|
|
nextp->prop->au_len = 0;
|
|
} else {
|
|
len = strlen(pwd->pw_name);
|
|
strcpy(nextp->prop->author, pwd->pw_name);
|
|
*(nextp->prop->author + len) = '\0';
|
|
nextp->prop->au_len = len;
|
|
} */
|
|
n++;
|
|
}
|
|
|
|
/***********************/
|
|
/* Now go looking for version-0 entries */
|
|
/***********************/
|
|
|
|
for (nextp = prevp; nextp; nextp = nextp->next) {
|
|
FINFO *newp;
|
|
|
|
if (!make_old_version(old, nextp->no_ver_name)) continue;
|
|
|
|
if (isslash) {
|
|
if (drive)
|
|
sprintf(namebuf, "%c:\\%s", drive, old);
|
|
else
|
|
sprintf(namebuf, "\\%s", old);
|
|
} else
|
|
sprintf(namebuf, "%s\\%s", dir, old);
|
|
TIMEOUT(rval = stat(namebuf, &sbuf));
|
|
|
|
if (rval == -1) continue;
|
|
|
|
AllocFinfo(newp);
|
|
newp->next = prevp;
|
|
/* All other types than directory. */
|
|
newp->dirp = 0;
|
|
sprintf(namebuf, "%s.~00~", nextp->no_ver_name);
|
|
quote_fname(namebuf);
|
|
len = strlen(namebuf);
|
|
strcpy(newp->lname, namebuf);
|
|
*(newp->lname + len) = '\0';
|
|
newp->lname_len = len;
|
|
|
|
strcpy(newp->no_ver_name, old);
|
|
newp->version = 0;
|
|
newp->ino = sbuf.st_ino;
|
|
newp->prop->length = (unsigned)sbuf.st_size;
|
|
newp->prop->wdate = (unsigned)ToLispTime(sbuf.st_mtime);
|
|
newp->prop->rdate = (unsigned)ToLispTime(sbuf.st_atime);
|
|
newp->prop->protect = (unsigned)sbuf.st_mode;
|
|
n++;
|
|
prevp = newp;
|
|
}
|
|
if (n > 0) *finfo_buf = prevp;
|
|
return (n);
|
|
}
|
|
#else /* DOS */
|
|
static int enum_dsk_prop(char *dir, char *name, char *ver, FINFO **finfo_buf)
|
|
{
|
|
register struct dirent *dp;
|
|
register FINFO *prevp;
|
|
register FINFO *nextp;
|
|
int n, rval;
|
|
size_t len;
|
|
DIR *dirp;
|
|
register struct passwd *pwd;
|
|
struct stat sbuf;
|
|
char namebuf[MAXPATHLEN];
|
|
char fver[VERSIONLEN];
|
|
|
|
errno = 0;
|
|
TIMEOUT0(dirp = opendir(dir));
|
|
if (dirp == NULL) {
|
|
*Lisp_errno = errno;
|
|
return (-1);
|
|
}
|
|
|
|
for (S_TOUT(dp = readdir(dirp)), nextp = prevp = (FINFO *)NULL, n = 0;
|
|
dp != (struct dirent *)NULL || errno == EINTR;
|
|
errno = 0, S_TOUT(dp = readdir(dirp)), prevp = nextp)
|
|
if (dp) {
|
|
if (strcmp(dp->d_name, ".") == 0 || strcmp(dp->d_name, "..") == 0 || dp->d_ino == 0) continue;
|
|
MatchP((char *)dp->d_name, name, ver, match, unmatch);
|
|
unmatch:
|
|
continue;
|
|
match:
|
|
AllocFinfo(nextp);
|
|
if (nextp == (FINFO *)NULL) {
|
|
FreeFinfo(prevp);
|
|
closedir(dirp);
|
|
*Lisp_errno = errno;
|
|
return (-1);
|
|
}
|
|
nextp->next = prevp;
|
|
sprintf(namebuf, "%s/%s", dir, dp->d_name);
|
|
TIMEOUT(rval = stat(namebuf, &sbuf));
|
|
if (rval == -1 && errno != ENOENT) {
|
|
/*
|
|
* ENOENT error might be caused by missing symbolic
|
|
* link. We should ignore such error here.
|
|
*/
|
|
FreeFinfo(nextp);
|
|
closedir(dirp);
|
|
*Lisp_errno = errno;
|
|
return (-1);
|
|
}
|
|
|
|
strcpy(namebuf, dp->d_name);
|
|
if (sbuf.st_mode & S_IFDIR) {
|
|
nextp->dirp = 1;
|
|
quote_dname(namebuf);
|
|
strcpy(nextp->lname, namebuf);
|
|
len = strlen(namebuf);
|
|
*(nextp->lname + len) = DIRCHAR;
|
|
*(nextp->lname + len + 1) = '\0';
|
|
nextp->lname_len = len + 1;
|
|
} else {
|
|
/* All other types than directory. */
|
|
nextp->dirp = 0;
|
|
quote_fname(namebuf);
|
|
len = strlen(namebuf);
|
|
strcpy(nextp->lname, namebuf);
|
|
*(nextp->lname + len) = '\0';
|
|
nextp->lname_len = len;
|
|
}
|
|
|
|
strcpy(namebuf, dp->d_name);
|
|
len = strlen(namebuf);
|
|
separate_version(namebuf, fver, 1);
|
|
DOWNCASE(namebuf);
|
|
strcpy(nextp->no_ver_name, namebuf);
|
|
if (*fver == '\0')
|
|
nextp->version = 0;
|
|
else
|
|
nextp->version = strtoul(fver, (char **)NULL, 10);
|
|
nextp->ino = sbuf.st_ino;
|
|
nextp->prop->length = (unsigned)sbuf.st_size;
|
|
nextp->prop->wdate = (unsigned)ToLispTime(sbuf.st_mtime);
|
|
nextp->prop->rdate = (unsigned)ToLispTime(sbuf.st_atime);
|
|
nextp->prop->protect = (unsigned)sbuf.st_mode;
|
|
TIMEOUT0(pwd = getpwuid(sbuf.st_uid));
|
|
if (pwd == (struct passwd *)NULL) {
|
|
nextp->prop->au_len = 0;
|
|
} else {
|
|
len = strlen(pwd->pw_name);
|
|
strcpy(nextp->prop->author, pwd->pw_name);
|
|
*(nextp->prop->author + len) = '\0';
|
|
nextp->prop->au_len = len;
|
|
}
|
|
n++;
|
|
}
|
|
closedir(dirp);
|
|
if (n > 0) *finfo_buf = prevp;
|
|
return (n);
|
|
}
|
|
#endif /* DOS */
|
|
|
|
/*
|
|
* Name: enum_dsk
|
|
*
|
|
* Argument: char *dir Absolute path of directory in UNIX format.
|
|
* char *name Pattern specify the files to be enumerated.
|
|
* char *ver String representation of version should be
|
|
* enumerated.
|
|
* FINFO **finfo_buf
|
|
* The place where linked list of FINFO structures
|
|
* result of the enumeration will be stored.
|
|
*
|
|
* Value: If succeed, returns the number of enumerated files, otherwise -1.
|
|
*
|
|
* Side Effect: None.
|
|
*
|
|
* Description:
|
|
*
|
|
* Similar to enum_dsk_prop, but file properties are not stored.
|
|
*/
|
|
#ifdef DOS
|
|
static int enum_dsk(char *dir, char *name, char *ver, FINFO **finfo_buf)
|
|
{
|
|
register struct direct *dp;
|
|
register FINFO *prevp;
|
|
register FINFO *nextp;
|
|
int n, len, rval, isslash = 0, drive = 0;
|
|
struct find_t dirp;
|
|
struct stat sbuf;
|
|
char namebuf[MAXPATHLEN];
|
|
char fver[VERSIONLEN];
|
|
char old[MAXPATHLEN];
|
|
|
|
/* The null directory has to be special cased */
|
|
/* because adjacent \'s in the pathname don't match anything */
|
|
if (dir[1] == DRIVESEP) drive = dir[0];
|
|
|
|
if (strcmp(dir, "\\") == 0)
|
|
isslash = 1;
|
|
else if (drive && (strcmp(dir + 2, "\\") == 0))
|
|
isslash = 1;
|
|
|
|
if (!isslash)
|
|
strcpy(namebuf, dir); /* Only add the dir if it's real */
|
|
else if (drive) {
|
|
namebuf[0] = drive;
|
|
namebuf[1] = DRIVESEP;
|
|
namebuf[2] = '\0';
|
|
} else
|
|
*namebuf = '\0';
|
|
|
|
strcat(namebuf, DIRSEPSTR);
|
|
strcat(namebuf, name);
|
|
|
|
TIMEOUT(rval = _dos_findfirst(namebuf, _A_NORMAL | _A_SUBDIR, &dirp));
|
|
if (rval != 0) {
|
|
*Lisp_errno = errno;
|
|
return (-1);
|
|
}
|
|
|
|
for (nextp = prevp = (FINFO *)NULL, n = 0; rval == 0;
|
|
S_TOUT(rval = _dos_findnext(&dirp)), prevp = nextp) {
|
|
if (strcmp(dirp.name, ".") == 0 || strcmp(dirp.name, "..") == 0) continue;
|
|
MatchP(dirp.name, name, ver, match, unmatch);
|
|
unmatch:
|
|
continue;
|
|
match:
|
|
AllocFinfo(nextp);
|
|
if (nextp == (FINFO *)NULL) {
|
|
FreeFinfo(prevp);
|
|
*Lisp_errno = errno;
|
|
return (-1);
|
|
}
|
|
nextp->next = prevp;
|
|
if (isslash) {
|
|
if (drive)
|
|
sprintf(namebuf, "%c:\\%s", drive, dirp.name);
|
|
else
|
|
sprintf(namebuf, "\\%s", dirp.name);
|
|
} else
|
|
sprintf(namebuf, "%s\\%s", dir, dirp.name);
|
|
TIMEOUT(rval = stat(namebuf, &sbuf));
|
|
if (rval == -1 && errno != ENOENT) {
|
|
/*
|
|
* ENOENT error might be caused by missing symbolic
|
|
* link. We should ignore such error here.
|
|
*/
|
|
FreeFinfo(nextp);
|
|
*Lisp_errno = errno;
|
|
return (-1);
|
|
}
|
|
|
|
strcpy(namebuf, dirp.name); /* moved from below 2/26/93 */
|
|
if (sbuf.st_mode & S_IFDIR) {
|
|
nextp->dirp = 1;
|
|
quote_dname(namebuf);
|
|
strcpy(nextp->lname, namebuf);
|
|
len = strlen(namebuf);
|
|
*(nextp->lname + len) = DIRCHAR;
|
|
*(nextp->lname + len + 1) = '\0';
|
|
nextp->lname_len = len + 1;
|
|
} else {
|
|
/* All other types than directory. */
|
|
nextp->dirp = 0;
|
|
strcat(namebuf, ".~1~");
|
|
quote_fname(namebuf);
|
|
len = strlen(namebuf);
|
|
strcpy(nextp->lname, namebuf);
|
|
*(nextp->lname + len) = '\0';
|
|
nextp->lname_len = len;
|
|
}
|
|
|
|
strcpy(namebuf, dirp.name); /* to get real versionless name */
|
|
len = strlen(namebuf);
|
|
DOWNCASE(namebuf);
|
|
strcpy(nextp->no_ver_name, namebuf);
|
|
nextp->version = 1;
|
|
nextp->ino = sbuf.st_ino;
|
|
n++;
|
|
}
|
|
|
|
/***********************/
|
|
/* Now go looking for version-0 entries */
|
|
/***********************/
|
|
|
|
for (nextp = prevp; nextp; nextp = nextp->next) {
|
|
FINFO *newp;
|
|
|
|
if (!make_old_version(old, nextp->no_ver_name)) continue;
|
|
|
|
if (isslash) {
|
|
if (drive)
|
|
sprintf(namebuf, "%c:\\%s", drive, old);
|
|
else
|
|
sprintf(namebuf, "\\%s", old);
|
|
} else
|
|
sprintf(namebuf, "%s\\%s", dir, old);
|
|
TIMEOUT(rval = stat(namebuf, &sbuf));
|
|
|
|
if (rval == -1) continue;
|
|
|
|
AllocFinfo(newp);
|
|
newp->next = prevp;
|
|
/* All other types than directory. */
|
|
newp->dirp = 0;
|
|
sprintf(namebuf, "%s.~00~", nextp->no_ver_name);
|
|
quote_fname(namebuf);
|
|
len = strlen(namebuf);
|
|
strcpy(newp->lname, namebuf);
|
|
*(newp->lname + len) = '\0';
|
|
newp->lname_len = len;
|
|
|
|
strcpy(newp->no_ver_name, old);
|
|
newp->version = 0;
|
|
newp->ino = sbuf.st_ino;
|
|
n++;
|
|
prevp = newp;
|
|
}
|
|
|
|
if (n > 0) *finfo_buf = prevp;
|
|
return (n);
|
|
}
|
|
|
|
#else /* DOS */
|
|
|
|
static int enum_dsk(char *dir, char *name, char *ver, FINFO **finfo_buf)
|
|
{
|
|
register struct dirent *dp;
|
|
register FINFO *prevp;
|
|
register FINFO *nextp;
|
|
int n, rval;
|
|
size_t len;
|
|
DIR *dirp;
|
|
struct stat sbuf;
|
|
char namebuf[MAXPATHLEN];
|
|
char fver[VERSIONLEN];
|
|
|
|
errno = 0;
|
|
TIMEOUT0(dirp = opendir(dir));
|
|
if (dirp == NULL) {
|
|
*Lisp_errno = errno;
|
|
return (-1);
|
|
}
|
|
|
|
for (S_TOUT(dp = readdir(dirp)), nextp = prevp = (FINFO *)NULL, n = 0;
|
|
dp != (struct dirent *)NULL || errno == EINTR;
|
|
errno = 0, S_TOUT(dp = readdir(dirp)), prevp = nextp)
|
|
if (dp) {
|
|
if (strcmp(dp->d_name, ".") == 0 || strcmp(dp->d_name, "..") == 0 || dp->d_ino == 0) continue;
|
|
MatchP((char *)dp->d_name, name, ver, match, unmatch);
|
|
unmatch:
|
|
continue;
|
|
match:
|
|
AllocFinfo(nextp);
|
|
if (nextp == (FINFO *)NULL) {
|
|
FreeFinfo(prevp);
|
|
closedir(dirp);
|
|
*Lisp_errno = errno;
|
|
return (-1);
|
|
}
|
|
nextp->next = prevp;
|
|
sprintf(namebuf, "%s/%s", dir, dp->d_name);
|
|
TIMEOUT(rval = stat(namebuf, &sbuf));
|
|
if (rval == -1 && errno != ENOENT) {
|
|
/*
|
|
* ENOENT error might be caused by missing symbolic
|
|
* link. We should ignore such error here.
|
|
*/
|
|
FreeFinfo(nextp);
|
|
closedir(dirp);
|
|
*Lisp_errno = errno;
|
|
return (-1);
|
|
}
|
|
|
|
strcpy(namebuf, dp->d_name);
|
|
if (sbuf.st_mode & S_IFDIR) {
|
|
nextp->dirp = 1;
|
|
quote_dname(namebuf);
|
|
strcpy(nextp->lname, namebuf);
|
|
len = strlen(namebuf);
|
|
*(nextp->lname + len) = DIRCHAR;
|
|
*(nextp->lname + len + 1) = '\0';
|
|
nextp->lname_len = len + 1;
|
|
} else {
|
|
/* All other types than directory. */
|
|
nextp->dirp = 0;
|
|
quote_fname(namebuf);
|
|
len = strlen(namebuf);
|
|
strcpy(nextp->lname, namebuf);
|
|
*(nextp->lname + len) = '\0';
|
|
nextp->lname_len = len;
|
|
}
|
|
|
|
strcpy(namebuf, dp->d_name);
|
|
len = strlen(namebuf);
|
|
separate_version(namebuf, fver, 1);
|
|
DOWNCASE(namebuf);
|
|
strcpy(nextp->no_ver_name, namebuf);
|
|
if (*fver == '\0')
|
|
nextp->version = 0;
|
|
else
|
|
nextp->version = strtoul(fver, (char **)NULL, 10);
|
|
nextp->ino = sbuf.st_ino;
|
|
n++;
|
|
}
|
|
closedir(dirp);
|
|
if (n > 0) *finfo_buf = prevp;
|
|
return (n);
|
|
}
|
|
#endif /* DOS */
|
|
|
|
/*
|
|
* Name: enum_ufs_prop
|
|
*
|
|
* Argument: char *dir Absolute path of directory in UNIX format.
|
|
* char *name Pattern specify the files to be enumerated.
|
|
* char *ver String representation of version should be
|
|
* enumerated.
|
|
* FINFO **finfo_buf
|
|
* The place where linked list of FINFO structures
|
|
* result of the enumeration will be stored.
|
|
*
|
|
* Value: If succeed, returns the number of enumerated files, otherwise -1.
|
|
*
|
|
* Side Effect: None.
|
|
*
|
|
* Description:
|
|
*
|
|
* Enumerates files and directories matching to the pattern on the specified
|
|
* directory. The pattern matching is done in case sensitive manner.
|
|
* File properties Lisp will need later are also stored in the result linked list
|
|
* of FINFO structures.
|
|
*/
|
|
#ifdef DOS
|
|
static int enum_ufs_prop(char *dir, char *name, char *ver, FINFO **finfo_buf)
|
|
{
|
|
register struct direct *dp;
|
|
register FINFO *prevp;
|
|
register FINFO *nextp;
|
|
int n, len, rval;
|
|
struct find_t dirp;
|
|
/* register struct passwd *pwd; -- From author support */
|
|
struct stat sbuf;
|
|
char namebuf[MAXPATHLEN];
|
|
|
|
TIMEOUT(rval = _dos_findfirst(dir, _A_SUBDIR, &dirp));
|
|
if (rval != 0) {
|
|
*Lisp_errno = errno;
|
|
return (-1);
|
|
}
|
|
|
|
for (nextp = prevp = (FINFO *)NULL, n = 0; rval == 0;
|
|
S_TOUT(rval = _dos_findnext(&dirp)), prevp = nextp) {
|
|
if (strcmp(dirp.name, ".") == 0 || strcmp(dirp.name, "..") == 0) continue;
|
|
MatchP_Case(dirp.name, name, ver, match, unmatch);
|
|
unmatch:
|
|
continue;
|
|
match:
|
|
AllocFinfo(nextp);
|
|
if (nextp == (FINFO *)NULL) {
|
|
FreeFinfo(prevp);
|
|
*Lisp_errno = errno;
|
|
return (-1);
|
|
}
|
|
nextp->next = prevp;
|
|
sprintf(namebuf, "%s\\%s", dir, dirp.name);
|
|
TIMEOUT(rval = stat(namebuf, &sbuf));
|
|
if (rval == -1 && errno != ENOENT) {
|
|
/*
|
|
* ENOENT error might be caused by missing symbolic
|
|
* link. We should ignore such error here.
|
|
*/
|
|
FreeFinfo(nextp);
|
|
*Lisp_errno = errno;
|
|
return (-1);
|
|
}
|
|
|
|
strcpy(namebuf, dirp.name);
|
|
if (sbuf.st_mode & S_IFDIR) {
|
|
nextp->dirp = 1;
|
|
quote_dname(namebuf);
|
|
strcpy(nextp->lname, namebuf);
|
|
len = strlen(namebuf);
|
|
*(nextp->lname + len) = DIRCHAR;
|
|
*(nextp->lname + len + 1) = '\0';
|
|
nextp->lname_len = len + 1;
|
|
} else {
|
|
/* All other types than directory. */
|
|
nextp->dirp = 0;
|
|
quote_fname_ufs(namebuf);
|
|
len = strlen(namebuf);
|
|
strcpy(nextp->lname, namebuf);
|
|
*(nextp->lname + len) = '\0';
|
|
nextp->lname_len = len;
|
|
}
|
|
|
|
strcpy(namebuf, dirp.name);
|
|
len = strlen(namebuf);
|
|
nextp->ino = sbuf.st_ino;
|
|
nextp->prop->length = (unsigned)sbuf.st_size;
|
|
nextp->prop->wdate = (unsigned)ToLispTime(sbuf.st_mtime);
|
|
nextp->prop->rdate = (unsigned)ToLispTime(sbuf.st_atime);
|
|
nextp->prop->protect = (unsigned)sbuf.st_mode;
|
|
/*
|
|
TIMEOUT(pwd = getpwuid(sbuf.st_uid));
|
|
if (pwd == (struct passwd *)NULL) {
|
|
nextp->prop->au_len = 0;
|
|
} else {
|
|
len = strlen(pwd->pw_name);
|
|
strcpy(nextp->prop->author, pwd->pw_name);
|
|
*(nextp->prop->author + len) = '\0';
|
|
nextp->prop->au_len = len;
|
|
}
|
|
*/
|
|
n++;
|
|
}
|
|
if (n > 0) *finfo_buf = prevp;
|
|
return (n);
|
|
}
|
|
#else /* DOS */
|
|
static int enum_ufs_prop(char *dir, char *name, char *ver, FINFO **finfo_buf)
|
|
{
|
|
register struct dirent *dp;
|
|
register FINFO *prevp;
|
|
register FINFO *nextp;
|
|
int n, rval;
|
|
size_t len;
|
|
DIR *dirp;
|
|
/* register struct passwd *pwd; -- From author support */
|
|
struct stat sbuf;
|
|
char namebuf[MAXPATHLEN];
|
|
|
|
errno = 0;
|
|
TIMEOUT0(dirp = opendir(dir));
|
|
if (dirp == NULL) {
|
|
*Lisp_errno = errno;
|
|
return (-1);
|
|
}
|
|
|
|
for (S_TOUT(dp = readdir(dirp)), nextp = prevp = (FINFO *)NULL, n = 0;
|
|
dp != (struct dirent *)NULL || errno == EINTR;
|
|
errno = 0, S_TOUT(dp = readdir(dirp)), prevp = nextp)
|
|
if (dp) {
|
|
if (strcmp(dp->d_name, ".") == 0 || strcmp(dp->d_name, "..") == 0 || dp->d_ino == 0) continue;
|
|
MatchP_Case((char *)dp->d_name, name, ver, match, unmatch);
|
|
unmatch:
|
|
continue;
|
|
match:
|
|
AllocFinfo(nextp);
|
|
if (nextp == (FINFO *)NULL) {
|
|
FreeFinfo(prevp);
|
|
closedir(dirp);
|
|
*Lisp_errno = errno;
|
|
return (-1);
|
|
}
|
|
nextp->next = prevp;
|
|
sprintf(namebuf, "%s/%s", dir, dp->d_name);
|
|
TIMEOUT(rval = stat(namebuf, &sbuf));
|
|
if (rval == -1 && errno != ENOENT) {
|
|
/*
|
|
* ENOENT error might be caused by missing symbolic
|
|
* link. We should ignore such error here.
|
|
*/
|
|
FreeFinfo(nextp);
|
|
closedir(dirp);
|
|
*Lisp_errno = errno;
|
|
return (-1);
|
|
}
|
|
|
|
strcpy(namebuf, dp->d_name);
|
|
if (sbuf.st_mode & S_IFDIR) {
|
|
nextp->dirp = 1;
|
|
quote_dname(namebuf);
|
|
strcpy(nextp->lname, namebuf);
|
|
len = strlen(namebuf);
|
|
*(nextp->lname + len) = DIRCHAR;
|
|
*(nextp->lname + len + 1) = '\0';
|
|
nextp->lname_len = len + 1;
|
|
} else {
|
|
/* All other types than directory. */
|
|
nextp->dirp = 0;
|
|
quote_fname_ufs(namebuf);
|
|
len = strlen(namebuf);
|
|
strcpy(nextp->lname, namebuf);
|
|
*(nextp->lname + len) = '\0';
|
|
nextp->lname_len = len;
|
|
}
|
|
|
|
strcpy(namebuf, dp->d_name);
|
|
len = strlen(namebuf);
|
|
nextp->ino = sbuf.st_ino;
|
|
nextp->prop->length = (unsigned)sbuf.st_size;
|
|
nextp->prop->wdate = (unsigned)ToLispTime(sbuf.st_mtime);
|
|
nextp->prop->rdate = (unsigned)ToLispTime(sbuf.st_atime);
|
|
nextp->prop->protect = (unsigned)sbuf.st_mode;
|
|
/*
|
|
TIMEOUT(pwd = getpwuid(sbuf.st_uid));
|
|
if (pwd == (struct passwd *)NULL) {
|
|
nextp->prop->au_len = 0;
|
|
} else {
|
|
len = strlen(pwd->pw_name);
|
|
strcpy(nextp->prop->author, pwd->pw_name);
|
|
*(nextp->prop->author + len) = '\0';
|
|
nextp->prop->au_len = len;
|
|
}
|
|
*/
|
|
n++;
|
|
}
|
|
closedir(dirp);
|
|
if (n > 0) *finfo_buf = prevp;
|
|
return (n);
|
|
}
|
|
#endif /* DOS */
|
|
|
|
/*
|
|
* Name: enum_ufs
|
|
*
|
|
* Argument: char *dir Absolute path of directory in UNIX format.
|
|
* char *name Pattern specify the files to be enumerated.
|
|
* char *ver String representation of version should be
|
|
* enumerated.
|
|
* FINFO **finfo_buf
|
|
* The place where linked list of FINFO structures
|
|
* result of the enumeration will be stored.
|
|
*
|
|
* Value: If succeed, returns the number of enumerated files, otherwise -1.
|
|
*
|
|
* Side Effect: None.
|
|
*
|
|
* Description:
|
|
*
|
|
* Similar to enum_ufs_prop, but file properties are not stored.
|
|
*/
|
|
#ifdef DOS
|
|
static int enum_ufs(char *dir, char *name, char *ver, FINFO **finfo_buf)
|
|
{
|
|
register struct direct *dp;
|
|
register FINFO *prevp;
|
|
register FINFO *nextp;
|
|
int n, len, rval;
|
|
struct find_t dirp;
|
|
struct stat sbuf;
|
|
char namebuf[MAXPATHLEN];
|
|
|
|
TIMEOUT(rval = _dos_findfirst(dir, _A_SUBDIR, &dirp));
|
|
if (rval != 0) {
|
|
*Lisp_errno = errno;
|
|
return (-1);
|
|
}
|
|
|
|
for (nextp = prevp = (FINFO *)NULL, n = 0; rval == 0;
|
|
S_TOUT(rval = _dos_findnext(&dirp)), prevp = nextp) {
|
|
if (strcmp(dirp.name, ".") == 0 || strcmp(dirp.name, "..") == 0) continue;
|
|
MatchP_Case(dirp.name, name, ver, match, unmatch);
|
|
unmatch:
|
|
continue;
|
|
match:
|
|
AllocFinfo(nextp);
|
|
if (nextp == (FINFO *)NULL) {
|
|
FreeFinfo(prevp);
|
|
*Lisp_errno = errno;
|
|
return (-1);
|
|
}
|
|
nextp->next = prevp;
|
|
sprintf(namebuf, "%s\\%s", dir, dirp.name);
|
|
TIMEOUT(rval = stat(namebuf, &sbuf));
|
|
if (rval == -1 && errno != ENOENT) {
|
|
/*
|
|
* ENOENT error might be caused by missing symbolic
|
|
* link. We should ignore such error here.
|
|
*/
|
|
FreeFinfo(nextp);
|
|
*Lisp_errno = errno;
|
|
return (-1);
|
|
}
|
|
|
|
strcpy(namebuf, dirp.name);
|
|
if (sbuf.st_mode & S_IFDIR) {
|
|
nextp->dirp = 1;
|
|
quote_dname(namebuf);
|
|
strcpy(nextp->lname, namebuf);
|
|
len = strlen(namebuf);
|
|
*(nextp->lname + len) = DIRCHAR;
|
|
*(nextp->lname + len + 1) = '\0';
|
|
nextp->lname_len = len + 1;
|
|
} else {
|
|
/* All other types than directory. */
|
|
nextp->dirp = 0;
|
|
quote_fname_ufs(namebuf);
|
|
len = strlen(namebuf);
|
|
strcpy(nextp->lname, namebuf);
|
|
*(nextp->lname + len) = '\0';
|
|
nextp->lname_len = len;
|
|
}
|
|
|
|
strcpy(namebuf, dirp.name);
|
|
len = strlen(namebuf);
|
|
nextp->ino = sbuf.st_ino;
|
|
n++;
|
|
}
|
|
if (n > 0) *finfo_buf = prevp;
|
|
return (n);
|
|
}
|
|
#else /* DOS */
|
|
static int enum_ufs(char *dir, char *name, char *ver, FINFO **finfo_buf)
|
|
{
|
|
register struct dirent *dp;
|
|
register FINFO *prevp;
|
|
register FINFO *nextp;
|
|
int n, rval;
|
|
size_t len;
|
|
DIR *dirp;
|
|
struct stat sbuf;
|
|
char namebuf[MAXPATHLEN];
|
|
|
|
errno = 0;
|
|
TIMEOUT0(dirp = opendir(dir));
|
|
if (dirp == NULL) {
|
|
*Lisp_errno = errno;
|
|
return (-1);
|
|
}
|
|
|
|
for (S_TOUT(dp = readdir(dirp)), nextp = prevp = (FINFO *)NULL, n = 0;
|
|
dp != (struct dirent *)NULL || errno == EINTR;
|
|
errno = 0, S_TOUT(dp = readdir(dirp)), prevp = nextp)
|
|
if (dp) {
|
|
if (strcmp(dp->d_name, ".") == 0 || strcmp(dp->d_name, "..") == 0 || dp->d_ino == 0) continue;
|
|
MatchP_Case((char *)dp->d_name, name, ver, match, unmatch);
|
|
unmatch:
|
|
continue;
|
|
match:
|
|
AllocFinfo(nextp);
|
|
if (nextp == (FINFO *)NULL) {
|
|
FreeFinfo(prevp);
|
|
closedir(dirp);
|
|
*Lisp_errno = errno;
|
|
return (-1);
|
|
}
|
|
nextp->next = prevp;
|
|
sprintf(namebuf, "%s/%s", dir, dp->d_name);
|
|
TIMEOUT(rval = stat(namebuf, &sbuf));
|
|
if (rval == -1 && errno != ENOENT) {
|
|
/*
|
|
* ENOENT error might be caused by missing symbolic
|
|
* link. We should ignore such error here.
|
|
*/
|
|
FreeFinfo(nextp);
|
|
closedir(dirp);
|
|
*Lisp_errno = errno;
|
|
return (-1);
|
|
}
|
|
|
|
strcpy(namebuf, dp->d_name);
|
|
if (sbuf.st_mode & S_IFDIR) {
|
|
nextp->dirp = 1;
|
|
quote_dname(namebuf);
|
|
strcpy(nextp->lname, namebuf);
|
|
len = strlen(namebuf);
|
|
*(nextp->lname + len) = DIRCHAR;
|
|
*(nextp->lname + len + 1) = '\0';
|
|
nextp->lname_len = len + 1;
|
|
} else {
|
|
/* All other types than directory. */
|
|
nextp->dirp = 0;
|
|
quote_fname_ufs(namebuf);
|
|
len = strlen(namebuf);
|
|
strcpy(nextp->lname, namebuf);
|
|
*(nextp->lname + len) = '\0';
|
|
nextp->lname_len = len;
|
|
}
|
|
|
|
strcpy(namebuf, dp->d_name);
|
|
len = strlen(namebuf);
|
|
nextp->ino = sbuf.st_ino;
|
|
n++;
|
|
}
|
|
closedir(dirp);
|
|
if (n > 0) *finfo_buf = prevp;
|
|
return (n);
|
|
}
|
|
#endif /* DOS*/
|
|
|
|
/*
|
|
* Name: trim_finfo
|
|
*
|
|
* Argument: FINFO **fp Linked list of the numerated FINFO structures.
|
|
*
|
|
* Value: Returns the total number of files still remaining in **fp.
|
|
*
|
|
* Side Effect: None.
|
|
*
|
|
* Description:
|
|
*
|
|
* Giving the linked list of FINFO, take care of versionless files. If the
|
|
* versionless file is not linked any higher versioned file, it is given a highest
|
|
* version. If versionless file is linked to one of versioned file, it is got
|
|
* rid of.
|
|
* This routine is only used by DSK codes.
|
|
*/
|
|
|
|
static int trim_finfo(FINFO **fp)
|
|
{
|
|
#ifndef DOS
|
|
register FINFO *tp, *sp, *mp, *cp, *pp;
|
|
register int num, pnum;
|
|
int linkp;
|
|
char ver[VERSIONLEN];
|
|
|
|
sp = mp = cp = *fp;
|
|
pp = (FINFO *)NULL;
|
|
num = pnum = 0;
|
|
|
|
do {
|
|
if (cp->dirp) {
|
|
pp = cp;
|
|
sp = cp = cp->next;
|
|
pnum++;
|
|
num++;
|
|
continue;
|
|
}
|
|
|
|
if (cp->next != (FINFO *)NULL && strcmp(cp->next->no_ver_name, cp->no_ver_name) == 0) {
|
|
mp = cp = cp->next;
|
|
num++;
|
|
while (cp->next != (FINFO *)NULL && strcmp(cp->next->no_ver_name, cp->no_ver_name) == 0) {
|
|
cp = cp->next;
|
|
num++;
|
|
}
|
|
} else {
|
|
mp = cp;
|
|
}
|
|
|
|
if (sp->version == 0) {
|
|
if (cp != sp) {
|
|
/*
|
|
* Both versionless and versioned files exists.
|
|
*/
|
|
linkp = 0;
|
|
tp = sp;
|
|
do {
|
|
tp = tp->next;
|
|
if (tp->ino == sp->ino) {
|
|
linkp = 1;
|
|
break;
|
|
}
|
|
} while (cp != tp);
|
|
|
|
if (!linkp) {
|
|
/*
|
|
* Versionless is not linked to any versioned
|
|
* file.
|
|
*/
|
|
sprintf(ver, ";%u", mp->version + 1);
|
|
strcat(sp->lname, ver);
|
|
sp->lname_len = strlen(sp->lname);
|
|
pnum = ++num;
|
|
pp = cp;
|
|
sp = cp = cp->next;
|
|
} else {
|
|
/*
|
|
* Versionless is linked to one of versionless
|
|
* files. We can remove it.
|
|
*/
|
|
sp->next = (FINFO *)NULL;
|
|
FreeFinfo(sp);
|
|
pnum = num;
|
|
if (pp != (FINFO *)NULL)
|
|
pp->next = mp;
|
|
else
|
|
*fp = mp;
|
|
pp = cp;
|
|
sp = cp = cp->next;
|
|
}
|
|
} else {
|
|
/*
|
|
* Only versionless file exists. It is regarded as
|
|
* version 1.
|
|
*/
|
|
strcat(cp->lname, ";1");
|
|
cp->lname_len += 2;
|
|
pp = cp;
|
|
sp = cp = cp->next;
|
|
num = ++pnum;
|
|
}
|
|
} else {
|
|
if (cp != sp) {
|
|
/*
|
|
* All files are versioned.
|
|
*/
|
|
pnum = ++num;
|
|
} else {
|
|
/*
|
|
* A versioned file only exists.
|
|
*/
|
|
num = ++pnum;
|
|
}
|
|
pp = cp;
|
|
sp = cp = cp->next;
|
|
}
|
|
} while (sp != (FINFO *)NULL);
|
|
|
|
#else /* DOS version */
|
|
int num = 0;
|
|
FINFO *tp;
|
|
tp = *fp;
|
|
while (tp) {
|
|
num++;
|
|
tp = tp->next;
|
|
}
|
|
#endif /* DOS */
|
|
|
|
return (num);
|
|
}
|
|
|
|
/*
|
|
* Name: trim_finfo_highest
|
|
*
|
|
* Argument: FINFO **fp Linked list of the numerated FINFO structures.
|
|
*
|
|
* Value: Returns the total number of files still remaining in **fp.
|
|
*
|
|
* Side Effect: None.
|
|
*
|
|
* Description:
|
|
*
|
|
* Similar to true_finfo, but the files but the highest versioned file are got rid
|
|
* of.
|
|
*/
|
|
|
|
static int trim_finfo_highest(FINFO **fp, int highestp)
|
|
{
|
|
register FINFO *tp, *sp, *mp, *cp, *pp;
|
|
register int num, pnum;
|
|
int linkp;
|
|
char ver[VERSIONLEN];
|
|
|
|
sp = mp = cp = *fp;
|
|
pp = (FINFO *)NULL;
|
|
num = pnum = 0;
|
|
|
|
do {
|
|
if (cp->dirp) {
|
|
pp = cp;
|
|
sp = cp = cp->next;
|
|
pnum++;
|
|
num++;
|
|
continue;
|
|
}
|
|
|
|
if (cp->next != (FINFO *)NULL && strcmp(cp->next->no_ver_name, cp->no_ver_name) == 0) {
|
|
mp = cp = cp->next;
|
|
num++;
|
|
while (cp->next != (FINFO *)NULL && strcmp(cp->next->no_ver_name, cp->no_ver_name) == 0) {
|
|
cp = cp->next;
|
|
num++;
|
|
}
|
|
} else {
|
|
mp = cp;
|
|
}
|
|
|
|
if (sp->version == 0) {
|
|
if (cp != sp) {
|
|
/*
|
|
* Both versionless and versioned files exists.
|
|
*/
|
|
linkp = 0;
|
|
tp = sp;
|
|
do {
|
|
tp = tp->next;
|
|
if (tp->ino == sp->ino) {
|
|
linkp = 1;
|
|
break;
|
|
}
|
|
} while (cp != tp);
|
|
|
|
if (!linkp) {
|
|
/*
|
|
* Versionless is not linked to any versioned
|
|
* file.
|
|
*/
|
|
sprintf(ver, ";%u", mp->version + 1);
|
|
strcat(sp->lname, ver);
|
|
sp->lname_len = strlen(sp->lname);
|
|
/*
|
|
* Lower versioned files, mp to cp
|
|
* inclusive, should be removed.
|
|
*/
|
|
sp->next = cp->next;
|
|
cp->next = (FINFO *)NULL;
|
|
FreeFinfo(mp);
|
|
num = ++pnum;
|
|
pp = sp;
|
|
sp = cp = pp->next;
|
|
} else {
|
|
/*
|
|
* Versionless is linked to one of versionless
|
|
* files. We can remove it.
|
|
*/
|
|
|
|
if (mp != cp) {
|
|
sp->next = mp->next;
|
|
mp->next = cp->next;
|
|
cp->next = (FINFO *)NULL;
|
|
} else {
|
|
sp->next = (FINFO *)NULL;
|
|
}
|
|
FreeFinfo(sp);
|
|
num = ++pnum;
|
|
if (pp != (FINFO *)NULL)
|
|
pp->next = mp;
|
|
else
|
|
*fp = mp;
|
|
pp = mp;
|
|
sp = cp = mp->next;
|
|
}
|
|
} else {
|
|
/*
|
|
* Only versionless file exists. It is regarded as
|
|
* version 1.
|
|
*/
|
|
strcat(cp->lname, ";1");
|
|
cp->lname_len += 2;
|
|
pp = cp;
|
|
sp = cp = cp->next;
|
|
num = ++pnum;
|
|
}
|
|
} else {
|
|
if (cp != sp) {
|
|
/*
|
|
* All files are versioned.
|
|
* Lower versioned files can be removed.
|
|
*/
|
|
tp = sp->next;
|
|
sp->next = cp->next;
|
|
cp->next = (FINFO *)NULL;
|
|
FreeFinfo(tp);
|
|
num = ++pnum;
|
|
} else {
|
|
/*
|
|
* A versioned file only exists.
|
|
*/
|
|
num = ++pnum;
|
|
}
|
|
pp = sp;
|
|
sp = cp = sp->next;
|
|
}
|
|
} while (sp != (FINFO *)NULL);
|
|
|
|
return (num);
|
|
}
|
|
|
|
/*
|
|
* Name: trim_finfo_version
|
|
*
|
|
* Argument: FINFO **fp Linked list of the numerated FINFO structures.
|
|
* unsigned rver Requested version number.
|
|
*
|
|
* Value: Returns the total number of files still remaining in **fp.
|
|
*
|
|
* Side Effect: None.
|
|
*
|
|
* Description:
|
|
*
|
|
* Similar to true_finfo, but the files but the versioned file with specified version
|
|
* are got rid of.
|
|
*/
|
|
|
|
static int trim_finfo_version(FINFO **fp, unsigned rver)
|
|
{
|
|
register FINFO *tp, *sp, *mp, *cp, *pp, *vp;
|
|
register int num, pnum;
|
|
int linkp;
|
|
char ver[VERSIONLEN];
|
|
|
|
sp = mp = cp = *fp;
|
|
pp = (FINFO *)NULL;
|
|
num = pnum = 0;
|
|
|
|
do {
|
|
if (cp->dirp) {
|
|
/*
|
|
* Directory has no version, thus they should be removed.
|
|
*/
|
|
sp = cp = cp->next;
|
|
continue;
|
|
}
|
|
|
|
if (cp->next != (FINFO *)NULL && strcmp(cp->next->no_ver_name, cp->no_ver_name) == 0) {
|
|
mp = cp = cp->next;
|
|
num++;
|
|
while (cp->next != (FINFO *)NULL && strcmp(cp->next->no_ver_name, cp->no_ver_name) == 0) {
|
|
cp = cp->next;
|
|
num++;
|
|
}
|
|
} else {
|
|
mp = cp;
|
|
}
|
|
|
|
for (tp = sp, vp = (FINFO *)NULL; tp != cp->next; tp = tp->next) {
|
|
if (tp->version == rver) {
|
|
vp = tp;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (vp != (FINFO *)NULL) {
|
|
/*
|
|
* Specified version file exists. Other files should be
|
|
* removed.
|
|
*/
|
|
if (vp == sp) {
|
|
if (cp != sp) {
|
|
vp->next = cp->next;
|
|
cp->next = (FINFO *)NULL;
|
|
FreeFinfo(mp);
|
|
}
|
|
} else {
|
|
for (tp = sp; tp->next != vp; tp = tp->next) {}
|
|
if (vp != cp) {
|
|
tp->next = vp->next;
|
|
vp->next = cp->next;
|
|
cp->next = (FINFO *)NULL;
|
|
} else {
|
|
tp->next = (FINFO *)NULL;
|
|
}
|
|
if (pp != (FINFO *)NULL)
|
|
pp->next = vp;
|
|
else
|
|
*fp = vp;
|
|
FreeFinfo(sp);
|
|
}
|
|
pp = vp;
|
|
sp = cp = vp->next;
|
|
num = ++pnum;
|
|
continue;
|
|
}
|
|
|
|
/*
|
|
* Although there is no file with specified version, versionless
|
|
* file might be interpreted the specified version.
|
|
*/
|
|
if (sp->version == 0) {
|
|
if (cp != sp) {
|
|
/*
|
|
* Both versionless and versioned files exists.
|
|
*/
|
|
linkp = 0;
|
|
tp = sp;
|
|
do {
|
|
tp = tp->next;
|
|
if (tp->ino == sp->ino) {
|
|
linkp = 1;
|
|
break;
|
|
}
|
|
} while (cp != tp);
|
|
|
|
if (!linkp) {
|
|
/*
|
|
* Versionless is not linked to any versioned
|
|
* file.
|
|
*/
|
|
if (mp->version + 1 == rver) {
|
|
sprintf(ver, ";%u", rver);
|
|
strcat(sp->lname, ver);
|
|
sp->lname_len = strlen(sp->lname);
|
|
/*
|
|
* Lower versioned files, mp to cp
|
|
* inclusive, should be removed.
|
|
*/
|
|
sp->next = cp->next;
|
|
cp->next = (FINFO *)NULL;
|
|
FreeFinfo(mp);
|
|
num = ++pnum;
|
|
pp = sp;
|
|
sp = cp = pp->next;
|
|
} else {
|
|
/*
|
|
* sp to cp inclusive, all files,
|
|
* should be removed.
|
|
*/
|
|
tp = cp->next;
|
|
if (pp != (FINFO *)NULL)
|
|
pp->next = tp;
|
|
else
|
|
*fp = tp;
|
|
cp->next = (FINFO *)NULL;
|
|
FreeFinfo(sp);
|
|
sp = cp = tp;
|
|
}
|
|
} else {
|
|
/*
|
|
* Versionless is linked to one of versionless
|
|
* files. We can remove all files, because
|
|
* no versioned file match with rver.
|
|
*/
|
|
tp = cp->next;
|
|
if (pp != (FINFO *)NULL)
|
|
pp->next = tp;
|
|
else
|
|
*fp = tp;
|
|
cp->next = (FINFO *)NULL;
|
|
FreeFinfo(sp);
|
|
sp = cp = tp;
|
|
}
|
|
} else {
|
|
/*
|
|
* Only versionless file exists. It is regarded as
|
|
* version 1. Unless rver is 1, we can remove it.
|
|
*/
|
|
if (rver != 1) {
|
|
cp = sp->next;
|
|
if (pp != (FINFO *)NULL)
|
|
pp->next = cp;
|
|
else
|
|
*fp = cp;
|
|
sp->next = (FINFO *)NULL;
|
|
FreeFinfo(sp);
|
|
sp = cp;
|
|
} else {
|
|
strcat(cp->lname, ";1");
|
|
cp->lname_len += 2;
|
|
pp = cp;
|
|
sp = cp = cp->next;
|
|
num = ++pnum;
|
|
}
|
|
}
|
|
}
|
|
} while (sp != (FINFO *)NULL);
|
|
|
|
return (num);
|
|
}
|
|
|
|
/************************************************************************/
|
|
/************ E N D O F F I L E - I N F O C O D E *****************/
|
|
/************************************************************************/
|
|
|
|
/************************************************************************/
|
|
/********* B E G I N O F F I L E - S O R T I N G C O D E ***********/
|
|
/************************************************************************/
|
|
|
|
/*
|
|
* Name: prepare_sort_buf
|
|
*
|
|
* Argument: FINFO *fp Linked list of FINFO structures being sorted.
|
|
* int n Total number of structures in the above list.
|
|
*
|
|
* Value: If succeed, returns the pointer to the buffer, otherwise NULL
|
|
* pointer.
|
|
*
|
|
* Side Effect: (sizeof(FINFO *) * n) bytes storage are allocated as a sort buffer.
|
|
*
|
|
* Description:
|
|
*
|
|
* Prepare an area to be used as a sort buffer by qsort routine, and arrange the
|
|
* contents of the buffer to be convenience to qsort routine.
|
|
* Caller have to free the area after sorting done.
|
|
*/
|
|
|
|
static FINFO **prepare_sort_buf(register FINFO *fp, register int n)
|
|
{
|
|
register FINFO **bp;
|
|
register FINFO **bufp;
|
|
|
|
if ((bufp = (FINFO **)malloc(sizeof(FINFO *) * n)) == NULL) {
|
|
*Lisp_errno = errno;
|
|
return ((FINFO **)NULL);
|
|
}
|
|
for (bp = bufp; fp != (FINFO *)NULL; fp = fp->next, bp++) *bp = fp;
|
|
|
|
return (bufp);
|
|
}
|
|
|
|
/*
|
|
* Name: dsk_filecmp
|
|
*
|
|
* Argument: FINFO *fp1 A FINFO structure, a file name in it is being compared.
|
|
* FINFO *fp2 A FINFO structure, a file name in it is being compared.
|
|
*
|
|
* Value: Returns -1, 0, or 1, according as s1 is lexically but with case
|
|
* insensitive mode greater than, equal to, or less than c2.
|
|
*
|
|
* Side Effect: None.
|
|
*
|
|
* Description:
|
|
*
|
|
* Compares two file names lexically but with case insensitive mode. Two file names
|
|
* should be processed by UnixVersionToLispVersion to make sure that they have a
|
|
* valid version fields. The version fields comparison is done in numerical manner.
|
|
* Note that the result is in the reversed order.
|
|
*/
|
|
|
|
static int dsk_filecmp(FINFO **fp1, FINFO **fp2)
|
|
{
|
|
register int res;
|
|
unsigned v1, v2;
|
|
|
|
if ((res = strcmp((*fp1)->no_ver_name, (*fp2)->no_ver_name)) != 0) return (res);
|
|
|
|
if ((*fp1)->version == (*fp2)->version) return (0);
|
|
#ifndef DOS
|
|
if ((v1 = (*fp1)->version) == 0) return (-1);
|
|
if ((v2 = (*fp2)->version) == 0) return (1);
|
|
#endif /* DOS */
|
|
return ((v1 < v2) ? 1 : -1);
|
|
}
|
|
|
|
/*
|
|
* Name: unix_filecmp
|
|
*
|
|
* Argument: FINFO *f1 A FINFO structure, a file name in it is being compared.
|
|
* FINFO *f2 A FINFO structure, a file name in it is being compared.
|
|
*
|
|
* Value: Returns -1, 0, or 1, according as s1 is lexically greater than,
|
|
* equal to, or less than c2.
|
|
*
|
|
* Side Effect: None.
|
|
*
|
|
* Description:
|
|
*
|
|
* Compares two file names lexically mode.
|
|
* Note that the result is in the reversed order.
|
|
*/
|
|
|
|
static int unix_filecmp(register FINFO **f1, register FINFO **f2)
|
|
{ return (strcmp((*f1)->lname, (*f2)->lname)); }
|
|
|
|
/*
|
|
* Name: file_sort
|
|
*
|
|
* Argument: FINFO **fpp A pointer to a pointer addressing the linked FINFO
|
|
* being sorted.
|
|
* int n A number of FINFO structure linked.
|
|
* int (*sortfn)()
|
|
* A pointer to a function to be used to sort the FINFOs.
|
|
*
|
|
* Value: If succeed, returns 1, otherwise, 0.
|
|
*
|
|
* Side Effect: None.
|
|
*
|
|
* Description:
|
|
*
|
|
* Sorts the files to be appropriate for Lisp. dsk_filecmp and unix_filecmp are
|
|
* used for {DSK} and {UNIX} device respectively as a sort function.
|
|
*/
|
|
|
|
static int file_sort(register FINFO **fpp, register int n, register int (*sortfn)())
|
|
{
|
|
register FINFO **fp;
|
|
register FINFO **sort_bufp;
|
|
|
|
if ((sort_bufp = prepare_sort_buf(*fpp, n)) == (FINFO **)NULL) return (0);
|
|
|
|
qsort(sort_bufp, n, sizeof(FINFO *), sortfn);
|
|
|
|
/*
|
|
* Relink FINFO structures in a buffer.
|
|
*/
|
|
for (fp = sort_bufp; n > 1; fp++, n--) (*fp)->next = *(fp + 1);
|
|
(*fp)->next = (FINFO *)NULL;
|
|
|
|
*fpp = *sort_bufp;
|
|
|
|
free((char *)sort_bufp);
|
|
|
|
return (1);
|
|
}
|
|
|
|
/************************************************************************/
|
|
/************ E N D O F F I L E - S O R T I N G C O D E ***********/
|
|
/************************************************************************/
|
|
|
|
#ifndef BYTESWAP
|
|
#ifdef BIGVM
|
|
typedef struct ufsgfs {
|
|
unsigned finfoid;
|
|
unsigned fileid;
|
|
unsigned totalnum;
|
|
LispPTR directory;
|
|
unsigned propp : 1;
|
|
unsigned padding : 3;
|
|
unsigned dev : 28;
|
|
LispPTR thisfile;
|
|
int errnum;
|
|
LispPTR name;
|
|
unsigned length;
|
|
unsigned wdate;
|
|
unsigned rdate;
|
|
unsigned protection;
|
|
LispPTR author;
|
|
unsigned aulen;
|
|
} UFSGFS;
|
|
#else
|
|
typedef struct ufsgfs {
|
|
unsigned finfoid;
|
|
unsigned fileid;
|
|
unsigned totalnum;
|
|
LispPTR directory;
|
|
unsigned propp : 1;
|
|
unsigned padding : 7;
|
|
unsigned dev : 24;
|
|
LispPTR thisfile;
|
|
int errnum;
|
|
LispPTR name;
|
|
unsigned length;
|
|
unsigned wdate;
|
|
unsigned rdate;
|
|
unsigned protection;
|
|
LispPTR author;
|
|
unsigned aulen;
|
|
} UFSGFS;
|
|
#endif /* BIGVM */
|
|
|
|
#else /* BYTESWAP */
|
|
|
|
#ifdef BIGVM
|
|
typedef struct ufsgfs {
|
|
unsigned finfoid;
|
|
unsigned fileid;
|
|
unsigned totalnum;
|
|
LispPTR directory;
|
|
unsigned dev : 28;
|
|
unsigned padding : 3;
|
|
unsigned propp : 1;
|
|
LispPTR thisfile;
|
|
int errnum;
|
|
LispPTR name;
|
|
unsigned length;
|
|
unsigned wdate;
|
|
unsigned rdate;
|
|
unsigned protection;
|
|
LispPTR author;
|
|
unsigned aulen;
|
|
} UFSGFS;
|
|
#else
|
|
typedef struct ufsgfs {
|
|
unsigned finfoid;
|
|
unsigned fileid;
|
|
unsigned totalnum;
|
|
LispPTR directory;
|
|
unsigned dev : 24;
|
|
unsigned padding : 7;
|
|
unsigned propp : 1;
|
|
LispPTR thisfile;
|
|
int errnum;
|
|
LispPTR name;
|
|
unsigned length;
|
|
unsigned wdate;
|
|
unsigned rdate;
|
|
unsigned protection;
|
|
LispPTR author;
|
|
unsigned aulen;
|
|
} UFSGFS;
|
|
#endif /* BIGVM */
|
|
#endif /* BYTESWAP */
|
|
|
|
/*
|
|
* Name: COM_gen_files
|
|
*
|
|
* Argument: LispPTR *args args[0]
|
|
* The pattern of file name to be enumerated in Lisp
|
|
* format. Includes the host field.
|
|
* args[1]
|
|
* Flag indicating whether Lisp needs property or not.
|
|
* args[2]
|
|
* The place where the file info ID should be placed.
|
|
* args[3]
|
|
* The place where the error number should be stored.
|
|
*
|
|
* Value: If succeed, returns the Lisp positive integer which represents the
|
|
* total number of enumerated files, otherwise Lisp -1.
|
|
*
|
|
* Side Effect: None.
|
|
*
|
|
* Description:
|
|
*
|
|
* The implementation of GENERATEFILES FDEV method for DSK and UNIX device.
|
|
* Enumerates files matching pattern.
|
|
*/
|
|
|
|
LispPTR COM_gen_files(register LispPTR *args)
|
|
{
|
|
char fbuf[MAXPATHLEN + 5], dir[MAXPATHLEN], pattern[MAXPATHLEN];
|
|
char host[MAXNAMLEN], name[MAXNAMLEN], ver[VERSIONLEN];
|
|
#ifdef DOS
|
|
char drive[1];
|
|
#endif
|
|
int dskp, count, highestp, fid;
|
|
unsigned propp, version;
|
|
register char *cp;
|
|
FINFO *fp;
|
|
int dsk_filecmp(), unix_filecmp();
|
|
|
|
ERRSETJMP(GetSmallp(-1));
|
|
|
|
Lisp_errno = (int *)(Addr68k_from_LADDR(args[3]));
|
|
|
|
LispStringLength(args[0], count, dskp);
|
|
/*
|
|
* Because of the version number convention, Lisp pathname might
|
|
* be shorter than UNIX one. For THIN string, the difference
|
|
* is 2 bytes, for FAT string, 4 bytes. Add 1 byte for NULL
|
|
* terminating character.
|
|
*/
|
|
count = dskp ? count + 4 + 1 : count + 2 + 1;
|
|
/* Add 5 for the host name field in Lisp format. */
|
|
if (count > MAXPATHLEN + 5) FileNameTooLong((GetSmallp(-1)));
|
|
|
|
LispStringToCString(args[0], fbuf, MAXPATHLEN);
|
|
#ifdef DOS
|
|
separate_host(fbuf, host, drive);
|
|
#else
|
|
separate_host(fbuf, host);
|
|
#endif /* DOS */
|
|
|
|
UPCASE(host);
|
|
if (strcmp(host, "DSK") == 0)
|
|
dskp = 1;
|
|
else if (strcmp(host, "UNIX") == 0)
|
|
dskp = 0;
|
|
else
|
|
return (NIL);
|
|
|
|
if (args[1] == NIL)
|
|
propp = 0;
|
|
else
|
|
propp = 1;
|
|
|
|
/*
|
|
* The way to deal with the version field in file enumeration is a little
|
|
* bit tricky because of the bad specification of original {UNIX} device.
|
|
*
|
|
* According to the Medley 1.1 release note, in the representation
|
|
* "{UNIX}<dir>name.ext;3", ';' and '3' are regarded as a part of the
|
|
* file name, not its version. On the other hand, in 1.1 implementation,
|
|
* in the pattern "{UNIX}<dir>*.*;*", the ';' and the last '*' are regarded
|
|
* as a version field, not part of the file name. Actually the pattern
|
|
* "{UNIX}<tmp>*.*;*" enumerates all of the files on /tmp directory
|
|
* even if they never include ';' character in its name, as well as '.'.
|
|
*
|
|
* Thus I believe, the specification should be clean upped as like,
|
|
* "UNIX device always ignores the version field in it file name representation
|
|
* even if a user specifies it explicitly".
|
|
* But to keep a compatibility to an already released version, we have
|
|
* to do some trick here.
|
|
*/
|
|
|
|
#ifdef DOS
|
|
if (!unixpathname(fbuf, pattern, 1, 1, drive, 0, 0)) {
|
|
#else
|
|
if (!unixpathname(fbuf, pattern, 1, 1)) {
|
|
#endif /* DOS */
|
|
/* Yes, always dskp is on */
|
|
return (GetSmallp(-1));
|
|
}
|
|
|
|
if (!unpack_filename(pattern, dir, name, ver, 0)) return (GetSmallp(-1));
|
|
|
|
if (dskp) {
|
|
/*
|
|
* On {DSK}, we have to make sure dir is case insensitively existing
|
|
* directory.
|
|
*/
|
|
if (true_name(dir) != -1) return (GetSmallp(-1));
|
|
|
|
if (*ver != '\0') {
|
|
highestp = 0;
|
|
version = strtoul(ver, (char **)NULL, 10);
|
|
if (version > 0) strcpy(ver, "*");
|
|
} else {
|
|
version = 0;
|
|
for (cp = fbuf; *cp; cp++) {}
|
|
if (*(cp - 1) == ';' && *(cp - 2) != '\'') {
|
|
/*
|
|
* An empty version is interpreted as wanting the
|
|
* highest version. In this case, at first enumerate
|
|
* all version. trim_finfo_highest will get rid of
|
|
* lower versions.
|
|
*/
|
|
strcpy(ver, "*");
|
|
highestp = 1;
|
|
} else {
|
|
highestp = 0;
|
|
}
|
|
}
|
|
if (propp)
|
|
count = enum_dsk_prop(dir, name, ver, &fp);
|
|
else
|
|
count = enum_dsk(dir, name, ver, &fp);
|
|
} else {
|
|
/* Makes UNIX device matches any version. */
|
|
strcpy(ver, "*");
|
|
|
|
if (propp)
|
|
count = enum_ufs_prop(dir, name, ver, &fp);
|
|
else
|
|
count = enum_ufs(dir, name, ver, &fp);
|
|
}
|
|
|
|
switch (count) {
|
|
case -1: return (GetSmallp(-1));
|
|
|
|
case 0: return (GetSmallp(0));
|
|
|
|
default:
|
|
if (!file_sort(&fp, count, dskp ? dsk_filecmp : unix_filecmp)) return (GetSmallp(-1));
|
|
if (dskp) {
|
|
if (highestp)
|
|
count = trim_finfo_highest(&fp, highestp);
|
|
else if (version > 0 && count > 0)
|
|
count = trim_finfo_version(&fp, version);
|
|
else
|
|
count = trim_finfo(&fp);
|
|
}
|
|
|
|
if ((fid = get_finfo_id()) < 0) return (GetSmallp(-1));
|
|
*(int *)(Addr68k_from_LADDR(args[2])) = fid;
|
|
FinfoArray[fid].head = fp;
|
|
FinfoArray[fid].next = fp;
|
|
return (GetSmallp(count));
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Name: COM_next_file
|
|
*
|
|
* Argument: LispPTR *args args[0]
|
|
* Lisp pointer to UFSGFS structure.
|
|
*
|
|
* Value: If succeed, returns the length of the file name as a Lisp positive
|
|
* integer, otherwise -1.
|
|
*
|
|
* Side Effect: None.
|
|
*
|
|
* Description:
|
|
*
|
|
* The implementation of NEXTFILEFN File Generator Component for DSK and UNIX device.
|
|
* Because of the efficiency reason, if propp, stores properties as well as file
|
|
* name.
|
|
*/
|
|
|
|
LispPTR COM_next_file(register LispPTR *args)
|
|
{
|
|
register LispPTR laddr;
|
|
register FPROP *pp;
|
|
register FINFO *fp;
|
|
register char *base;
|
|
register DFINFO *dfp;
|
|
register UFSGFS *gfsp;
|
|
int finfoid;
|
|
unsigned propp;
|
|
|
|
ERRSETJMP(-1);
|
|
Lisp_errno = &Dummy_errno;
|
|
|
|
gfsp = (UFSGFS *)(Addr68k_from_LADDR(args[0]));
|
|
|
|
finfoid = (int)gfsp->finfoid;
|
|
|
|
if (finfoid < 0 || MAXFINFO - 1 < finfoid) return (GetSmallp(-1));
|
|
|
|
propp = gfsp->propp;
|
|
|
|
dfp = &FinfoArray[finfoid];
|
|
if (dfp->head == (FINFO *)0 || (fp = dfp->next) == (FINFO *)0) return (GetSmallp(-1));
|
|
dfp->next = fp->next;
|
|
|
|
laddr = gfsp->name;
|
|
STRING_BASE(laddr, base);
|
|
#ifndef BYTESWAP
|
|
strncpy(base, fp->lname, fp->lname_len);
|
|
#else
|
|
StrNCpyFromCToLisp(base, fp->lname, fp->lname_len);
|
|
#endif /* BYTESWAP */
|
|
|
|
if (!propp) return (GetSmallp(fp->lname_len));
|
|
|
|
pp = fp->prop;
|
|
gfsp->length = pp->length;
|
|
gfsp->wdate = pp->wdate;
|
|
gfsp->rdate = pp->rdate;
|
|
gfsp->protection = pp->protect;
|
|
|
|
laddr = gfsp->author;
|
|
STRING_BASE(laddr, base);
|
|
#ifndef BYTESWAP
|
|
strncpy(base, pp->author, pp->au_len);
|
|
#else
|
|
StrNCpyFromCToLisp(base, pp->author, pp->au_len);
|
|
#endif /* BYTESWAP */
|
|
|
|
gfsp->aulen = pp->au_len;
|
|
|
|
return (GetSmallp(fp->lname_len));
|
|
}
|
|
|
|
/*
|
|
* Name: COM_finish_finfo
|
|
*
|
|
* Argument: LispPTR *args args[0]
|
|
* Finfo ID.
|
|
*
|
|
* Value: If succeed, returns ATOM_T, otherwise Lisp NIL.
|
|
*
|
|
* Side Effect: None.
|
|
*
|
|
* Description:
|
|
*
|
|
* When Lisp directory enumeration file generator is exhausted or the enumerating
|
|
* operation is aborted, this routine is called.
|
|
* Abandon all cached information corresponding to the generator.
|
|
*/
|
|
|
|
LispPTR COM_finish_finfo(register LispPTR *args)
|
|
{
|
|
register DFINFO *dfp;
|
|
register FINFO *fp;
|
|
register int finfoid;
|
|
|
|
ERRSETJMP(NIL);
|
|
|
|
Lisp_errno = &Dummy_errno;
|
|
|
|
finfoid = LispNumToCInt(args[0]);
|
|
|
|
if (finfoid < 0 || MAXFINFO - 1 < finfoid) return (NIL);
|
|
|
|
dfp = &FinfoArray[finfoid];
|
|
if ((fp = dfp->head) == (FINFO *)0) {
|
|
dfp->next = (FINFO *)0;
|
|
return (NIL);
|
|
}
|
|
|
|
dfp->head = (FINFO *)0;
|
|
dfp->next = (FINFO *)0;
|
|
FreeFinfo(fp);
|
|
|
|
return (ATOM_T);
|
|
}
|