[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

[or-cvs] [tor/release-0.2.2] Merge remote branch 'origin/maint-0.2.1' into maint-0.2.2



commit f089804332c0289159ec432d8ce82bb1ed6316aa
Merge: cee433d e365aee
Author: Nick Mathewson <nickm@xxxxxxxxxxxxxx>
Date:   Mon Jan 3 15:31:19 2011 -0500

    Merge remote branch 'origin/maint-0.2.1' into maint-0.2.2

 changes/bug2326   |    6 ++++++
 src/common/util.c |    2 +-
 2 files changed, 7 insertions(+), 1 deletions(-)

diff --combined src/common/util.c
index c7282e7,f206d00..abd87ea
--- a/src/common/util.c
+++ b/src/common/util.c
@@@ -15,8 -15,7 +15,8 @@@
  
  #include "orconfig.h"
  #include "util.h"
 -#include "log.h"
 +#include "torlog.h"
 +#undef log
  #include "crypto.h"
  #include "torint.h"
  #include "container.h"
@@@ -26,17 -25,11 +26,17 @@@
  #include <io.h>
  #include <direct.h>
  #include <process.h>
 +#include <tchar.h>
  #else
  #include <dirent.h>
  #include <pwd.h>
  #endif
  
 +/* math.h needs this on Linux */
 +#ifndef __USE_ISOC99
 +#define __USE_ISOC99 1
 +#endif
 +#include <math.h>
  #include <stdlib.h>
  #include <stdio.h>
  #include <string.h>
@@@ -294,7 -287,7 +294,7 @@@ tor_log_mallinfo(int severity
    struct mallinfo mi;
    memset(&mi, 0, sizeof(mi));
    mi = mallinfo();
 -  log(severity, LD_MM,
 +  tor_log(severity, LD_MM,
        "mallinfo() said: arena=%d, ordblks=%d, smblks=%d, hblks=%d, "
        "hblkhd=%d, usmblks=%d, fsmblks=%d, uordblks=%d, fordblks=%d, "
        "keepcost=%d",
@@@ -317,25 -310,6 +317,25 @@@
   * Math
   * ===== */
  
 +/**
 + * Returns the natural logarithm of d base 2.  We define this wrapper here so
 + * as to make it easier not to conflict with Tor's log() macro.
 + */
 +double
 +tor_mathlog(double d)
 +{
 +  return log(d);
 +}
 +
 +/** Return the long integer closest to d.  We define this wrapper here so
 + * that not all users of math.h need to use the right incancations to get
 + * the c99 functions. */
 +long
 +tor_lround(double d)
 +{
 +  return lround(d);
 +}
 +
  /** Returns floor(log2(u64)).  If u64 is 0, (incorrectly) returns 0. */
  int
  tor_log2(uint64_t u64)
@@@ -380,36 -354,6 +380,36 @@@ round_to_power_of_2(uint64_t u64
      return low;
  }
  
 +/** Return the lowest x such that x is at least <b>number</b>, and x modulo
 + * <b>divisor</b> == 0. */
 +unsigned
 +round_to_next_multiple_of(unsigned number, unsigned divisor)
 +{
 +  number += divisor - 1;
 +  number -= number % divisor;
 +  return number;
 +}
 +
 +/** Return the lowest x such that x is at least <b>number</b>, and x modulo
 + * <b>divisor</b> == 0. */
 +uint32_t
 +round_uint32_to_next_multiple_of(uint32_t number, uint32_t divisor)
 +{
 +  number += divisor - 1;
 +  number -= number % divisor;
 +  return number;
 +}
 +
 +/** Return the lowest x such that x is at least <b>number</b>, and x modulo
 + * <b>divisor</b> == 0. */
 +uint64_t
 +round_uint64_to_next_multiple_of(uint64_t number, uint64_t divisor)
 +{
 +  number += divisor - 1;
 +  number -= number % divisor;
 +  return number;
 +}
 +
  /* =====
   * String manipulation
   * ===== */
@@@ -692,29 -636,6 +692,29 @@@ find_whitespace_eos(const char *s, cons
    return s;
  }
  
 +/** Return the first occurrence of <b>needle</b> in <b>haystack</b> that
 + * occurs at the start of a line (that is, at the beginning of <b>haystack</b>
 + * or immediately after a newline).  Return NULL if no such string is found.
 + */
 +const char *
 +find_str_at_start_of_line(const char *haystack, const char *needle)
 +{
 +  size_t needle_len = strlen(needle);
 +
 +  do {
 +    if (!strncmp(haystack, needle, needle_len))
 +      return haystack;
 +
 +    haystack = strchr(haystack, '\n');
 +    if (!haystack)
 +      return NULL;
 +    else
 +      ++haystack;
 +  } while (*haystack);
 +
 +  return NULL;
 +}
 +
  /** Return true iff the 'len' bytes at 'mem' are all zero. */
  int
  tor_mem_is_zero(const char *mem, size_t len)
@@@ -742,13 -663,6 +742,13 @@@ tor_digest_is_zero(const char *digest
    return tor_mem_is_zero(digest, DIGEST_LEN);
  }
  
 +/** Return true iff the DIGEST256_LEN bytes in digest are all zero. */
 +int
 +tor_digest256_is_zero(const char *digest)
 +{
 +  return tor_mem_is_zero(digest, DIGEST256_LEN);
 +}
 +
  /* Helper: common code to check whether the result of a strtol or strtoul or
   * strtoll is correct. */
  #define CHECK_STRTOX_RESULT()                           \
@@@ -800,18 -714,7 +800,18 @@@ tor_parse_ulong(const char *s, int base
    CHECK_STRTOX_RESULT();
  }
  
 -/** As tor_parse_log, but return a unit64_t.  Only base 10 is guaranteed to
 +/** As tor_parse_long(), but return a double. */
 +double
 +tor_parse_double(const char *s, double min, double max, int *ok, char **next)
 +{
 +  char *endptr;
 +  double r;
 +
 +  r = strtod(s, &endptr);
 +  CHECK_STRTOX_RESULT();
 +}
 +
 +/** As tor_parse_long, but return a uint64_t.  Only base 10 is guaranteed to
   * work for now. */
  uint64_t
  tor_parse_uint64(const char *s, int base, uint64_t min,
@@@ -950,9 -853,6 +950,9 @@@ esc_for_log(const char *s
        case '\\':
        case '\"':
        case '\'':
 +      case '\r':
 +      case '\n':
 +      case '\t':
          len += 2;
          break;
        default:
@@@ -1014,7 -914,8 +1014,7 @@@ const char 
  escaped(const char *s)
  {
    static char *_escaped_val = NULL;
 -  if (_escaped_val)
 -    tor_free(_escaped_val);
 +  tor_free(_escaped_val);
  
    if (s)
      _escaped_val = esc_for_log(s);
@@@ -1101,42 -1002,6 +1101,42 @@@ wrap_string(smartlist_t *out, const cha
   * Time
   * ===== */
  
 +/**
 + * Converts struct timeval to a double value.
 + * Preserves microsecond precision, but just barely.
 + * Error is approx +/- 0.1 usec when dealing with epoch values.
 + */
 +double
 +tv_to_double(const struct timeval *tv)
 +{
 +  double conv = tv->tv_sec;
 +  conv += tv->tv_usec/1000000.0;
 +  return conv;
 +}
 +
 +/**
 + * Converts timeval to milliseconds.
 + */
 +int64_t
 +tv_to_msec(const struct timeval *tv)
 +{
 +  int64_t conv = ((int64_t)tv->tv_sec)*1000L;
 +  /* Round ghetto-style */
 +  conv += ((int64_t)tv->tv_usec+500)/1000L;
 +  return conv;
 +}
 +
 +/**
 + * Converts timeval to microseconds.
 + */
 +int64_t
 +tv_to_usec(const struct timeval *tv)
 +{
 +  int64_t conv = ((int64_t)tv->tv_sec)*1000000L;
 +  conv += tv->tv_usec;
 +  return conv;
 +}
 +
  /** Return the number of microseconds elapsed between *start and *end.
   */
  long
@@@ -1146,8 -1011,7 +1146,8 @@@ tv_udiff(const struct timeval *start, c
    long secdiff = end->tv_sec - start->tv_sec;
  
    if (labs(secdiff+1) > LONG_MAX/1000000) {
 -    log_warn(LD_GENERAL, "comparing times too far apart.");
 +    log_warn(LD_GENERAL, "comparing times on microsecond detail too far "
 +             "apart: %ld seconds", secdiff);
      return LONG_MAX;
    }
  
@@@ -1155,26 -1019,6 +1155,26 @@@
    return udiff;
  }
  
 +/** Return the number of milliseconds elapsed between *start and *end.
 + */
 +long
 +tv_mdiff(const struct timeval *start, const struct timeval *end)
 +{
 +  long mdiff;
 +  long secdiff = end->tv_sec - start->tv_sec;
 +
 +  if (labs(secdiff+1) > LONG_MAX/1000) {
 +    log_warn(LD_GENERAL, "comparing times on millisecond detail too far "
 +             "apart: %ld seconds", secdiff);
 +    return LONG_MAX;
 +  }
 +
 +  /* Subtract and round */
 +  mdiff = secdiff*1000L +
 +      ((long)end->tv_usec - (long)start->tv_usec + 500L) / 1000L;
 +  return mdiff;
 +}
 +
  /** Yield true iff <b>y</b> is a leap-year. */
  #define IS_LEAPYEAR(y) (!(y % 4) && ((y % 100) || !(y % 400)))
  /** Helper: Return the number of leap-days between Jan 1, y1 and Jan 1, y2. */
@@@ -1250,7 -1094,7 +1250,7 @@@ format_rfc1123_time(char *buf, time_t t
    memcpy(buf+8, MONTH_NAMES[tm.tm_mon], 3);
  }
  
 -/** Parse the the RFC1123 encoding of some time (in GMT) from <b>buf</b>,
 +/** Parse the RFC1123 encoding of some time (in GMT) from <b>buf</b>,
   * and store the result in *<b>t</b>.
   *
   * Return 0 on success, -1 on failure.
@@@ -1588,49 -1432,6 +1588,49 @@@ ftime_definitely_before(time_t now, tim
  }
  
  /* =====
 + * Rate limiting
 + * ===== */
 +
 +/** If the rate-limiter <b>lim</b> is ready at <b>now</b>, return the number
 + * of calls to rate_limit_is_ready (including this one!) since the last time
 + * rate_limit_is_ready returned nonzero.  Otherwise return 0. */
 +static int
 +rate_limit_is_ready(ratelim_t *lim, time_t now)
 +{
 +  if (lim->rate + lim->last_allowed <= now) {
 +    int res = lim->n_calls_since_last_time + 1;
 +    lim->last_allowed = now;
 +    lim->n_calls_since_last_time = 0;
 +    return res;
 +  } else {
 +    ++lim->n_calls_since_last_time;
 +    return 0;
 +  }
 +}
 +
 +/** If the rate-limiter <b>lim</b> is ready at <b>now</b>, return a newly
 + * allocated string indicating how many messages were suppressed, suitable to
 + * append to a log message.  Otherwise return NULL. */
 +char *
 +rate_limit_log(ratelim_t *lim, time_t now)
 +{
 +  int n;
 +  if ((n = rate_limit_is_ready(lim, now))) {
 +    if (n == 1) {
 +      return tor_strdup("");
 +    } else {
 +      char *cp=NULL;
 +      tor_asprintf(&cp,
 +                   " [%d similar message(s) suppressed in last %d seconds]",
 +                   n-1, lim->rate);
 +      return cp;
 +    }
 +  } else {
 +    return NULL;
 +  }
 +}
 +
 +/* =====
   * File helpers
   * ===== */
  
@@@ -1754,22 -1555,22 +1754,22 @@@ check_private_dir(const char *dirname, 
    tor_free(f);
    if (r) {
      if (errno != ENOENT) {
 -      log(LOG_WARN, LD_FS, "Directory %s cannot be read: %s", dirname,
 -          strerror(errno));
 +      log_warn(LD_FS, "Directory %s cannot be read: %s", dirname,
 +               strerror(errno));
        return -1;
      }
      if (check == CPD_NONE) {
 -      log(LOG_WARN, LD_FS, "Directory %s does not exist.", dirname);
 +      log_warn(LD_FS, "Directory %s does not exist.", dirname);
        return -1;
      } else if (check == CPD_CREATE) {
        log_info(LD_GENERAL, "Creating directory %s", dirname);
 -#ifdef MS_WINDOWS
 +#if defined (MS_WINDOWS) && !defined (WINCE)
        r = mkdir(dirname);
  #else
        r = mkdir(dirname, 0700);
  #endif
        if (r) {
 -        log(LOG_WARN, LD_FS, "Error creating directory %s: %s", dirname,
 +        log_warn(LD_FS, "Error creating directory %s: %s", dirname,
              strerror(errno));
          return -1;
        }
@@@ -1779,7 -1580,7 +1779,7 @@@
      return 0;
    }
    if (!(st.st_mode & S_IFDIR)) {
 -    log(LOG_WARN, LD_FS, "%s is not a directory", dirname);
 +    log_warn(LD_FS, "%s is not a directory", dirname);
      return -1;
    }
  #ifndef MS_WINDOWS
@@@ -1792,7 -1593,7 +1792,7 @@@
  
      pw = getpwuid(st.st_uid);
  
 -    log(LOG_WARN, LD_FS, "%s is not owned by this user (%s, %d) but by "
 +    log_warn(LD_FS, "%s is not owned by this user (%s, %d) but by "
          "%s (%d). Perhaps you are running Tor as the wrong user?",
                           dirname, process_ownername, (int)getuid(),
                           pw ? pw->pw_name : "<unknown>", (int)st.st_uid);
@@@ -1801,9 -1602,9 +1801,9 @@@
      return -1;
    }
    if (st.st_mode & 0077) {
 -    log(LOG_WARN, LD_FS, "Fixing permissions on directory %s", dirname);
 +    log_warn(LD_FS, "Fixing permissions on directory %s", dirname);
      if (chmod(dirname, 0700)) {
 -      log(LOG_WARN, LD_FS, "Could not chmod directory %s: %s", dirname,
 +      log_warn(LD_FS, "Could not chmod directory %s: %s", dirname,
            strerror(errno));
        return -1;
      } else {
@@@ -1834,13 -1635,12 +1834,13 @@@ write_str_to_file(const char *fname, co
  }
  
  /** Represents a file that we're writing to, with support for atomic commit:
 - * we can write into a a temporary file, and either remove the file on
 + * we can write into a temporary file, and either remove the file on
   * failure, or replace the original file on success. */
  struct open_file_t {
    char *tempname; /**< Name of the temporary file. */
    char *filename; /**< Name of the original file. */
 -  int rename_on_close; /**< Are we using the temporary file or not? */
 +  unsigned rename_on_close:1; /**< Are we using the temporary file or not? */
 +  unsigned binary:1; /**< Did we open in binary mode? */
    int fd; /**< fd for the open file. */
    FILE *stdio_file; /**< stdio wrapper for <b>fd</b>. */
  };
@@@ -1888,7 -1688,7 +1888,7 @@@ start_writing_to_file(const char *fname
    } else {
      open_name = new_file->tempname = tor_malloc(tempname_len);
      if (tor_snprintf(new_file->tempname, tempname_len, "%s.tmp", fname)<0) {
 -      log(LOG_WARN, LD_GENERAL, "Failed to generate filename");
 +      log_warn(LD_GENERAL, "Failed to generate filename");
        goto err;
      }
      /* We always replace an existing temporary file if there is one. */
@@@ -1896,12 -1696,9 +1896,12 @@@
      open_flags &= ~O_EXCL;
      new_file->rename_on_close = 1;
    }
 +  if (open_flags & O_BINARY)
 +    new_file->binary = 1;
  
 -  if ((new_file->fd = open(open_name, open_flags, mode)) < 0) {
 -    log(LOG_WARN, LD_FS, "Couldn't open \"%s\" (%s) for writing: %s",
 +  new_file->fd = open(open_name, open_flags, mode);
 +  if (new_file->fd < 0) {
 +    log_warn(LD_FS, "Couldn't open \"%s\" (%s) for writing: %s",
          open_name, fname, strerror(errno));
      goto err;
    }
@@@ -1937,8 -1734,7 +1937,8 @@@ fdopen_file(open_file_t *file_data
    if (file_data->stdio_file)
      return file_data->stdio_file;
    tor_assert(file_data->fd >= 0);
 -  if (!(file_data->stdio_file = fdopen(file_data->fd, "a"))) {
 +  if (!(file_data->stdio_file = fdopen(file_data->fd,
 +                                       file_data->binary?"ab":"a"))) {
      log_warn(LD_FS, "Couldn't fdopen \"%s\" [%d]: %s", file_data->filename,
               file_data->fd, strerror(errno));
    }
@@@ -2038,7 -1834,7 +2038,7 @@@ write_chunks_to_file_impl(const char *f
    {
      result = write_all(fd, chunk->bytes, chunk->len, 0);
      if (result < 0) {
 -      log(LOG_WARN, LD_FS, "Error writing to \"%s\": %s", fname,
 +      log_warn(LD_FS, "Error writing to \"%s\": %s", fname,
            strerror(errno));
        goto err;
      }
@@@ -2140,7 -1936,7 +2140,7 @@@ read_file_to_str(const char *filename, 
      return NULL;
    }
  
-   if ((uint64_t)(statbuf.st_size)+1 > SIZE_T_CEILING)
+   if ((uint64_t)(statbuf.st_size)+1 >= SIZE_T_CEILING)
      return NULL;
  
    string = tor_malloc((size_t)(statbuf.st_size+1));
@@@ -2294,40 -2090,7 +2294,40 @@@ unescape_string(const char *s, char **r
  const char *
  parse_config_line_from_str(const char *line, char **key_out, char **value_out)
  {
 +  /* I believe the file format here is supposed to be:
 +     FILE = (EMPTYLINE | LINE)* (EMPTYLASTLINE | LASTLINE)?
 +
 +     EMPTYLASTLINE = SPACE* | COMMENT
 +     EMPTYLINE = EMPTYLASTLINE NL
 +     SPACE = ' ' | '\r' | '\t'
 +     COMMENT = '#' NOT-NL*
 +     NOT-NL = Any character except '\n'
 +     NL = '\n'
 +
 +     LASTLINE = SPACE* KEY SPACE* VALUES
 +     LINE = LASTLINE NL
 +     KEY = KEYCHAR+
 +     KEYCHAR = Any character except ' ', '\r', '\n', '\t', '#', "\"
 +
 +     VALUES = QUOTEDVALUE | NORMALVALUE
 +     QUOTEDVALUE = QUOTE QVITEM* QUOTE EOLSPACE?
 +     QUOTE = '"'
 +     QVCHAR = KEYCHAR | ESC ('n' | 't' | 'r' | '"' | ESC |'\'' | OCTAL | HEX)
 +     ESC = "\\"
 +     OCTAL = ODIGIT (ODIGIT ODIGIT?)?
 +     HEX = ('x' | 'X') HEXDIGIT HEXDIGIT
 +     ODIGIT = '0' .. '7'
 +     HEXDIGIT = '0'..'9' | 'a' .. 'f' | 'A' .. 'F'
 +     EOLSPACE = SPACE* COMMENT?
 +
 +     NORMALVALUE = (VALCHAR | ESC ESC_IGNORE | CONTINUATION)* EOLSPACE?
 +     VALCHAR = Any character except ESC, '#', and '\n'
 +     ESC_IGNORE = Any character except '#' or '\n'
 +     CONTINUATION = ESC NL ( COMMENT NL )*
 +   */
 +
    const char *key, *val, *cp;
 +  int continuation = 0;
  
    tor_assert(key_out);
    tor_assert(value_out);
@@@ -2351,10 -2114,9 +2351,10 @@@
      return line;
    }
  
 -  /* Skip until the next space. */
 +  /* Skip until the next space or \ followed by newline. */
    key = line;
 -  while (*line && !TOR_ISSPACE(*line) && *line != '#')
 +  while (*line && !TOR_ISSPACE(*line) && *line != '#' &&
 +         ! (line[0] == '\\' && line[1] == '\n'))
      ++line;
    *key_out = tor_strndup(key, line-key);
  
@@@ -2365,7 -2127,7 +2365,7 @@@
    val = line;
  
    /* Find the end of the line. */
 -  if (*line == '\"') {
 +  if (*line == '\"') { // XXX No continuation handling is done here
      if (!(line = unescape_string(line, value_out, NULL)))
         return NULL;
      while (*line == ' ' || *line == '\t')
@@@ -2373,53 -2135,18 +2373,53 @@@
      if (*line && *line != '#' && *line != '\n')
        return NULL;
    } else {
 -    while (*line && *line != '\n' && *line != '#')
 -      ++line;
 +    /* Look for the end of the line. */
 +    while (*line && *line != '\n' && (*line != '#' || continuation)) {
 +      if (*line == '\\' && line[1] == '\n') {
 +        continuation = 1;
 +        line += 2;
 +      } else if (*line == '#') {
 +        do {
 +          ++line;
 +        } while (*line && *line != '\n');
 +        if (*line == '\n')
 +          ++line;
 +      } else {
 +        ++line;
 +      }
 +    }
 +
      if (*line == '\n') {
        cp = line++;
      } else {
        cp = line;
      }
 +    /* Now back cp up to be the last nonspace character */
      while (cp>val && TOR_ISSPACE(*(cp-1)))
        --cp;
  
      tor_assert(cp >= val);
 +
 +    /* Now copy out and decode the value. */
      *value_out = tor_strndup(val, cp-val);
 +    if (continuation) {
 +      char *v_out, *v_in;
 +      v_out = v_in = *value_out;
 +      while (*v_in) {
 +        if (*v_in == '#') {
 +          do {
 +            ++v_in;
 +          } while (*v_in && *v_in != '\n');
 +          if (*v_in == '\n')
 +            ++v_in;
 +        } else if (v_in[0] == '\\' && v_in[1] == '\n') {
 +          v_in += 2;
 +        } else {
 +          *v_out++ = *v_in++;
 +        }
 +      }
 +      *v_out = '\0';
 +    }
    }
  
    if (*line == '#') {
@@@ -2438,22 -2165,19 +2438,22 @@@ char 
  expand_filename(const char *filename)
  {
    tor_assert(filename);
 +#ifdef MS_WINDOWS
 +  return tor_strdup(filename);
 +#else
    if (*filename == '~') {
 -    size_t len;
 -    char *home, *result;
 +    char *home, *result=NULL;
      const char *rest;
  
      if (filename[1] == '/' || filename[1] == '\0') {
        home = getenv("HOME");
        if (!home) {
          log_warn(LD_CONFIG, "Couldn't find $HOME environment variable while "
 -                 "expanding \"%s\"", filename);
 -        return NULL;
 +                 "expanding \"%s\"; defaulting to \"\".", filename);
 +        home = tor_strdup("");
 +      } else {
 +        home = tor_strdup(home);
        }
 -      home = tor_strdup(home);
        rest = strlen(filename)>=2?(filename+2):"";
      } else {
  #ifdef HAVE_PWD_H
@@@ -2480,19 -2204,21 +2480,19 @@@
      if (strlen(home)>1 && !strcmpend(home,PATH_SEPARATOR)) {
        home[strlen(home)-1] = '\0';
      }
 -    /* Plus one for /, plus one for NUL.
 -     * Round up to 16 in case we can't do math. */
 -    len = strlen(home)+strlen(rest)+16;
 -    result = tor_malloc(len);
 -    tor_snprintf(result,len,"%s"PATH_SEPARATOR"%s",home,rest);
 +    tor_asprintf(&result,"%s"PATH_SEPARATOR"%s",home,rest);
      tor_free(home);
      return result;
    } else {
      return tor_strdup(filename);
    }
 +#endif
  }
  
  #define MAX_SCANF_WIDTH 9999
  
 -/** DOCDOC */
 +/** Helper: given an ASCII-encoded decimal digit, return its numeric value.
 + * NOTE: requires that its input be in-bounds. */
  static int
  digit_to_num(char d)
  {
@@@ -2501,10 -2227,7 +2501,10 @@@
    return num;
  }
  
 -/** DOCDOC */
 +/** Helper: Read an unsigned int from *<b>bufp</b> of up to <b>width</b>
 + * characters.  (Handle arbitrary width if <b>width</b> is less than 0.)  On
 + * success, store the result in <b>out</b>, advance bufp to the next
 + * character, and return 0.  On failure, return -1. */
  static int
  scan_unsigned(const char **bufp, unsigned *out, int width)
  {
@@@ -2531,9 -2254,7 +2531,9 @@@
    return 0;
  }
  
 -/** DOCDOC */
 +/** Helper: copy up to <b>width</b> non-space characters from <b>bufp</b> to
 + * <b>out</b>.  Make sure <b>out</b> is nul-terminated. Advance <b>bufp</b>
 + * to the next non-space character or the EOS. */
  static int
  scan_string(const char **bufp, char *out, int width)
  {
@@@ -2622,12 -2343,7 +2622,12 @@@ tor_vsscanf(const char *buf, const cha
   * and store the results in the corresponding argument fields.  Differs from
   * sscanf in that it: Only handles %u and %Ns.  Does not handle arbitrarily
   * long widths. %u does not consume any space.  Is locale-independent.
 - * Returns -1 on malformed patterns. */
 + * Returns -1 on malformed patterns.
 + *
 + * (As with other locale-independent functions, we need this to parse data that
 + * is in ASCII without worrying that the C library's locale-handling will make
 + * miscellaneous characters look like numbers, spaces, and so on.)
 + */
  int
  tor_sscanf(const char *buf, const char *pattern, ...)
  {
@@@ -2648,32 -2364,20 +2648,32 @@@ tor_listdir(const char *dirname
    smartlist_t *result;
  #ifdef MS_WINDOWS
    char *pattern;
 +  TCHAR tpattern[MAX_PATH] = {0};
 +  char name[MAX_PATH] = {0};
    HANDLE handle;
    WIN32_FIND_DATA findData;
    size_t pattern_len = strlen(dirname)+16;
    pattern = tor_malloc(pattern_len);
    tor_snprintf(pattern, pattern_len, "%s\\*", dirname);
 -  if (INVALID_HANDLE_VALUE == (handle = FindFirstFile(pattern, &findData))) {
 +#ifdef UNICODE
 +  mbstowcs(tpattern,pattern,MAX_PATH);
 +#else
 +  strlcpy(tpattern, pattern, MAX_PATH);
 +#endif
 +  if (INVALID_HANDLE_VALUE == (handle = FindFirstFile(tpattern, &findData))) {
      tor_free(pattern);
      return NULL;
    }
    result = smartlist_create();
    while (1) {
 -    if (strcmp(findData.cFileName, ".") &&
 -        strcmp(findData.cFileName, "..")) {
 -      smartlist_add(result, tor_strdup(findData.cFileName));
 +#ifdef UNICODE
 +    wcstombs(name,findData.cFileName,MAX_PATH);
 +#else
 +    strlcpy(name,findData.cFileName,sizeof(name));
 +#endif
 +    if (strcmp(name, ".") &&
 +        strcmp(name, "..")) {
 +      smartlist_add(result, tor_strdup(name));
      }
      if (!FindNextFile(handle, &findData)) {
        DWORD err;
@@@ -2872,18 -2576,3 +2872,18 @@@ write_pidfile(char *filename
    }
  }
  
 +#ifdef MS_WINDOWS
 +HANDLE
 +load_windows_system_library(const TCHAR *library_name)
 +{
 +  TCHAR path[MAX_PATH];
 +  unsigned n;
 +  n = GetSystemDirectory(path, MAX_PATH);
 +  if (n == 0 || n + _tcslen(library_name) + 2 >= MAX_PATH)
 +    return 0;
 +  _tcscat(path, TEXT("\\"));
 +  _tcscat(path, library_name);
 +  return LoadLibrary(path);
 +}
 +#endif
 +