1/*
2  Copyright (c) 1990-2002 Info-ZIP.  All rights reserved.
3
4  See the accompanying file LICENSE, version 2000-Apr-09 or later
5  (the contents of which are also included in zip.h) for terms of use.
6  If, for some reason, all these files are missing, the Info-ZIP license
7  also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
8*/
9/*
10 * routines common to TANDEM (ZIP and UNZIP)
11 */
12
13#include "zip.h"   /* This sets up ZIP / UNZIP define */
14
15#include <tal.h>
16#include "$system.zsysdefs.zsysc" nolist
17#include <cextdecs> nolist
18#include "tannsk.h"
19
20static time_t gmt_to_time_t (long long *);
21
22int isatty (fnum)
23int fnum;
24{
25  return 1;
26}
27
28/********************/
29/* Function in2ex() */
30/********************/
31
32#ifdef UNZIP
33char *in2ex(__G__ n)
34  __GDEF
35#else
36char *in2ex(n)
37#endif
38  char *n;              /* internal file name */
39/* Convert the zip file name to an external file name, returning the malloc'ed
40   string or NULL if not enough memory. */
41{
42  char *x;              /* external file name buffer */
43  char *y;              /* pointer to external buffer */
44  char *max;            /* pointer to max end of next file part */
45  char *t;              /* pointer to internal - start of substring */
46  char *p;              /* pointer to internal - TANDEM delimiter */
47  char *e;              /* pointer to internal - DOS extension delimiter */
48  char *z;              /* pointer to internal - end of substring */
49  int len;              /* length of substring to copy to external name */
50  int allow_dollar;     /* $ symbol allowed as next character */
51
52  if ((x = malloc(strlen(n) + 4)) == NULL)  /* + 4 for safety */
53    return NULL;
54
55  *x = '\0';
56
57  /* Junk pathname as requested */
58#ifdef UNZIP
59  if (uO.jflag && (t = strrchr(n, INTERNAL_DELIMITER)) != NULL)
60    ++t;
61  else
62    t = n;
63#endif /* UNZIP */
64#ifdef ZIP
65  if (!pathput)
66    t = last(n, INTERNAL_DELIMITER);
67  else
68    t = n;
69#endif /* ZIP */
70
71  allow_dollar = TRUE;
72
73  while (*t != '\0') {  /* File part could be sys, vol, subvol or file */
74    if (*t == INTERNAL_DELIMITER) {    /* System, Volume or Subvol Name */
75      t++;
76      if (*t == INTERNAL_DELIMITER) {  /* System */
77        strcat(x, TANDEM_NODE_STR);
78        t++;
79      }
80      else {
81        strcat(x, TANDEM_DELIMITER_STR);
82        allow_dollar = FALSE;
83      }
84    }
85    /* Work out where end of current external string is */
86    y = x + strlen(x);
87
88    /* Work out substring to copy and externalise */
89    p = strchr(t, INTERNAL_DELIMITER);
90    e = strchr(t, DOS_EXTENSION);
91    if (p != NULL) {
92      if (e > p)
93        e = NULL;
94    }
95
96    z = e;
97    if (z == NULL)
98      z = p;
99    if (z == NULL)
100      z = t + strlen(t);
101
102    /* can't have Tandem name longer than 8 characters */
103    max = y + MAXFILEPARTLEN;
104
105    /* Allow $ symbol as first character in some cases */
106    if (*t == '$') {
107      if (allow_dollar)
108        *y++ = *t++;
109      else;
110        *t++;
111    }
112
113    /* Make sure first real character is alpha */
114    if (! isalpha(*t) )
115      *y++ = 'A';
116
117    /* Characters left to process */
118    len = z - t;
119
120    while ( len > 0 ) {
121      if ( isalnum(*t) ) {
122        *y++ = toupper(*t++);
123        if (y >= max)
124          break;
125      }
126      else
127        t++;
128      len--;
129    }
130    *y = '\0';
131    t = p;
132
133    if (p == NULL) {
134      /* Last part of filename, store pseudo extension if available */
135      if (e != NULL) {
136        strcat(x, TANDEM_EXTENSION_STR);
137        y = x + strlen(x);
138
139        /* no restriction on extension length as its virtual */
140        z = e + 1;
141        while ( *z != '\0' ) {
142          *y++ = toupper(*z++);
143        }
144        *y = '\0';
145      }
146      break;
147    }
148  }
149
150  return x;
151}
152
153void zexit(status)
154  int status;
155{
156  /* Exit(>0) creates saveabend files */
157  terminate_program (0,0,(short)status,,,);
158}
159
160/************************/
161/*  Function zputc()    */
162/************************/
163
164#ifdef putc
165#  undef putc
166#endif
167
168int zputc(ch, fptr)
169  int ch;
170  FILE *fptr;
171{
172  int err;
173  err = putc(ch,fptr);
174  fflush(fptr);
175  return err;
176}
177#define putc zputc
178
179#ifdef LICENSED
180_tal _priv short FILE_CHANGELABEL_ (
181 short,          /* IN */
182 short,          /* IN */
183 const short _far *    /* IN */
184 );
185
186_c _callable int changelabel OF((short, const short *, const short *));
187
188_c _callable int changelabel(fnum, modtime, actime)
189  short fnum;
190  const short *modtime;
191  const short *actime;
192{
193  int err;
194
195  err = FILE_CHANGELABEL_(fnum, 16, modtime);
196  if (!err)
197    err = FILE_CHANGELABEL_(fnum, 17, actime);
198  return err;
199}
200
201int islicensed(void)
202{
203  #define plist_items 1
204  #define plist_size 10
205
206  short myphandle[ZSYS_VAL_PHANDLE_WLEN];
207  short licensetag[plist_items] = {37};
208  short licensed[plist_size];
209  short maxlen = plist_size;
210  short items = plist_items;
211  short resultlen[1], err;
212
213  err = PROCESSHANDLE_NULLIT_(myphandle);
214
215  if (!err)
216    err = PROCESS_GETINFO_(myphandle);
217
218  if (!err)
219    err = PROCESS_GETINFOLIST_(/*cpu*/,
220                               /*pin*/,
221                               /*nodename*/,
222                               /*nodenamelen*/,
223                               myphandle,
224                               licensetag,
225                               items,
226                               licensed,
227                               maxlen,
228                               resultlen
229                              );
230
231  if (err != 0)
232    return 0;
233  else
234    return licensed[0];
235}
236#endif /* LICENSED */
237
238int utime(file, time)
239  const char *file;
240  const ztimbuf *time;
241{
242#ifdef LICENSED
243  int result, err;
244  union timestamp_ov {
245    long long fulltime;
246    short wordtime[4];
247  };
248  union timestamp_ov lasttime, opentime;
249  struct tm *modt, *opent;
250  short datetime[8], errormask[1];
251  short len, fnum, access, exclus, options;
252  char fname[FILENAME_MAX + 1];
253  short extension;
254  char ext[EXTENSION_MAX + 1];
255
256  if (islicensed() ) {
257    /* Attempt to update file label */
258    modt = gmtime( &time->modtime );
259
260    datetime[0] = modt->tm_year + 1900;
261    datetime[1] = modt->tm_mon + 1;
262    datetime[2] = modt->tm_mday;
263    datetime[3] = modt->tm_hour;
264    datetime[4] = modt->tm_min;
265    datetime[5] = modt->tm_sec;
266    datetime[6] = datetime[7] = 0;
267    errormask[0] = 0;
268    lasttime.fulltime = COMPUTETIMESTAMP (datetime, errormask);
269
270    opent = gmtime( &time->actime );
271
272    datetime[0] = opent->tm_year + 1900;
273    datetime[1] = opent->tm_mon + 1;
274    datetime[2] = opent->tm_mday;
275    datetime[3] = opent->tm_hour;
276    datetime[4] = opent->tm_min;
277    datetime[5] = opent->tm_sec;
278    datetime[6] = datetime[7] = 0;
279    errormask[0] = 0;
280    opentime.fulltime = COMPUTETIMESTAMP (datetime, errormask);
281
282    /* Remove any (pseudo) file extension */
283    extension = parsename (file,fname,ext);
284    len = strlen(fname);
285
286    access = NSK_WRONLY;
287    exclus = NSK_SHARED;
288    options = NSK_NOUPDATEOPENTIME;
289
290    extension = parsename (file,fname,ext);
291    len = strlen(fname);
292
293    err = FILE_OPEN_((char *)fname, len, &fnum, access, exclus,,,options,,,);
294    result = changelabel(fnum,lasttime.wordtime,opentime.wordtime);
295    err = FILE_CLOSE_(fnum);
296    return result;
297  }
298  return -1;
299#else  /* !LICENSED */
300  return 0;             /* "no error", to suppress annoying failure messages */
301#endif  /* ?LICENSED */
302}
303
304/* TANDEM version of chmod() function */
305
306int chmod(file, unix_sec)
307  const char *file;
308  mode_t unix_sec;
309{
310  FILE *stream;
311  struct nsk_sec_type {
312    unsigned progid : 1;
313    unsigned clear  : 1;
314    unsigned null   : 2;
315    unsigned read   : 3;
316    unsigned write  : 3;
317    unsigned execute: 3;
318    unsigned purge  : 3;
319  };
320  union nsk_sec_ov {
321    struct nsk_sec_type bit_ov;
322    short int_ov;
323  };
324  union nsk_sec_ov nsk_sec;
325  short fnum, err, nsk_sec_int;
326  short len, access, exclus, extension, options;
327  char fname[FILENAME_MAX + 1];
328  char ext[EXTENSION_MAX + 1];
329
330  nsk_sec.bit_ov.progid = 0;
331  nsk_sec.bit_ov.clear  = 0;
332  nsk_sec.bit_ov.null   = 0;
333
334  /*  4="N", 5="C", 6="U", 7="-"   */
335
336  if (unix_sec & S_IROTH) nsk_sec.bit_ov.read = 4;
337  else if (unix_sec & S_IRGRP) nsk_sec.bit_ov.read = 5;
338  else if (unix_sec & S_IRUSR) nsk_sec.bit_ov.read = 6;
339  else nsk_sec.bit_ov.read = 7;
340
341  if (unix_sec & S_IWOTH) nsk_sec.bit_ov.write = 4;
342  else if (unix_sec & S_IWGRP) nsk_sec.bit_ov.write = 5;
343  else if (unix_sec & S_IWUSR) nsk_sec.bit_ov.write = 6;
344  else nsk_sec.bit_ov.write = 7;
345
346  if (unix_sec & S_IXOTH) nsk_sec.bit_ov.execute = 4;
347  else if (unix_sec & S_IXGRP) nsk_sec.bit_ov.execute = 5;
348  else if (unix_sec & S_IXUSR) nsk_sec.bit_ov.execute = 6;
349  else nsk_sec.bit_ov.execute = 7;
350
351  nsk_sec.bit_ov.purge = nsk_sec.bit_ov.write;
352
353  nsk_sec_int = nsk_sec.int_ov;
354
355  access = NSK_RDONLY;
356  exclus = NSK_SHARED;
357  options = NSK_NOUPDATEOPENTIME;
358
359  extension = parsename (file,fname,ext);
360  len = strlen(fname);
361
362  err = FILE_OPEN_((char *)fname, len, &fnum, access, exclus,,,options,,,);
363  err = (SETMODE(fnum, SET_FILE_SECURITY, nsk_sec_int) != CCE);
364  err = FILE_CLOSE_(fnum);
365
366  return (err != 0 ? -1 : 0);
367}
368
369/* TANDEM version of chown() function */
370
371int chown(file, uid, gid)
372  const char *file;
373  uid_t uid;
374  gid_t gid;
375{
376  FILE *stream;
377  struct nsk_own_type {
378    unsigned group  : 8;
379    unsigned user   : 8;
380  };
381  union nsk_own_ov {
382    struct nsk_own_type bit_ov;
383    short int_ov;
384  };
385  union nsk_own_ov nsk_own;
386  short fnum, err, nsk_own_int;
387  short len, access, exclus, extension, options;
388  char fname[FILENAME_MAX + 1];
389  char ext[EXTENSION_MAX + 1];
390
391  nsk_own.bit_ov.group = gid;
392  nsk_own.bit_ov.user  = uid;
393
394  nsk_own_int = nsk_own.int_ov;
395
396  access = NSK_RDONLY;
397  exclus = NSK_SHARED;
398  options = NSK_NOUPDATEOPENTIME;
399
400  extension = parsename (file,fname,ext);
401  len = strlen(fname);
402
403  err = FILE_OPEN_((char *)fname, len, &fnum, access, exclus,,,options,,,);
404  err = (SETMODE(fnum, SET_FILE_OWNER, nsk_own_int) != CCE);
405  err = FILE_CLOSE_(fnum);
406  return (err != 0 ? -1 : 0);
407}
408
409/* TANDEM version of getch() - non-echo character reading */
410int zgetch(void)
411{
412  char ch;
413  short f, err, count, fnum, rlen;
414
415  rlen = 1;
416  f = (short)fileno(stdin);
417  fnum = fdtogfn (f);
418  #define ECHO_MODE 20
419  err = (SETMODE(fnum, ECHO_MODE, 0) != CCE);
420  err = (READX(fnum, &ch, rlen, (short *) &count) != CCE);
421  err = (SETMODE(fnum, ECHO_MODE, 1) != CCE);
422
423  if (err)
424    if (err != 1)
425      return EOF;
426    else
427      ch = 'q';
428  else
429    if (count == 0)
430      ch = '\r';
431
432  return (int)ch;
433}
434
435short parsename(srce, fname, ext)
436  const char *srce;
437  char *fname;
438  char *ext;
439{
440  /* As a way of supporting DOS extensions from Tandem we look for a space
441     separated extension string after the Guardian filename
442     e.g. ZIP ZIPFILE "$DATA4.TESTING.INVOICE TXT"
443  */
444
445  char *fstart;
446  char *fptr;
447  short extension = 0;
448
449  *fname = *ext = '\0';  /* set to null string */
450
451  fstart = (char *) srce;
452
453  if ((fptr = strrchr(fstart, TANDEM_EXTENSION)) != NULL) {
454    extension = 1;
455
456    fptr++;
457    strncat(ext, fptr, _min(EXTENSION_MAX, strlen(fptr)));
458
459    fptr = strchr(fstart, TANDEM_EXTENSION);  /* End of filename */
460    strncat(fname, fstart, _min(FILENAME_MAX, (fptr - fstart)));
461  }
462  else {
463    /* just copy string */
464    strncat(fname, srce, _min(FILENAME_MAX, strlen(srce)));
465  }
466
467  return extension;
468}
469
470static time_t gmt_to_time_t (gmt)
471  long long *gmt;
472{
473  #define GMT_TO_LCT 0
474  #define GMT_TO_LST 1
475
476  struct tm temp_tm;
477  short  date_time[8];
478  long   julian_dayno;
479  long long lct, lst, itime;
480  short  err[1], type;
481
482  type = GMT_TO_LCT;
483  lct = CONVERTTIMESTAMP(*gmt, type,, err);
484
485  if (!err[0]) {
486    type = GMT_TO_LST;
487    lst = CONVERTTIMESTAMP(*gmt, type,, err);
488  }
489
490  itime = (err[0] ? *gmt : lct);
491  /* If we have no DST in force then make sure we give it a value,
492     else mktime screws up if we set the isdst flag to -1 */
493  temp_tm.tm_isdst = (err[0] ? 0 : ((lct == lst) ? 0 : 1));
494
495  julian_dayno = INTERPRETTIMESTAMP(itime, date_time);
496
497  temp_tm.tm_sec   = date_time[5];
498  temp_tm.tm_min   = date_time[4];
499  temp_tm.tm_hour  = date_time[3];
500  temp_tm.tm_mday  = date_time[2];
501  temp_tm.tm_mon   = date_time[1] - 1;     /* C's so sad */
502  temp_tm.tm_year  = date_time[0] - 1900;  /* it's almost funny */
503
504  return (mktime(&temp_tm));
505}
506
507/* TANDEM version of stat() function */
508int stat(n, s)
509  const char *n;
510  struct stat *s;
511{
512  #define ilist_items 26
513  #define klist_items 4
514  #define slist_items 3
515  #define ulist_items 1
516  #define flist_size 100
517
518  short err, i, extension;
519  char fname[FILENAME_MAX + 1];
520  short fnamelen;
521  char ext[EXTENSION_MAX + 1];
522
523                         /* #0  #1  #2  #3  #4  #5  #6  #7  #8  #9 */
524  short ilist[ilist_items]={56,144, 54,142, 58, 62, 60, 41, 42, 44,
525                            50, 51, 52, 61, 63, 66, 67, 70, 72, 73,
526                            74, 75, 76, 77, 78, 79                 };
527  short ilen[ilist_items] ={ 4,  4,  4,  2,  1,  2,  1,  1,  1,  1,
528                             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
529                             1,  1,  1,  1,  1,  1                 };
530  short ioff[ilist_items];
531
532                         /* #0  #1  #2  #3  #4  #5  #6  #7  #8  #9 */
533  short klist[klist_items]={45, 46, 68, 69                         };
534  short klen[klist_items] ={ 1,  1,  1,  1                         };
535  short koff[klist_items];
536
537                         /* #0  #1  #2  #3  #4  #5  #6  #7  #8  #9 */
538  short slist[slist_items]={43, 80, 90                             };
539  short slen[slist_items] ={ 1,  1,  1                             };
540  short soff[slist_items];
541
542                         /* #0  #1  #2  #3  #4  #5  #6  #7  #8  #9 */
543  short ulist[ulist_items]={65                                     };
544  short ulen[ulist_items] ={ 1                                     };
545  short uoff[ulist_items];
546
547  short flist[flist_size];
548  short extra[2];
549  short *rlen=&extra[0];
550  short *err_item=&extra[1];
551  unsigned short *fowner;
552  unsigned short *fprogid;
553  char *fsec;
554
555  nsk_stat_ov *nsk_ov;
556  nsk_file_attrs *nsk_attr;
557
558  short end, count, kind, level, options, searchid;
559  short info[5];
560
561  /* Initialise stat structure */
562  s->st_dev = _S_GUARDIANOBJECT;
563  s->st_ino = 0;
564  s->st_nlink = 0;
565  s->st_rdev = 0;
566  s->st_uid = s->st_gid = 0;
567  s->st_size = 0;
568  s->st_atime = s->st_ctime = s->st_mtime = 0;
569  s->st_reserved[0] = 0;
570  s->st_reserved[1] = 0;
571  s->st_reserved[2] = 0;
572  nsk_ov = (nsk_stat_ov *)&s->st_reserved[0];
573  nsk_attr = (nsk_file_attrs *)&nsk_ov->ov.nsk_ef_region;
574
575  /* Check to see if name contains a (pseudo) file extension */
576  extension = parsename (n,fname,ext);
577
578  fnamelen = strlen(fname);
579
580  options = 3; /* Allow Subvols and Templates */
581  err = FILENAME_SCAN_( fname,
582                        fnamelen,
583                        &count,
584                        &kind,
585                        &level,
586                        options
587                      );
588
589  /* allow kind == 2 (DEFINE names) */
590  if (err != 0) return -1;
591
592  if (kind == 1 || (kind == 0 && level < 2)) {
593    /* Pattern, Subvol Name or One part Filename - lets see if it exists */
594    err = FILENAME_FINDSTART_ ( &searchid,
595                                fname,
596                                fnamelen,
597                                ,
598                                DISK_DEVICE
599                              );
600
601    if (err != 0) {
602      end = FILENAME_FINDFINISH_ ( searchid );
603      return -1;
604    }
605
606    err = FILENAME_FINDNEXT_ ( searchid,
607                               fname,
608                               FILENAME_MAX,
609                               &fnamelen,
610                               info
611                              );
612    end = FILENAME_FINDFINISH_ ( searchid );
613
614    if (err != 0)
615      return -1;  /* Non existing template, subvol or file */
616
617    if (kind == 1 || info[2] == -1) {
618      s->st_mode = S_IFDIR;    /* Its an existing template or directory */
619      return 0;
620    }
621
622    /* Must be a real file so drop to code below to get info on it */
623  }
624
625  err = FILE_GETINFOLISTBYNAME_( fname,
626                                 fnamelen,
627                                 ilist,
628                                 ilist_items,
629                                 flist,
630                                 flist_size,
631                                 rlen,
632                                 err_item
633                               );
634  if (err != 0) return -1;
635
636  ioff[0] = 0;
637
638  /*  Build up table of offets into result list */
639  for (i=1; i < ilist_items; i++)
640    ioff[i] = ioff[i-1] + ilen[i-1];
641
642  /* Set up main stat fields */
643
644  /* Setup timestamps */
645  s->st_atime = gmt_to_time_t ((long long *)&flist[ioff[0]]);
646  s->st_mtime = s->st_ctime = gmt_to_time_t ((long long *)&flist[ioff[1]]);
647  nsk_ov->ov.creation_time = gmt_to_time_t ((long long *)&flist[ioff[2]]);
648
649  s->st_size = *(off_t *)&flist[ioff[3]];
650
651  fowner = (unsigned short *)&flist[ioff[4]];
652  s->st_uid = *fowner & 0x00ff;
653  s->st_gid = *fowner >> 8;
654
655  /* Note that Purge security (fsec[3]) in NSK has no relevance to stat() */
656  fsec = (char *)&flist[ioff[5]];
657  fprogid = (unsigned short *)&flist[ioff[6]];
658
659  s->st_mode = S_IFREG |  /* Regular File */
660  /*  Parse Read Flag */
661               ((fsec[0] & 0x03) == 0x00 ? S_IROTH : 0) |
662               ((fsec[0] & 0x02) == 0x00 ? S_IRGRP : 0) |
663               ((fsec[0] & 0x03) != 0x03 ? S_IRUSR : 0) |
664  /*  Parse Write Flag */
665               ((fsec[1] & 0x03) == 0x00 ? S_IWOTH : 0) |
666               ((fsec[1] & 0x02) == 0x00 ? S_IWGRP : 0) |
667               ((fsec[1] & 0x03) != 0x03 ? S_IWUSR : 0) |
668  /*  Parse Execute Flag */
669               ((fsec[2] & 0x03) == 0x00 ? S_IXOTH : 0) |
670               ((fsec[2] & 0x02) == 0x00 ? S_IXGRP : 0) |
671               ((fsec[2] & 0x03) != 0x03 ? S_IXUSR : 0) |
672  /*  Parse Progid */
673               (*fprogid == 1 ? (S_ISUID | S_ISGID) : 0) ;
674
675  /* Set up NSK additional stat fields */
676  nsk_attr->progid   = (unsigned) flist[ioff[6]];
677  nsk_attr->filetype = (unsigned) flist[ioff[7]];
678  nsk_attr->filecode = (unsigned) flist[ioff[8]];
679  nsk_attr->block    = (unsigned short) flist[ioff[9]];
680  nsk_attr->priext   = (unsigned short) flist[ioff[10]];
681  nsk_attr->secext   = (unsigned short) flist[ioff[11]];
682  nsk_attr->maxext   = (unsigned short) flist[ioff[12]];
683  nsk_attr->flags.clearonpurge = (unsigned) flist[ioff[13]];
684  nsk_attr->licensed     = (unsigned) flist[ioff[14]];
685  nsk_attr->flags.audited      = (unsigned) flist[ioff[15]];
686  nsk_attr->flags.acompress    = (unsigned) flist[ioff[16]];
687  nsk_attr->flags.refresheof   = (unsigned) flist[ioff[17]];
688  nsk_attr->flags.buffered     = (unsigned) (flist[ioff[18]] == 0 ? 1 : 0);
689  nsk_attr->flags.verified     = (unsigned) flist[ioff[19]];
690  nsk_attr->flags.serial       = (unsigned) flist[ioff[20]];
691  nsk_attr->flags.crashopen    = (unsigned) flist[ioff[22]];
692  nsk_attr->flags.rollforward  = (unsigned) flist[ioff[23]];
693  nsk_attr->flags.broken       = (unsigned) flist[ioff[24]];
694  nsk_attr->flags.corrupt      = (unsigned) flist[ioff[25]];
695  nsk_attr->fileopen     = (unsigned) flist[ioff[21]];
696
697
698  if (nsk_attr->filetype == NSK_UNSTRUCTURED) {
699    /* extra info for Unstructured files */
700    err = FILE_GETINFOLISTBYNAME_( fname,
701                                   fnamelen,
702                                   ulist,
703                                   ulist_items,
704                                   flist,
705                                   flist_size,
706                                   rlen,
707                                   err_item
708                                 );
709    if (err != 0) return -1;
710
711    uoff[0] = 0;
712
713    /*  Build up table of offets into result list */
714    for (i=1; i < ulist_items; i++)
715      uoff[i] = uoff[i-1] + ulen[i-1];
716  }
717  else {
718    /* extra info for Structured files */
719    err = FILE_GETINFOLISTBYNAME_( fname,
720                                   fnamelen,
721                                   slist,
722                                   slist_items,
723                                   flist,
724                                   flist_size,
725                                   rlen,
726                                   err_item
727                                 );
728    if (err != 0) return -1;
729
730    soff[0] = 0;
731
732    /*  Build up table of offets into result list */
733    for (i=1; i < slist_items; i++)
734      soff[i] = soff[i-1] + slen[i-1];
735
736    nsk_attr->reclen   = (unsigned) flist[soff[0]];
737    nsk_attr->flags.secpart   = (unsigned) flist[soff[1]];
738    nsk_attr->flags.primpart  = (unsigned)
739     ( (flist[soff[2]] > 0 && nsk_attr->flags.secpart == 0) ? 1 : 0 );
740
741    if (nsk_attr->filetype == NSK_KEYSEQUENCED) {
742      /* extra info for Key Sequenced files */
743      err = FILE_GETINFOLISTBYNAME_( fname,
744                                     fnamelen,
745                                     klist,
746                                     klist_items,
747                                     flist,
748                                     flist_size,
749                                     rlen,
750                                     err_item
751                                   );
752      if (err != 0) return -1;
753
754      koff[0] = 0;
755
756      /*  Build up table of offets into result list */
757      for (i=1; i < klist_items; i++)
758        koff[i] = koff[i-1] + klen[i-1];
759
760      nsk_attr->keyoff   = (unsigned) flist[koff[0]];
761      nsk_attr->keylen   = (unsigned) flist[koff[1]];
762      nsk_attr->flags.dcompress = (unsigned) flist[koff[2]];
763      nsk_attr->flags.icompress = (unsigned) flist[koff[3]];
764    }
765  }
766
767  return 0;
768}
769
770#ifndef SFX
771/* TANDEM Directory processing */
772
773DIR *opendir(const char *dirname)
774{
775   short i, resolve;
776   char sname[FILENAME_MAX + 1];
777   short snamelen;
778   char fname[FILENAME_MAX + 1];
779   short fnamelen;
780   char *p;
781   short searchid, err, end;
782   struct dirent *entry;
783   DIR *dirp;
784   char ext[EXTENSION_MAX + 1];
785   short extension;
786
787   extension = parsename(dirname, sname, ext);
788   snamelen = strlen(sname);
789
790   /*  First we work out how detailed the template is...
791    *  e.g. If the template is DAVES*.* we want the search result
792    *       in the same format
793    */
794
795   p = sname;
796   i = 0;
797   while ((p = strchr(p, TANDEM_DELIMITER)) != NULL){
798     i++;
799     p++;
800   };
801   resolve = 2 - i;
802
803   /*  Attempt to start a filename template */
804   err = FILENAME_FINDSTART_ ( &searchid,
805                               sname,
806                               snamelen,
807                               resolve,
808                               DISK_DEVICE
809                             );
810   if (err != 0) {
811     end = FILENAME_FINDFINISH_(searchid);
812     return NULL;
813   }
814
815   /* Create DIR structure */
816   if ((dirp = malloc(sizeof(DIR))) == NULL ) {
817     end = FILENAME_FINDFINISH_(searchid);
818     return NULL;
819   }
820   dirp->D_list = dirp->D_curpos = NULL;
821   strcpy(dirp->D_path, dirname);
822
823   while ((err = FILENAME_FINDNEXT_(searchid,
824                                    fname,
825                                    FILENAME_MAX,
826                                    &fnamelen
827                                   )
828           ) == 0 ){
829     /*  Create space for entry */
830     if ((entry = malloc (sizeof(struct dirent))) == NULL) {
831       end = FILENAME_FINDFINISH_(searchid);
832       return NULL;
833     }
834
835     /*  Link to last entry */
836     if (dirp->D_curpos == NULL)
837       dirp->D_list = dirp->D_curpos = entry;  /* First name */
838     else {
839       dirp->D_curpos->d_next = entry;         /* Link */
840       dirp->D_curpos = entry;
841     };
842     /* Add directory entry */
843     *dirp->D_curpos->d_name = '\0';
844     strncat(dirp->D_curpos->d_name,fname,fnamelen);
845     if (extension) {
846       strcat(dirp->D_curpos->d_name,TANDEM_EXTENSION_STR);
847       strcat(dirp->D_curpos->d_name,ext);
848     };
849     dirp->D_curpos->d_next = NULL;
850   };
851
852   end = FILENAME_FINDFINISH_(searchid);
853
854   if (err == 1) {  /*  Should return EOF at end of search */
855     dirp->D_curpos = dirp->D_list;        /* Set current pos to start */
856     return dirp;
857   }
858   else
859     return NULL;
860}
861
862struct dirent *readdir(DIR *dirp)
863{
864   struct dirent *cur;
865
866   cur = dirp->D_curpos;
867   dirp->D_curpos = dirp->D_curpos->d_next;
868   return cur;
869}
870
871void rewinddir(DIR *dirp)
872{
873   dirp->D_curpos = dirp->D_list;
874}
875
876int closedir(DIR *dirp)
877{
878   struct dirent *node;
879
880   while (dirp->D_list != NULL) {
881      node = dirp->D_list;
882      dirp->D_list = dirp->D_list->d_next;
883      free( node );
884   }
885   free( dirp );
886   return 0;
887}
888
889#endif /* !SFX */
890