diff options
Diffstat (limited to 'tandem/tandem.c')
-rw-r--r-- | tandem/tandem.c | 889 |
1 files changed, 889 insertions, 0 deletions
diff --git a/tandem/tandem.c b/tandem/tandem.c new file mode 100644 index 0000000..0aa1e06 --- /dev/null +++ b/tandem/tandem.c @@ -0,0 +1,889 @@ +/* + 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 */ |