xpcom/glue/nsINIParser.cpp

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

     1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
     2 /* This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 // Moz headers (alphabetical)
     7 #include "nsCRTGlue.h"
     8 #include "nsError.h"
     9 #include "nsIFile.h"
    10 #include "nsINIParser.h"
    11 #include "mozilla/FileUtils.h" // AutoFILE
    13 // System headers (alphabetical)
    14 #include <stdio.h>
    15 #include <stdlib.h>
    16 #ifdef XP_WIN
    17 #include <windows.h>
    18 #endif
    20 #if defined(XP_WIN)
    21 #define READ_BINARYMODE L"rb"
    22 #else
    23 #define READ_BINARYMODE "r"
    24 #endif
    26 #ifdef XP_WIN
    27 inline FILE *TS_tfopen (const char *path, const wchar_t *mode)
    28 {
    29     wchar_t wPath[MAX_PATH];
    30     MultiByteToWideChar(CP_UTF8, 0, path, -1, wPath, MAX_PATH);
    31     return _wfopen(wPath, mode);
    32 }
    33 #else
    34 inline FILE *TS_tfopen (const char *path, const char *mode)
    35 {
    36     return fopen(path, mode);
    37 }
    38 #endif
    40 // Stack based FILE wrapper to ensure that fclose is called, copied from
    41 // toolkit/mozapps/update/updater/readstrings.cpp
    43 class AutoFILE {
    44 public:
    45   AutoFILE(FILE *fp = nullptr) : fp_(fp) {}
    46   ~AutoFILE() { if (fp_) fclose(fp_); }
    47   operator FILE *() { return fp_; }
    48   FILE** operator &() { return &fp_; }
    49   void operator=(FILE *fp) { fp_ = fp; }
    50 private:
    51   FILE *fp_;
    52 };
    54 nsresult
    55 nsINIParser::Init(nsIFile* aFile)
    56 {
    57     /* open the file. Don't use OpenANSIFileDesc, because you mustn't
    58        pass FILE* across shared library boundaries, which may be using
    59        different CRTs */
    61     AutoFILE fd;
    63 #ifdef XP_WIN
    64     nsAutoString path;
    65     nsresult rv = aFile->GetPath(path);
    66     if (NS_WARN_IF(NS_FAILED(rv)))
    67       return rv;
    69     fd = _wfopen(path.get(), READ_BINARYMODE);
    70 #else
    71     nsAutoCString path;
    72     aFile->GetNativePath(path);
    74     fd = fopen(path.get(), READ_BINARYMODE);
    75 #endif
    77     if (!fd)
    78       return NS_ERROR_FAILURE;
    80     return InitFromFILE(fd);
    81 }
    83 nsresult
    84 nsINIParser::Init(const char *aPath)
    85 {
    86     /* open the file */
    87     AutoFILE fd = TS_tfopen(aPath, READ_BINARYMODE);
    89     if (!fd)
    90         return NS_ERROR_FAILURE;
    92     return InitFromFILE(fd);
    93 }
    95 static const char kNL[] = "\r\n";
    96 static const char kEquals[] = "=";
    97 static const char kWhitespace[] = " \t";
    98 static const char kRBracket[] = "]";
   100 nsresult
   101 nsINIParser::InitFromFILE(FILE *fd)
   102 {
   103     /* get file size */
   104     if (fseek(fd, 0, SEEK_END) != 0)
   105         return NS_ERROR_FAILURE;
   107     long flen = ftell(fd);
   108     if (flen == 0)
   109         return NS_ERROR_FAILURE;
   111     /* malloc an internal buf the size of the file */
   112     mFileContents = new char[flen + 2];
   113     if (!mFileContents)
   114         return NS_ERROR_OUT_OF_MEMORY;
   116     /* read the file in one swoop */
   117     if (fseek(fd, 0, SEEK_SET) != 0)
   118         return NS_BASE_STREAM_OSERROR;
   120     int rd = fread(mFileContents, sizeof(char), flen, fd);
   121     if (rd != flen)
   122         return NS_BASE_STREAM_OSERROR;
   124     // We write a UTF16 null so that the file is easier to convert to UTF8
   125     mFileContents[flen] = mFileContents[flen + 1] = '\0';
   127     char *buffer = &mFileContents[0];
   129     if (flen >= 3
   130     && mFileContents[0] == static_cast<char>(0xEF)
   131     && mFileContents[1] == static_cast<char>(0xBB)
   132     && mFileContents[2] == static_cast<char>(0xBF)) {
   133       // Someone set us up the Utf-8 BOM
   134       // This case is easy, since we assume that BOM-less
   135       // files are Utf-8 anyway.  Just skip the BOM and process as usual.
   136       buffer = &mFileContents[3];
   137     }
   139 #ifdef XP_WIN
   140     if (flen >= 2
   141      && mFileContents[0] == static_cast<char>(0xFF)
   142      && mFileContents[1] == static_cast<char>(0xFE)) {
   143         // Someone set us up the Utf-16LE BOM
   144         buffer = &mFileContents[2];
   145         // Get the size required for our Utf8 buffer
   146         flen = WideCharToMultiByte(CP_UTF8,
   147                                    0,
   148                                    reinterpret_cast<LPWSTR>(buffer),
   149                                    -1,
   150                                    nullptr,
   151                                    0,
   152                                    nullptr,
   153                                    nullptr);
   154         if (0 == flen) {
   155             return NS_ERROR_FAILURE;
   156         }
   158         nsAutoArrayPtr<char> utf8Buffer(new char[flen]);
   159         if (0 == WideCharToMultiByte(CP_UTF8,
   160                                      0,
   161                                      reinterpret_cast<LPWSTR>(buffer),
   162                                      -1,
   163                                      utf8Buffer,
   164                                      flen,
   165                                      nullptr,
   166                                      nullptr)) {
   167             return NS_ERROR_FAILURE;
   168         }
   169         mFileContents = utf8Buffer.forget();
   170         buffer = mFileContents;
   171     }
   172 #endif
   174     char *currSection = nullptr;
   176     // outer loop tokenizes into lines
   177     while (char *token = NS_strtok(kNL, &buffer)) {
   178         if (token[0] == '#' || token[0] == ';') // it's a comment
   179             continue;
   181         token = (char*) NS_strspnp(kWhitespace, token);
   182         if (!*token) // empty line
   183             continue;
   185         if (token[0] == '[') { // section header!
   186             ++token;
   187             currSection = token;
   189             char *rb = NS_strtok(kRBracket, &token);
   190             if (!rb || NS_strtok(kWhitespace, &token)) {
   191                 // there's either an unclosed [Section or a [Section]Moretext!
   192                 // we could frankly decide that this INI file is malformed right
   193                 // here and stop, but we won't... keep going, looking for
   194                 // a well-formed [section] to continue working with
   195                 currSection = nullptr;
   196             }
   198             continue;
   199         }
   201         if (!currSection) {
   202             // If we haven't found a section header (or we found a malformed
   203             // section header), don't bother parsing this line.
   204             continue;
   205         }
   207         char *key = token;
   208         char *e = NS_strtok(kEquals, &token);
   209         if (!e || !token)
   210             continue;
   212         INIValue *v;
   213         if (!mSections.Get(currSection, &v)) {
   214             v = new INIValue(key, token);
   215             if (!v)
   216                 return NS_ERROR_OUT_OF_MEMORY;
   218             mSections.Put(currSection, v);
   219             continue;
   220         }
   222         // Check whether this key has already been specified; overwrite
   223         // if so, or append if not.
   224         while (v) {
   225             if (!strcmp(key, v->key)) {
   226                 v->value = token;
   227                 break;
   228             }
   229             if (!v->next) {
   230                 v->next = new INIValue(key, token);
   231                 if (!v->next)
   232                     return NS_ERROR_OUT_OF_MEMORY;
   233                 break;
   234             }
   235             v = v->next;
   236         }
   237         NS_ASSERTION(v, "v should never be null coming out of this loop");
   238     }
   240     return NS_OK;
   241 }
   243 nsresult
   244 nsINIParser::GetString(const char *aSection, const char *aKey, 
   245                        nsACString &aResult)
   246 {
   247     INIValue *val;
   248     mSections.Get(aSection, &val);
   250     while (val) {
   251         if (strcmp(val->key, aKey) == 0) {
   252             aResult.Assign(val->value);
   253             return NS_OK;
   254         }
   256         val = val->next;
   257     }
   259     return NS_ERROR_FAILURE;
   260 }
   262 nsresult
   263 nsINIParser::GetString(const char *aSection, const char *aKey, 
   264                        char *aResult, uint32_t aResultLen)
   265 {
   266     INIValue *val;
   267     mSections.Get(aSection, &val);
   269     while (val) {
   270         if (strcmp(val->key, aKey) == 0) {
   271             strncpy(aResult, val->value, aResultLen);
   272             aResult[aResultLen - 1] = '\0';
   273             if (strlen(val->value) >= aResultLen)
   274                 return NS_ERROR_LOSS_OF_SIGNIFICANT_DATA;
   276             return NS_OK;
   277         }
   279         val = val->next;
   280     }
   282     return NS_ERROR_FAILURE;
   283 }
   285 PLDHashOperator
   286 nsINIParser::GetSectionsCB(const char *aKey, INIValue *aData,
   287                            void *aClosure)
   288 {
   289     GSClosureStruct *cs = reinterpret_cast<GSClosureStruct*>(aClosure);
   291     return cs->usercb(aKey, cs->userclosure) ? PL_DHASH_NEXT : PL_DHASH_STOP;
   292 }
   294 nsresult
   295 nsINIParser::GetSections(INISectionCallback aCB, void *aClosure)
   296 {
   297     GSClosureStruct gs = {
   298         aCB,
   299         aClosure
   300     };
   302     mSections.EnumerateRead(GetSectionsCB, &gs);
   303     return NS_OK;
   304 }
   306 nsresult
   307 nsINIParser::GetStrings(const char *aSection,
   308                         INIStringCallback aCB, void *aClosure)
   309 {
   310     INIValue *val;
   312     for (mSections.Get(aSection, &val);
   313          val;
   314          val = val->next) {
   316         if (!aCB(val->key, val->value, aClosure))
   317             return NS_OK;
   318     }
   320     return NS_OK;
   321 }

mercurial