mirror of
https://github.com/Interlisp/maiko.git
synced 2026-01-15 15:57:13 +00:00
2323 lines
64 KiB
C
2323 lines
64 KiB
C
/* $Id: dir.c,v 1.4 2001/12/26 22:17:01 sybalsky Exp $ (C) Copyright Venue, All Rights Reserved */
|
|
static char *id = "$Id: dir.c,v 1.4 2001/12/26 22:17:01 sybalsky Exp $ Copyright (C) Venue";
|
|
|
|
/************************************************************************/
|
|
/* */
|
|
/* (C) Copyright 1989-99 Venue. All Rights Reserved. */
|
|
/* Manufactured in the United States of America. */
|
|
/* */
|
|
/************************************************************************/
|
|
|
|
#include "version.h"
|
|
|
|
#include <sys/types.h>
|
|
#include <setjmp.h>
|
|
#ifndef DOS
|
|
#include <sys/param.h>
|
|
#ifndef OS5
|
|
#ifndef FREEBSD
|
|
#include <sys/dir.h>
|
|
#endif /* FREEBSD */
|
|
#endif /* OS5 */
|
|
#include <sys/stat.h>
|
|
#include <setjmp.h>
|
|
#include <pwd.h>
|
|
|
|
#ifndef SYSVONLY
|
|
#include <strings.h>
|
|
/* #else */
|
|
/* #include <string.h> */
|
|
#endif /* SYSVONLY */
|
|
|
|
#if defined(LINUX) || defined(MACOSX) || defined(FREEBSD) || defined(OS5)
|
|
#include <string.h>
|
|
#endif /* LINUX */
|
|
|
|
#ifdef INDIGO
|
|
#include <strings.h>
|
|
#endif
|
|
|
|
#ifdef RISCOS
|
|
#include <dirent.h>
|
|
#define direct dirent
|
|
#endif /* RISCOS */
|
|
|
|
#ifdef ISC
|
|
#include <dirent.h>
|
|
#include <unistd.h>
|
|
#include <sys/bsdtypes.h>
|
|
#define direct dirent
|
|
#endif /* ISC */
|
|
|
|
#else /* DOS, now */
|
|
#include <dos.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
#include <sys/stat.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#define index strchr
|
|
#define rindex strrchr
|
|
#define MAXPATHLEN _MAX_PATH
|
|
#define MAXNAMLEN _MAX_PATH
|
|
#define alarm(x) 1
|
|
#endif /* DOS */
|
|
|
|
#if defined(SYSVONLY) || defined(MACOSX) || defined(FREEBSD) || defined(LINUX)
|
|
#include <unistd.h>
|
|
#endif /* SYSVONLY */
|
|
|
|
#if defined(OS5) || defined(FREEBSD)
|
|
#include <dirent.h>
|
|
#define direct dirent
|
|
#endif
|
|
|
|
#include <stdio.h>
|
|
#include <errno.h>
|
|
#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 *)rindex(tname, '.')) == NULL) { \
|
|
*text = '\0'; \
|
|
} else { \
|
|
*pp = '\0'; \
|
|
strcpy(text, pp + 1); \
|
|
} \
|
|
\
|
|
if ((pp = (char *)rindex(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; \
|
|
else \
|
|
goto unmatchtag; \
|
|
}
|
|
|
|
#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; \
|
|
else \
|
|
goto unmatchtag; \
|
|
}
|
|
|
|
/*
|
|
* 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
|
|
|
|
unsigned 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("%d\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 suceed, 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 suceed, 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 direct *dp;
|
|
register FINFO *prevp;
|
|
register FINFO *nextp;
|
|
int n, len, rval;
|
|
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 direct *)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 = atoi(fver);
|
|
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_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 direct *dp;
|
|
register FINFO *prevp;
|
|
register FINFO *nextp;
|
|
int n, len, rval;
|
|
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 direct *)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 = atoi(fver);
|
|
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;
|
|
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 direct *dp;
|
|
register FINFO *prevp;
|
|
register FINFO *nextp;
|
|
int n, len, rval;
|
|
DIR *dirp;
|
|
register struct passwd *pwd;
|
|
struct stat sbuf;
|
|
char namebuf[MAXPATHLEN];
|
|
|
|
errno = 0;
|
|
TIMEOUT(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 direct *)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 direct *dp;
|
|
register FINFO *prevp;
|
|
register FINFO *nextp;
|
|
int n, len, rval;
|
|
DIR *dirp;
|
|
struct stat sbuf;
|
|
char namebuf[MAXPATHLEN];
|
|
|
|
errno = 0;
|
|
TIMEOUT(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 direct *)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, ";%d", 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, ";%d", 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.
|
|
* int 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, int 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, ";%d", 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, 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], drive[1];
|
|
int dskp, count, highestp, propp, fid, 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 = atoi(ver);
|
|
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, 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);
|
|
}
|