unzip/tandem/tandem.c

890 lines
24 KiB
C

/*
Copyright (c) 1990-2002 Info-ZIP. All rights reserved.
See the accompanying file LICENSE, version 2000-Apr-09 or later
(the contents of which are also included in zip.h) for terms of use.
If, for some reason, all these files are missing, the Info-ZIP license
also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
*/
/*
* routines common to TANDEM (ZIP and UNZIP)
*/
#include "zip.h" /* This sets up ZIP / UNZIP define */
#include <tal.h>
#include "$system.zsysdefs.zsysc" nolist
#include <cextdecs> nolist
#include "tannsk.h"
static time_t gmt_to_time_t (long long *);
int isatty (fnum)
int fnum;
{
return 1;
}
/********************/
/* Function in2ex() */
/********************/
#ifdef UNZIP
char *in2ex(__G__ n)
__GDEF
#else
char *in2ex(n)
#endif
char *n; /* internal file name */
/* Convert the zip file name to an external file name, returning the malloc'ed
string or NULL if not enough memory. */
{
char *x; /* external file name buffer */
char *y; /* pointer to external buffer */
char *max; /* pointer to max end of next file part */
char *t; /* pointer to internal - start of substring */
char *p; /* pointer to internal - TANDEM delimiter */
char *e; /* pointer to internal - DOS extension delimiter */
char *z; /* pointer to internal - end of substring */
int len; /* length of substring to copy to external name */
int allow_dollar; /* $ symbol allowed as next character */
if ((x = malloc(strlen(n) + 4)) == NULL) /* + 4 for safety */
return NULL;
*x = '\0';
/* Junk pathname as requested */
#ifdef UNZIP
if (uO.jflag && (t = strrchr(n, INTERNAL_DELIMITER)) != NULL)
++t;
else
t = n;
#endif /* UNZIP */
#ifdef ZIP
if (!pathput)
t = last(n, INTERNAL_DELIMITER);
else
t = n;
#endif /* ZIP */
allow_dollar = TRUE;
while (*t != '\0') { /* File part could be sys, vol, subvol or file */
if (*t == INTERNAL_DELIMITER) { /* System, Volume or Subvol Name */
t++;
if (*t == INTERNAL_DELIMITER) { /* System */
strcat(x, TANDEM_NODE_STR);
t++;
}
else {
strcat(x, TANDEM_DELIMITER_STR);
allow_dollar = FALSE;
}
}
/* Work out where end of current external string is */
y = x + strlen(x);
/* Work out substring to copy and externalise */
p = strchr(t, INTERNAL_DELIMITER);
e = strchr(t, DOS_EXTENSION);
if (p != NULL) {
if (e > p)
e = NULL;
}
z = e;
if (z == NULL)
z = p;
if (z == NULL)
z = t + strlen(t);
/* can't have Tandem name longer than 8 characters */
max = y + MAXFILEPARTLEN;
/* Allow $ symbol as first character in some cases */
if (*t == '$') {
if (allow_dollar)
*y++ = *t++;
else;
*t++;
}
/* Make sure first real character is alpha */
if (! isalpha(*t) )
*y++ = 'A';
/* Characters left to process */
len = z - t;
while ( len > 0 ) {
if ( isalnum(*t) ) {
*y++ = toupper(*t++);
if (y >= max)
break;
}
else
t++;
len--;
}
*y = '\0';
t = p;
if (p == NULL) {
/* Last part of filename, store pseudo extension if available */
if (e != NULL) {
strcat(x, TANDEM_EXTENSION_STR);
y = x + strlen(x);
/* no restriction on extension length as its virtual */
z = e + 1;
while ( *z != '\0' ) {
*y++ = toupper(*z++);
}
*y = '\0';
}
break;
}
}
return x;
}
void zexit(status)
int status;
{
/* Exit(>0) creates saveabend files */
terminate_program (0,0,(short)status,,,);
}
/************************/
/* Function zputc() */
/************************/
#ifdef putc
# undef putc
#endif
int zputc(ch, fptr)
int ch;
FILE *fptr;
{
int err;
err = putc(ch,fptr);
fflush(fptr);
return err;
}
#define putc zputc
#ifdef LICENSED
_tal _priv short FILE_CHANGELABEL_ (
short, /* IN */
short, /* IN */
const short _far * /* IN */
);
_c _callable int changelabel OF((short, const short *, const short *));
_c _callable int changelabel(fnum, modtime, actime)
short fnum;
const short *modtime;
const short *actime;
{
int err;
err = FILE_CHANGELABEL_(fnum, 16, modtime);
if (!err)
err = FILE_CHANGELABEL_(fnum, 17, actime);
return err;
}
int islicensed(void)
{
#define plist_items 1
#define plist_size 10
short myphandle[ZSYS_VAL_PHANDLE_WLEN];
short licensetag[plist_items] = {37};
short licensed[plist_size];
short maxlen = plist_size;
short items = plist_items;
short resultlen[1], err;
err = PROCESSHANDLE_NULLIT_(myphandle);
if (!err)
err = PROCESS_GETINFO_(myphandle);
if (!err)
err = PROCESS_GETINFOLIST_(/*cpu*/,
/*pin*/,
/*nodename*/,
/*nodenamelen*/,
myphandle,
licensetag,
items,
licensed,
maxlen,
resultlen
);
if (err != 0)
return 0;
else
return licensed[0];
}
#endif /* LICENSED */
int utime(file, time)
const char *file;
const ztimbuf *time;
{
#ifdef LICENSED
int result, err;
union timestamp_ov {
long long fulltime;
short wordtime[4];
};
union timestamp_ov lasttime, opentime;
struct tm *modt, *opent;
short datetime[8], errormask[1];
short len, fnum, access, exclus, options;
char fname[FILENAME_MAX + 1];
short extension;
char ext[EXTENSION_MAX + 1];
if (islicensed() ) {
/* Attempt to update file label */
modt = gmtime( &time->modtime );
datetime[0] = modt->tm_year + 1900;
datetime[1] = modt->tm_mon + 1;
datetime[2] = modt->tm_mday;
datetime[3] = modt->tm_hour;
datetime[4] = modt->tm_min;
datetime[5] = modt->tm_sec;
datetime[6] = datetime[7] = 0;
errormask[0] = 0;
lasttime.fulltime = COMPUTETIMESTAMP (datetime, errormask);
opent = gmtime( &time->actime );
datetime[0] = opent->tm_year + 1900;
datetime[1] = opent->tm_mon + 1;
datetime[2] = opent->tm_mday;
datetime[3] = opent->tm_hour;
datetime[4] = opent->tm_min;
datetime[5] = opent->tm_sec;
datetime[6] = datetime[7] = 0;
errormask[0] = 0;
opentime.fulltime = COMPUTETIMESTAMP (datetime, errormask);
/* Remove any (pseudo) file extension */
extension = parsename (file,fname,ext);
len = strlen(fname);
access = NSK_WRONLY;
exclus = NSK_SHARED;
options = NSK_NOUPDATEOPENTIME;
extension = parsename (file,fname,ext);
len = strlen(fname);
err = FILE_OPEN_((char *)fname, len, &fnum, access, exclus,,,options,,,);
result = changelabel(fnum,lasttime.wordtime,opentime.wordtime);
err = FILE_CLOSE_(fnum);
return result;
}
return -1;
#else /* !LICENSED */
return 0; /* "no error", to suppress annoying failure messages */
#endif /* ?LICENSED */
}
/* TANDEM version of chmod() function */
int chmod(file, unix_sec)
const char *file;
mode_t unix_sec;
{
FILE *stream;
struct nsk_sec_type {
unsigned progid : 1;
unsigned clear : 1;
unsigned null : 2;
unsigned read : 3;
unsigned write : 3;
unsigned execute: 3;
unsigned purge : 3;
};
union nsk_sec_ov {
struct nsk_sec_type bit_ov;
short int_ov;
};
union nsk_sec_ov nsk_sec;
short fnum, err, nsk_sec_int;
short len, access, exclus, extension, options;
char fname[FILENAME_MAX + 1];
char ext[EXTENSION_MAX + 1];
nsk_sec.bit_ov.progid = 0;
nsk_sec.bit_ov.clear = 0;
nsk_sec.bit_ov.null = 0;
/* 4="N", 5="C", 6="U", 7="-" */
if (unix_sec & S_IROTH) nsk_sec.bit_ov.read = 4;
else if (unix_sec & S_IRGRP) nsk_sec.bit_ov.read = 5;
else if (unix_sec & S_IRUSR) nsk_sec.bit_ov.read = 6;
else nsk_sec.bit_ov.read = 7;
if (unix_sec & S_IWOTH) nsk_sec.bit_ov.write = 4;
else if (unix_sec & S_IWGRP) nsk_sec.bit_ov.write = 5;
else if (unix_sec & S_IWUSR) nsk_sec.bit_ov.write = 6;
else nsk_sec.bit_ov.write = 7;
if (unix_sec & S_IXOTH) nsk_sec.bit_ov.execute = 4;
else if (unix_sec & S_IXGRP) nsk_sec.bit_ov.execute = 5;
else if (unix_sec & S_IXUSR) nsk_sec.bit_ov.execute = 6;
else nsk_sec.bit_ov.execute = 7;
nsk_sec.bit_ov.purge = nsk_sec.bit_ov.write;
nsk_sec_int = nsk_sec.int_ov;
access = NSK_RDONLY;
exclus = NSK_SHARED;
options = NSK_NOUPDATEOPENTIME;
extension = parsename (file,fname,ext);
len = strlen(fname);
err = FILE_OPEN_((char *)fname, len, &fnum, access, exclus,,,options,,,);
err = (SETMODE(fnum, SET_FILE_SECURITY, nsk_sec_int) != CCE);
err = FILE_CLOSE_(fnum);
return (err != 0 ? -1 : 0);
}
/* TANDEM version of chown() function */
int chown(file, uid, gid)
const char *file;
uid_t uid;
gid_t gid;
{
FILE *stream;
struct nsk_own_type {
unsigned group : 8;
unsigned user : 8;
};
union nsk_own_ov {
struct nsk_own_type bit_ov;
short int_ov;
};
union nsk_own_ov nsk_own;
short fnum, err, nsk_own_int;
short len, access, exclus, extension, options;
char fname[FILENAME_MAX + 1];
char ext[EXTENSION_MAX + 1];
nsk_own.bit_ov.group = gid;
nsk_own.bit_ov.user = uid;
nsk_own_int = nsk_own.int_ov;
access = NSK_RDONLY;
exclus = NSK_SHARED;
options = NSK_NOUPDATEOPENTIME;
extension = parsename (file,fname,ext);
len = strlen(fname);
err = FILE_OPEN_((char *)fname, len, &fnum, access, exclus,,,options,,,);
err = (SETMODE(fnum, SET_FILE_OWNER, nsk_own_int) != CCE);
err = FILE_CLOSE_(fnum);
return (err != 0 ? -1 : 0);
}
/* TANDEM version of getch() - non-echo character reading */
int zgetch(void)
{
char ch;
short f, err, count, fnum, rlen;
rlen = 1;
f = (short)fileno(stdin);
fnum = fdtogfn (f);
#define ECHO_MODE 20
err = (SETMODE(fnum, ECHO_MODE, 0) != CCE);
err = (READX(fnum, &ch, rlen, (short *) &count) != CCE);
err = (SETMODE(fnum, ECHO_MODE, 1) != CCE);
if (err)
if (err != 1)
return EOF;
else
ch = 'q';
else
if (count == 0)
ch = '\r';
return (int)ch;
}
short parsename(srce, fname, ext)
const char *srce;
char *fname;
char *ext;
{
/* As a way of supporting DOS extensions from Tandem we look for a space
separated extension string after the Guardian filename
e.g. ZIP ZIPFILE "$DATA4.TESTING.INVOICE TXT"
*/
char *fstart;
char *fptr;
short extension = 0;
*fname = *ext = '\0'; /* set to null string */
fstart = (char *) srce;
if ((fptr = strrchr(fstart, TANDEM_EXTENSION)) != NULL) {
extension = 1;
fptr++;
strncat(ext, fptr, _min(EXTENSION_MAX, strlen(fptr)));
fptr = strchr(fstart, TANDEM_EXTENSION); /* End of filename */
strncat(fname, fstart, _min(FILENAME_MAX, (fptr - fstart)));
}
else {
/* just copy string */
strncat(fname, srce, _min(FILENAME_MAX, strlen(srce)));
}
return extension;
}
static time_t gmt_to_time_t (gmt)
long long *gmt;
{
#define GMT_TO_LCT 0
#define GMT_TO_LST 1
struct tm temp_tm;
short date_time[8];
long julian_dayno;
long long lct, lst, itime;
short err[1], type;
type = GMT_TO_LCT;
lct = CONVERTTIMESTAMP(*gmt, type,, err);
if (!err[0]) {
type = GMT_TO_LST;
lst = CONVERTTIMESTAMP(*gmt, type,, err);
}
itime = (err[0] ? *gmt : lct);
/* If we have no DST in force then make sure we give it a value,
else mktime screws up if we set the isdst flag to -1 */
temp_tm.tm_isdst = (err[0] ? 0 : ((lct == lst) ? 0 : 1));
julian_dayno = INTERPRETTIMESTAMP(itime, date_time);
temp_tm.tm_sec = date_time[5];
temp_tm.tm_min = date_time[4];
temp_tm.tm_hour = date_time[3];
temp_tm.tm_mday = date_time[2];
temp_tm.tm_mon = date_time[1] - 1; /* C's so sad */
temp_tm.tm_year = date_time[0] - 1900; /* it's almost funny */
return (mktime(&temp_tm));
}
/* TANDEM version of stat() function */
int stat(n, s)
const char *n;
struct stat *s;
{
#define ilist_items 26
#define klist_items 4
#define slist_items 3
#define ulist_items 1
#define flist_size 100
short err, i, extension;
char fname[FILENAME_MAX + 1];
short fnamelen;
char ext[EXTENSION_MAX + 1];
/* #0 #1 #2 #3 #4 #5 #6 #7 #8 #9 */
short ilist[ilist_items]={56,144, 54,142, 58, 62, 60, 41, 42, 44,
50, 51, 52, 61, 63, 66, 67, 70, 72, 73,
74, 75, 76, 77, 78, 79 };
short ilen[ilist_items] ={ 4, 4, 4, 2, 1, 2, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1 };
short ioff[ilist_items];
/* #0 #1 #2 #3 #4 #5 #6 #7 #8 #9 */
short klist[klist_items]={45, 46, 68, 69 };
short klen[klist_items] ={ 1, 1, 1, 1 };
short koff[klist_items];
/* #0 #1 #2 #3 #4 #5 #6 #7 #8 #9 */
short slist[slist_items]={43, 80, 90 };
short slen[slist_items] ={ 1, 1, 1 };
short soff[slist_items];
/* #0 #1 #2 #3 #4 #5 #6 #7 #8 #9 */
short ulist[ulist_items]={65 };
short ulen[ulist_items] ={ 1 };
short uoff[ulist_items];
short flist[flist_size];
short extra[2];
short *rlen=&extra[0];
short *err_item=&extra[1];
unsigned short *fowner;
unsigned short *fprogid;
char *fsec;
nsk_stat_ov *nsk_ov;
nsk_file_attrs *nsk_attr;
short end, count, kind, level, options, searchid;
short info[5];
/* Initialise stat structure */
s->st_dev = _S_GUARDIANOBJECT;
s->st_ino = 0;
s->st_nlink = 0;
s->st_rdev = 0;
s->st_uid = s->st_gid = 0;
s->st_size = 0;
s->st_atime = s->st_ctime = s->st_mtime = 0;
s->st_reserved[0] = 0;
s->st_reserved[1] = 0;
s->st_reserved[2] = 0;
nsk_ov = (nsk_stat_ov *)&s->st_reserved[0];
nsk_attr = (nsk_file_attrs *)&nsk_ov->ov.nsk_ef_region;
/* Check to see if name contains a (pseudo) file extension */
extension = parsename (n,fname,ext);
fnamelen = strlen(fname);
options = 3; /* Allow Subvols and Templates */
err = FILENAME_SCAN_( fname,
fnamelen,
&count,
&kind,
&level,
options
);
/* allow kind == 2 (DEFINE names) */
if (err != 0) return -1;
if (kind == 1 || (kind == 0 && level < 2)) {
/* Pattern, Subvol Name or One part Filename - lets see if it exists */
err = FILENAME_FINDSTART_ ( &searchid,
fname,
fnamelen,
,
DISK_DEVICE
);
if (err != 0) {
end = FILENAME_FINDFINISH_ ( searchid );
return -1;
}
err = FILENAME_FINDNEXT_ ( searchid,
fname,
FILENAME_MAX,
&fnamelen,
info
);
end = FILENAME_FINDFINISH_ ( searchid );
if (err != 0)
return -1; /* Non existing template, subvol or file */
if (kind == 1 || info[2] == -1) {
s->st_mode = S_IFDIR; /* Its an existing template or directory */
return 0;
}
/* Must be a real file so drop to code below to get info on it */
}
err = FILE_GETINFOLISTBYNAME_( fname,
fnamelen,
ilist,
ilist_items,
flist,
flist_size,
rlen,
err_item
);
if (err != 0) return -1;
ioff[0] = 0;
/* Build up table of offets into result list */
for (i=1; i < ilist_items; i++)
ioff[i] = ioff[i-1] + ilen[i-1];
/* Set up main stat fields */
/* Setup timestamps */
s->st_atime = gmt_to_time_t ((long long *)&flist[ioff[0]]);
s->st_mtime = s->st_ctime = gmt_to_time_t ((long long *)&flist[ioff[1]]);
nsk_ov->ov.creation_time = gmt_to_time_t ((long long *)&flist[ioff[2]]);
s->st_size = *(off_t *)&flist[ioff[3]];
fowner = (unsigned short *)&flist[ioff[4]];
s->st_uid = *fowner & 0x00ff;
s->st_gid = *fowner >> 8;
/* Note that Purge security (fsec[3]) in NSK has no relevance to stat() */
fsec = (char *)&flist[ioff[5]];
fprogid = (unsigned short *)&flist[ioff[6]];
s->st_mode = S_IFREG | /* Regular File */
/* Parse Read Flag */
((fsec[0] & 0x03) == 0x00 ? S_IROTH : 0) |
((fsec[0] & 0x02) == 0x00 ? S_IRGRP : 0) |
((fsec[0] & 0x03) != 0x03 ? S_IRUSR : 0) |
/* Parse Write Flag */
((fsec[1] & 0x03) == 0x00 ? S_IWOTH : 0) |
((fsec[1] & 0x02) == 0x00 ? S_IWGRP : 0) |
((fsec[1] & 0x03) != 0x03 ? S_IWUSR : 0) |
/* Parse Execute Flag */
((fsec[2] & 0x03) == 0x00 ? S_IXOTH : 0) |
((fsec[2] & 0x02) == 0x00 ? S_IXGRP : 0) |
((fsec[2] & 0x03) != 0x03 ? S_IXUSR : 0) |
/* Parse Progid */
(*fprogid == 1 ? (S_ISUID | S_ISGID) : 0) ;
/* Set up NSK additional stat fields */
nsk_attr->progid = (unsigned) flist[ioff[6]];
nsk_attr->filetype = (unsigned) flist[ioff[7]];
nsk_attr->filecode = (unsigned) flist[ioff[8]];
nsk_attr->block = (unsigned short) flist[ioff[9]];
nsk_attr->priext = (unsigned short) flist[ioff[10]];
nsk_attr->secext = (unsigned short) flist[ioff[11]];
nsk_attr->maxext = (unsigned short) flist[ioff[12]];
nsk_attr->flags.clearonpurge = (unsigned) flist[ioff[13]];
nsk_attr->licensed = (unsigned) flist[ioff[14]];
nsk_attr->flags.audited = (unsigned) flist[ioff[15]];
nsk_attr->flags.acompress = (unsigned) flist[ioff[16]];
nsk_attr->flags.refresheof = (unsigned) flist[ioff[17]];
nsk_attr->flags.buffered = (unsigned) (flist[ioff[18]] == 0 ? 1 : 0);
nsk_attr->flags.verified = (unsigned) flist[ioff[19]];
nsk_attr->flags.serial = (unsigned) flist[ioff[20]];
nsk_attr->flags.crashopen = (unsigned) flist[ioff[22]];
nsk_attr->flags.rollforward = (unsigned) flist[ioff[23]];
nsk_attr->flags.broken = (unsigned) flist[ioff[24]];
nsk_attr->flags.corrupt = (unsigned) flist[ioff[25]];
nsk_attr->fileopen = (unsigned) flist[ioff[21]];
if (nsk_attr->filetype == NSK_UNSTRUCTURED) {
/* extra info for Unstructured files */
err = FILE_GETINFOLISTBYNAME_( fname,
fnamelen,
ulist,
ulist_items,
flist,
flist_size,
rlen,
err_item
);
if (err != 0) return -1;
uoff[0] = 0;
/* Build up table of offets into result list */
for (i=1; i < ulist_items; i++)
uoff[i] = uoff[i-1] + ulen[i-1];
}
else {
/* extra info for Structured files */
err = FILE_GETINFOLISTBYNAME_( fname,
fnamelen,
slist,
slist_items,
flist,
flist_size,
rlen,
err_item
);
if (err != 0) return -1;
soff[0] = 0;
/* Build up table of offets into result list */
for (i=1; i < slist_items; i++)
soff[i] = soff[i-1] + slen[i-1];
nsk_attr->reclen = (unsigned) flist[soff[0]];
nsk_attr->flags.secpart = (unsigned) flist[soff[1]];
nsk_attr->flags.primpart = (unsigned)
( (flist[soff[2]] > 0 && nsk_attr->flags.secpart == 0) ? 1 : 0 );
if (nsk_attr->filetype == NSK_KEYSEQUENCED) {
/* extra info for Key Sequenced files */
err = FILE_GETINFOLISTBYNAME_( fname,
fnamelen,
klist,
klist_items,
flist,
flist_size,
rlen,
err_item
);
if (err != 0) return -1;
koff[0] = 0;
/* Build up table of offets into result list */
for (i=1; i < klist_items; i++)
koff[i] = koff[i-1] + klen[i-1];
nsk_attr->keyoff = (unsigned) flist[koff[0]];
nsk_attr->keylen = (unsigned) flist[koff[1]];
nsk_attr->flags.dcompress = (unsigned) flist[koff[2]];
nsk_attr->flags.icompress = (unsigned) flist[koff[3]];
}
}
return 0;
}
#ifndef SFX
/* TANDEM Directory processing */
DIR *opendir(const char *dirname)
{
short i, resolve;
char sname[FILENAME_MAX + 1];
short snamelen;
char fname[FILENAME_MAX + 1];
short fnamelen;
char *p;
short searchid, err, end;
struct dirent *entry;
DIR *dirp;
char ext[EXTENSION_MAX + 1];
short extension;
extension = parsename(dirname, sname, ext);
snamelen = strlen(sname);
/* First we work out how detailed the template is...
* e.g. If the template is DAVES*.* we want the search result
* in the same format
*/
p = sname;
i = 0;
while ((p = strchr(p, TANDEM_DELIMITER)) != NULL){
i++;
p++;
};
resolve = 2 - i;
/* Attempt to start a filename template */
err = FILENAME_FINDSTART_ ( &searchid,
sname,
snamelen,
resolve,
DISK_DEVICE
);
if (err != 0) {
end = FILENAME_FINDFINISH_(searchid);
return NULL;
}
/* Create DIR structure */
if ((dirp = malloc(sizeof(DIR))) == NULL ) {
end = FILENAME_FINDFINISH_(searchid);
return NULL;
}
dirp->D_list = dirp->D_curpos = NULL;
strcpy(dirp->D_path, dirname);
while ((err = FILENAME_FINDNEXT_(searchid,
fname,
FILENAME_MAX,
&fnamelen
)
) == 0 ){
/* Create space for entry */
if ((entry = malloc (sizeof(struct dirent))) == NULL) {
end = FILENAME_FINDFINISH_(searchid);
return NULL;
}
/* Link to last entry */
if (dirp->D_curpos == NULL)
dirp->D_list = dirp->D_curpos = entry; /* First name */
else {
dirp->D_curpos->d_next = entry; /* Link */
dirp->D_curpos = entry;
};
/* Add directory entry */
*dirp->D_curpos->d_name = '\0';
strncat(dirp->D_curpos->d_name,fname,fnamelen);
if (extension) {
strcat(dirp->D_curpos->d_name,TANDEM_EXTENSION_STR);
strcat(dirp->D_curpos->d_name,ext);
};
dirp->D_curpos->d_next = NULL;
};
end = FILENAME_FINDFINISH_(searchid);
if (err == 1) { /* Should return EOF at end of search */
dirp->D_curpos = dirp->D_list; /* Set current pos to start */
return dirp;
}
else
return NULL;
}
struct dirent *readdir(DIR *dirp)
{
struct dirent *cur;
cur = dirp->D_curpos;
dirp->D_curpos = dirp->D_curpos->d_next;
return cur;
}
void rewinddir(DIR *dirp)
{
dirp->D_curpos = dirp->D_list;
}
int closedir(DIR *dirp)
{
struct dirent *node;
while (dirp->D_list != NULL) {
node = dirp->D_list;
dirp->D_list = dirp->D_list->d_next;
free( node );
}
free( dirp );
return 0;
}
#endif /* !SFX */