URI: 
       tutil.c - mixmaster - mixmaster 3.0 patched for libressl
  HTML git clone git://parazyd.org/mixmaster.git
   DIR Log
   DIR Files
   DIR Refs
   DIR README
       ---
       tutil.c (15615B)
       ---
            1 /* Mixmaster version 3.0  --  (C) 1999 - 2006 Anonymizer Inc. and others.
            2 
            3    Mixmaster may be redistributed and modified under certain conditions.
            4    This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF
            5    ANY KIND, either express or implied. See the file COPYRIGHT for
            6    details.
            7 
            8    Utility functions
            9    $Id: util.c 934 2006-06-24 13:40:39Z rabbi $ */
           10 
           11 #include "mix3.h"
           12 #include <stdlib.h>
           13 #include <string.h>
           14 #include <ctype.h>
           15 #include <fcntl.h>
           16 #include <sys/types.h>
           17 #include <sys/stat.h>
           18 #ifdef POSIX
           19 #include <signal.h>
           20 #include <errno.h>
           21 #include <unistd.h>
           22 #include <sys/file.h>
           23 #include <termios.h>
           24 #else /* end of POSIX */
           25 #include <io.h>
           26 #endif /* else if not POSIX */
           27 #ifdef HAVE_GETKEY
           28 #include <pc.h>
           29 #endif /* HAVE_GETKEY */
           30 #include <assert.h>
           31 
           32 /** string comparison functions. return 1 on match, 0 otherwise ********/
           33 
           34 int strileft(const char *string, const char *keyword)
           35 {
           36   register unsigned int i;
           37 
           38   for (i = 0; keyword[i] != '\0'; i++)
           39     if (tolower(string[i]) != tolower(keyword[i]))
           40       return 0;
           41   return 1;
           42 }
           43 
           44 int striright(const char *string, const char *keyword)
           45 {
           46   int l;
           47   l = strlen(string) - strlen(keyword);
           48   return (l >= 0 ? strieq(string + l, keyword) : -1);
           49 }
           50 
           51 int strleft(const char *string, const char *keyword)
           52 {
           53   register unsigned int i;
           54 
           55   for (i = 0; keyword[i] != '\0'; i++)
           56     if (string[i] != keyword[i])
           57       return 0;
           58   return 1;
           59 }
           60 
           61 int strifind(const char *string, const char *keyword)
           62 {
           63   register unsigned int i, j;
           64   char k;
           65 
           66   k = tolower(keyword[0]);
           67   for (i = 0; string[i] != '\0'; i++) {
           68     if (tolower(string[i]) == k) {
           69       for (j = 1; keyword[j] != '\0'; j++)
           70         if (tolower(string[i + j]) != tolower(keyword[j]))
           71           goto next;
           72       return 1;
           73     }
           74   next:
           75     ;
           76   }
           77   return 0;
           78 }
           79 
           80 int strieq(const char *s1, const char *s2)
           81 {
           82   register unsigned int i = 0;
           83 
           84   do
           85     if (tolower(s1[i]) != tolower(s2[i]))
           86       return 0;
           87   while (s1[i++] != '\0') ;
           88   return 1;
           89 }
           90 
           91 int streq(const char *a, const char *b)
           92 {
           93   return (strcmp(a, b) == 0);
           94 }
           95 
           96 int strfind(const char *a, const char *keyword)
           97 {
           98   return (strstr(a, keyword) != NULL);
           99 }
          100 
          101 void strcatn(char *dest, const char *src, int n)
          102 {
          103   int l;
          104   l = strlen(dest);
          105   if (l < n)
          106     strncpy(dest + l, src, n - l - 1);
          107   dest[n-1] = '\0';
          108 }
          109 
          110 /** files **************************************************************/
          111 
          112 int mixfile(char *path, const char *name)
          113 {
          114   char *h;
          115   assert(path != NULL && name != NULL);
          116 
          117 #ifdef POSIX
          118   if (name[0] == '~' && name[1] == DIRSEP && (h = getenv("HOME")) != NULL) {
          119     strncpy(path, h, PATHMAX);
          120     path[PATHMAX-1] = '\0';
          121     strcatn(path, name + 1, PATHMAX);
          122   } else
          123 #endif /* POSIX */
          124   if (name[0] == DIRSEP || (isalpha(name[0]) && name[1] == ':') || MIXDIR == NULL) {
          125     strncpy(path, name, PATHMAX);
          126     path[PATHMAX-1] = '\0';
          127   } else {
          128     strncpy(path, MIXDIR, PATHMAX);
          129     path[PATHMAX-1] = '\0';
          130     strcatn(path, name, PATHMAX);
          131   }
          132   return (0);
          133 }
          134 
          135 FILE *mix_openfile(const char *name, const char *a)
          136 {
          137   char path[PATHMAX];
          138 
          139   mixfile(path, name);
          140   return (fopen(path, a));
          141 }
          142 
          143 FILE *openpipe(const char *prog)
          144 {
          145   FILE *p = NULL;
          146 
          147 #ifdef POSIX
          148   p = popen(prog, "w");
          149 #endif /* POSIX */
          150 #ifdef _MSC
          151   p = _popen(prog, "w");
          152 #endif /* _MSC */
          153 
          154   if (p == NULL)
          155     errlog(ERRORMSG, "Unable to open pipe to %s\n", prog);
          156   return p;
          157 }
          158 
          159 int
          160 file_to_out(const char *filename)
          161 {
          162     int len;
          163     FILE *fp;
          164     char chunk[1024];
          165 
          166     if ((fp = mix_openfile(filename, "r")) == NULL)
          167             return -1;
          168     while ((len = fread(chunk, 1, sizeof(chunk), fp)) > 0)
          169             {
          170             fwrite(chunk, 1, len, stdout);
          171         }
          172     fclose (fp);
          173     return (len == 0 ? 0 : (-1));
          174 }
          175 
          176 int closepipe(FILE *p)
          177 {
          178 #ifdef POSIX
          179   return (pclose(p));
          180 #elif defined(_MSC) /* end of POSIX */
          181   return (_pclose(p));
          182 #else /* end of defined(_MSC) */
          183   return -1;
          184 #endif /* else if not defined(_MSC), POSIX */
          185 }
          186 
          187 /** Base 64 encoding ****************************************************/
          188 
          189 static byte bintoasc[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
          190 static byte asctobin[] =
          191 {
          192   0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
          193   0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
          194   0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
          195   0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
          196   0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
          197   0x80, 0x80, 0x80, 0076, 0x80, 0x80, 0x80, 0077,
          198   0064, 0065, 0066, 0067, 0070, 0071, 0072, 0073,
          199   0074, 0075, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
          200   0x80, 0000, 0001, 0002, 0003, 0004, 0005, 0006,
          201   0007, 0010, 0011, 0012, 0013, 0014, 0015, 0016,
          202   0017, 0020, 0021, 0022, 0023, 0024, 0025, 0026,
          203   0027, 0030, 0031, 0x80, 0x80, 0x80, 0x80, 0x80,
          204   0x80, 0032, 0033, 0034, 0035, 0036, 0037, 0040,
          205   0041, 0042, 0043, 0044, 0045, 0046, 0047, 0050,
          206   0051, 0052, 0053, 0054, 0055, 0056, 0057, 0060,
          207   0061, 0062, 0063, 0x80, 0x80, 0x80, 0x80, 0x80,
          208 
          209   0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
          210   0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
          211   0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
          212   0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
          213   0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
          214   0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
          215   0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
          216   0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
          217   0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
          218   0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
          219   0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
          220   0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
          221   0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
          222   0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
          223   0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
          224   0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80
          225 };
          226 
          227 void id_encode(byte id[], byte *s)
          228 {
          229   sprintf
          230     (s, "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
          231      id[0], id[1], id[2], id[3], id[4], id[5], id[6], id[7], id[8], id[9],
          232      id[10], id[11], id[12], id[13], id[14], id[15]);
          233 }
          234 
          235 void id_decode(byte *s, byte id[])
          236 {
          237   int i, x[16];
          238 
          239   sscanf
          240     (s, "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
          241      x, x + 1, x + 2, x + 3, x + 4, x + 5, x + 6, x + 7, x + 8,
          242      x + 9, x + 10, x + 11, x + 12, x + 13, x + 14, x + 15);
          243   for (i = 0; i < 16; i++)
          244     id[i] = x[i];
          245 }
          246 
          247 int encode(BUFFER *in, int linelen)
          248 {
          249   byte *b, *e;
          250   int i, l, m;
          251   unsigned long u;
          252   BUFFER *out;
          253 
          254   out = buf_new();
          255 
          256   l = in->length;
          257   if (l % 3 != 0)
          258     l += 2;
          259   l = l / 3 * 4;
          260 
          261   if (linelen) {
          262     l += l / linelen + (l % linelen > 0 ? 1 : 0);
          263   }
          264   linelen /= 4;                        /* blocks of 4 characters */
          265 
          266   buf_prepare(out, l);
          267 
          268   b = in->data;
          269   e = out->data;
          270   m = in->length - 2;
          271   for (i = 0, l = 0; i < m; i += 3) {
          272     u = ((unsigned long) b[i] << 16) | ((unsigned long) b[i + 1] << 8) |
          273         b[i + 2];
          274     *e++ = bintoasc[(u >> 18) & 0x3f];
          275     *e++ = bintoasc[(u >> 12) & 0x3f];
          276     *e++ = bintoasc[(u >> 6) & 0x3f];
          277     *e++ = bintoasc[u & 0x3f];
          278     if (linelen && ++l >= linelen) {
          279       l = 0;
          280       *e++ = '\n';
          281     }
          282   }
          283   if (i < in->length) {
          284     *e++ = bintoasc[b[i] >> 2];
          285     *e++ = bintoasc[((b[i] << 4) & 0x30) | ((b[i + 1] >> 4) & 0x0f)];
          286     if (i + 1 == in->length)
          287       *e++ = '=';
          288     else
          289       *e++ = bintoasc[((b[i + 1] << 2) & 0x3c) | ((b[i + 2] >> 6) & 0x03)];
          290     *e++ = '=';
          291     ++l;
          292   }
          293   if (linelen && l != 0)
          294     *e++ = '\n';
          295   *e = '\0';
          296 
          297   assert(out->data + out->length == e);
          298   buf_move(in, out);
          299   buf_free(out);
          300   return (0);
          301 }
          302 
          303 int decode(BUFFER *in, BUFFER *out)
          304 {
          305   int err = 0;
          306   register byte c0 = 0, c1 = 0, c2 = 0, c3 = 0;
          307   register byte *a, *d, *end;
          308   int tempbuf = 0;
          309   int i;
          310 
          311   if (in == out) {
          312     out = buf_new();
          313     tempbuf = 1;
          314   }
          315   buf_prepare(out, 3 * (in->length - in->ptr) / 4);
          316 
          317   a = in->data + in->ptr;
          318   end = in->data + in->length - 3;
          319   d = out->data;
          320   i = 0;
          321 
          322   while (a < end) {
          323     if ((c0 = asctobin[a[0]]) & 0x80 ||
          324         (c1 = asctobin[a[1]]) & 0x80 ||
          325         (c2 = asctobin[a[2]]) & 0x80 ||
          326         (c3 = asctobin[a[3]]) & 0x80) {
          327       if (a[0] == '\n') {        /* ignore newline */
          328         a++;
          329         continue;
          330       } else if (a[0] == '\r' && a[1] == '\n') {        /* ignore crlf */
          331         a += 2;
          332         continue;
          333       } else if (a[0] == '=' && a[1] == '4' && a[2] == '6' && !(asctobin[a[5]] & 0x80) ) {
          334         a += 2;                        /* '=46' at the left of a line really is 'F' */
          335         *a = 'F';                /* fix in memory ... */
          336         continue;
          337       } else if (a[2] == '=' || a[3] == '=') {
          338         if (a[0] & 0x80 || (c0 = asctobin[a[0]]) & 0x80 ||
          339             a[1] & 0x80 || (c1 = asctobin[a[1]]) & 0x80)
          340           err = -1;
          341         else if (a[2] == '=')
          342           c2 = 0, i += 1;
          343         else if (a[2] & 0x80 || (c2 = asctobin[a[2]]) & 0x80)
          344           err = -1;
          345         else
          346           i += 2;
          347         if (err == 0) {
          348           /* read the correct final block */
          349           *d++ = (byte) ((c0 << 2) | (c1 >> 4));
          350           *d++ = (byte) ((c1 << 4) | (c2 >> 2));
          351           if (a[3] != '=')
          352             *d++ = (byte) ((c2 << 6));
          353 #if 1
          354           if (a + 4 < in->data + in->length) {
          355             a += 4;
          356             continue;                /* support Mixmaster 2.0.3 encoding */
          357           }
          358 #endif /* 1 */
          359           break;
          360         }
          361       }
          362       err = -1;
          363       break;
          364     }
          365     a += 4;
          366 
          367     *d++ = (byte) ((c0 << 2) | (c1 >> 4));
          368     *d++ = (byte) ((c1 << 4) | (c2 >> 2));
          369     *d++ = (byte) ((c2 << 6) | c3);
          370     i += 3;
          371   }
          372 
          373   in->ptr = a - in->data;
          374 
          375   assert(i <= out->length);
          376   out->length = i;
          377 
          378   if (tempbuf) {
          379     buf_move(in, out);
          380     buf_free(out);
          381   }
          382   return (err);
          383 }
          384 
          385 LOCK *lockfile(char *filename)
          386 {
          387   LOCK *l;
          388   char name[LINELEN];
          389 
          390   strcpy(name, "lck");
          391   if (strchr(filename, DIRSEP))
          392     strcatn(name, strrchr(filename, DIRSEP), LINELEN);
          393   else
          394     strcatn(name, filename, LINELEN);
          395   l = malloc(sizeof(LOCK));
          396 
          397   l->name = malloc(PATHMAX);
          398   mixfile(l->name, name);
          399   l->f = mix_openfile(l->name, "w+");
          400   if (l->f)
          401     lock(l->f);
          402   return (l);
          403 }
          404 
          405 int unlockfile(LOCK *l)
          406 {
          407   if (l->f) {
          408     unlock(l->f);
          409     fclose(l->f);
          410   }
          411   unlink(l->name);
          412   free(l->name);
          413   free(l);
          414   return (0);
          415 }
          416 
          417 int lock(FILE *f)
          418 {
          419 #ifndef WIN32
          420   struct flock lockstruct;
          421 
          422   lockstruct.l_type = F_WRLCK;
          423   lockstruct.l_whence = 0;
          424   lockstruct.l_start = 0;
          425   lockstruct.l_len = 0;
          426   return (fcntl(fileno(f), F_SETLKW, &lockstruct));
          427 #else /* end of WIN32 */
          428   return (0);
          429 #endif /* else if not WIN32 */
          430 }
          431 
          432 int unlock(FILE *f)
          433 {
          434 #ifndef WIN32
          435 
          436   struct flock lockstruct;
          437 
          438   lockstruct.l_type = F_UNLCK;
          439   lockstruct.l_whence = 0;
          440   lockstruct.l_start = 0;
          441   lockstruct.l_len = 0;
          442   return (fcntl(fileno(f), F_SETLKW, &lockstruct));
          443 #else /* end of not WIN32 */
          444   return (0);
          445 #endif /* else if WIN32 */
          446 }
          447 
          448 /* get passphrase ******************************************************/
          449 
          450 static int getuserpass(BUFFER *b, int mode)
          451 {
          452   char p[LINELEN];
          453   int fd;
          454   int n;
          455 
          456 #ifdef HAVE_TERMIOS
          457   struct termios attr;
          458 
          459 #endif /* HAVE_TERMIOS */
          460 
          461   if (mode == 0)
          462     fprintf(stderr, "enter passphrase: ");
          463   else
          464     fprintf(stderr, "re-enter passphrase: ");
          465   fflush(stderr);
          466 #ifndef UNIX
          467 #ifdef HAVE_GETKEY
          468   for (n = 0; p[n] != '\n' && n < LINELEN; n++) {
          469     p[n] = getkey();
          470   }
          471   p[n] = 0;
          472 #else /* end of HAVE_GETKEY */
          473   scanf("%127s", p);
          474 #endif /* else if not HAVE_GETKEY */
          475 #else /* end of not UNIX */
          476   fd = open("/dev/tty", O_RDONLY);
          477   if (tcgetattr(fd, &attr) != 0)
          478     return (-1);
          479   attr.c_lflag &= ~ECHO;
          480   attr.c_lflag |= ICANON;
          481   if (tcsetattr(fd, TCSAFLUSH, &attr) != 0)
          482     return (-1);
          483 
          484   n = read(fd, p, LINELEN);
          485 
          486   attr.c_lflag |= ECHO;
          487   if (tcsetattr(fd, TCSAFLUSH, &attr) != 0)
          488     return (-1);
          489 
          490   close(fd);
          491   fprintf(stderr, "\n");
          492   p[n - 1] = 0;
          493 #endif /* else if UNIX */
          494   if (mode == 0)
          495     buf_appends(b, p);
          496   else
          497     return (bufeq(b, p));
          498   return (0);
          499 }
          500 
          501 static BUFFER *userpass = NULL;
          502 
          503 int user_pass(BUFFER *key)
          504 {
          505   if (userpass == NULL) {
          506     userpass = buf_new();
          507     userpass->sensitive = 1;
          508     if (getenv("MIXPASS"))
          509       buf_sets(userpass, getenv("MIXPASS"));
          510     else if (menu_getuserpass(userpass, 0) == -1)
          511       getuserpass(userpass, 0);
          512   }
          513   buf_set(key, userpass);
          514   key->sensitive = 1;
          515   return (0);
          516 }
          517 
          518 int user_confirmpass(BUFFER *key)
          519 {
          520   int ok;
          521 
          522   ok = menu_getuserpass(key, 1);
          523   if (ok == -1)
          524     ok = getuserpass(key, 1);
          525   return (ok);
          526 }
          527 
          528 void user_delpass(void)
          529 {
          530   if (userpass)
          531     buf_free(userpass);
          532   userpass = NULL;
          533 }
          534 
          535 int write_pidfile(char *pidfile)
          536 {
          537   int err = 0;
          538 #ifdef POSIX
          539   FILE *f;
          540   char host[LINELEN], myhostname[LINELEN];
          541   int pid, mypid;
          542   int assigned;
          543 
          544   mypid = getpid();
          545   gethostname(myhostname, LINELEN);
          546   myhostname[LINELEN-1] = '\0';
          547 
          548   f = mix_openfile(pidfile, "r+");
          549   if (f != NULL) {
          550     assert(LINELEN > 71);
          551     assigned = fscanf(f, "%d %70s", &pid, host);
          552     if (assigned == 2) {
          553       if (strcmp(host, myhostname) == 0) {
          554         if (kill (pid, 0) == -1) {
          555           if (errno == ESRCH) {
          556             fprintf(stderr, "Rewriting stale pid file.\n");
          557             rewind(f);
          558             ftruncate(fileno(f), 0);
          559             fprintf(f, "%d %s\n", mypid, myhostname);
          560           } else {
          561             fprintf(stderr, "Pid file exists and process still running.\n");
          562             err = -1;
          563           }
          564         } else {
          565           fprintf(stderr, "Pid file exists and process still running.\n");
          566           err = -1;
          567         }
          568       } else {
          569         /* Pid file was written on another host, fail */
          570         fprintf(stderr, "Pid file exists and was created on another host (%s).\n", host);
          571         err = -1;
          572       }
          573     } else {
          574       fprintf(stderr, "Pid file exists and and could not be parsed.\n");
          575       err = -1;
          576     }
          577   } else {
          578     if (errno == ENOENT) {
          579       f = mix_openfile(pidfile, "w+");
          580       if (f != NULL) {
          581         fprintf(f, "%d %s\n", mypid, myhostname);
          582       } else {
          583         fprintf(stderr, "Could not open pidfile for writing: %s\n", strerror(errno));
          584         err = -1;
          585       }
          586     } else {
          587       fprintf(stderr, "Could not open pidfile for readwrite: %s\n", strerror(errno));
          588       err = -1;
          589     };
          590   }
          591   if(f)
          592     fclose(f);
          593 #endif /* POSIX */
          594   return (err);
          595 }
          596 
          597 int clear_pidfile(char *pidfile)
          598 {
          599 #ifdef POSIX
          600   char path[PATHMAX];
          601 
          602   mixfile(path, pidfile);
          603   return (unlink(path));
          604 #else /* end of POSIX */
          605   return (0);
          606 #endif /* else if not POSIX */
          607 }
          608 
          609 time_t parse_yearmonthday(char* str)
          610 {
          611   time_t date;
          612   int day, month, year;
          613 
          614   if (sscanf( str, "%d-%d-%d", &year, &month, &day) == 3 ) {
          615     struct tm timestruct;
          616     char *tz;
          617 
          618     tz = getenv("TZ");
          619 #ifdef HAVE_SETENV
          620     setenv("TZ", "GMT", 1);
          621 #else /* end of HAVE_SETENV */
          622     putenv("TZ=GMT");
          623 #endif /* else if not HAVE_SETENV */
          624     tzset();
          625     memset(&timestruct, 0, sizeof(timestruct));
          626     timestruct.tm_mday = day;
          627     timestruct.tm_mon = month - 1;
          628     timestruct.tm_year = year - 1900;
          629     date = mktime(&timestruct);
          630 #ifdef HAVE_SETENV
          631     if (tz)
          632       setenv("TZ", tz, 1);
          633     else
          634       unsetenv("TZ");
          635 #else  /* end of HAVE_SETENV */
          636     if (tz) {
          637       char envstr[LINELEN];
          638       snprintf(envstr, LINELEN, "TZ=%s", tz);
          639       putenv(envstr);
          640     } else
          641       putenv("TZ=");
          642 #endif /* else if not HAVE_SETENV */
          643     tzset();
          644     return date;
          645   } else
          646     return -1;
          647 }
          648 
          649 /* functions missing on some systems *************************************/
          650 
          651 #ifdef __RSXNT__
          652 int fileno(FILE *f)
          653 {
          654   return (f->_handle);
          655 }
          656 
          657 #endif /* __RSXNT__ */
          658 
          659 #ifdef _MSC        /* Visual C lacks dirent */
          660 
          661 DIR *opendir(const char *name)
          662 {
          663   DIR *dir;
          664   WIN32_FIND_DATA d;
          665   char path[PATHMAX];
          666 
          667   dir = malloc(sizeof(HANDLE));
          668 
          669   sprintf(path, "%s%c*", name, DIRSEP);
          670   *dir = FindFirstFile(path, &d);
          671   /* first file found is "." -- can be safely ignored here */
          672 
          673   if (*dir == INVALID_HANDLE_VALUE) {
          674     free(dir);
          675     return (NULL);
          676   } else
          677     return (dir);
          678 }
          679 
          680 struct dirent e;
          681 struct dirent *readdir(DIR *dir)
          682 {
          683   WIN32_FIND_DATA d;
          684   int ok;
          685 
          686   ok = FindNextFile(*dir, &d);
          687   if (ok) {
          688     strncpy(e.d_name, d.cFileName, PATHMAX);
          689     return (&e);
          690   } else
          691     return (NULL);
          692 }
          693 
          694 int closedir(DIR *dir)
          695 {
          696   if (dir) {
          697     FindClose(*dir);
          698     free(dir);
          699     return (0);
          700   }
          701   return (-1);
          702 }
          703 
          704 #endif /* _MSC */