LCOV - code coverage report
Current view: top level - xpcom/io - nsLocalFileCommon.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 49 130 37.7 %
Date: 2017-07-14 16:53:18 Functions: 6 11 54.5 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #include "nsIServiceManager.h"
       8             : 
       9             : #include "nsLocalFile.h" // includes platform-specific headers
      10             : 
      11             : #include "nsString.h"
      12             : #include "nsCOMPtr.h"
      13             : #include "nsReadableUtils.h"
      14             : #include "nsPrintfCString.h"
      15             : #include "nsCRT.h"
      16             : #include "nsNativeCharsetUtils.h"
      17             : #include "nsUTF8Utils.h"
      18             : 
      19             : #ifdef XP_WIN
      20             : #include <string.h>
      21             : #endif
      22             : 
      23             : 
      24             : void
      25           3 : NS_StartupLocalFile()
      26             : {
      27           3 :   nsLocalFile::GlobalInit();
      28           3 : }
      29             : 
      30             : void
      31           0 : NS_ShutdownLocalFile()
      32             : {
      33           0 :   nsLocalFile::GlobalShutdown();
      34           0 : }
      35             : 
      36             : #if !defined(MOZ_WIDGET_COCOA) && !defined(XP_WIN)
      37             : NS_IMETHODIMP
      38           2 : nsLocalFile::InitWithFile(nsIFile* aFile)
      39             : {
      40           2 :   if (NS_WARN_IF(!aFile)) {
      41           0 :     return NS_ERROR_INVALID_ARG;
      42             :   }
      43             : 
      44           4 :   nsAutoCString path;
      45           2 :   aFile->GetNativePath(path);
      46           2 :   if (path.IsEmpty()) {
      47           0 :     return NS_ERROR_INVALID_ARG;
      48             :   }
      49           2 :   return InitWithNativePath(path);
      50             : }
      51             : #endif
      52             : 
      53             : #define kMaxFilenameLength 255
      54             : #define kMaxExtensionLength 100
      55             : #define kMaxSequenceNumberLength 5 // "-9999"
      56             : // requirement: kMaxExtensionLength < kMaxFilenameLength - kMaxSequenceNumberLength
      57             : 
      58             : NS_IMETHODIMP
      59           6 : nsLocalFile::CreateUnique(uint32_t aType, uint32_t aAttributes)
      60             : {
      61             :   nsresult rv;
      62             :   bool longName;
      63             : 
      64             : #ifdef XP_WIN
      65             :   nsAutoString pathName, leafName, rootName, suffix;
      66             :   rv = GetPath(pathName);
      67             : #else
      68          12 :   nsAutoCString pathName, leafName, rootName, suffix;
      69           6 :   rv = GetNativePath(pathName);
      70             : #endif
      71           6 :   if (NS_FAILED(rv)) {
      72           0 :     return rv;
      73             :   }
      74             : 
      75           6 :   longName = (pathName.Length() + kMaxSequenceNumberLength >
      76             :               kMaxFilenameLength);
      77           6 :   if (!longName) {
      78           6 :     rv = Create(aType, aAttributes);
      79           6 :     if (rv != NS_ERROR_FILE_ALREADY_EXISTS) {
      80           0 :       return rv;
      81             :     }
      82             :   }
      83             : 
      84             : #ifdef XP_WIN
      85             :   rv = GetLeafName(leafName);
      86             :   if (NS_FAILED(rv)) {
      87             :     return rv;
      88             :   }
      89             : 
      90             :   const int32_t lastDot = leafName.RFindChar(char16_t('.'));
      91             : #else
      92           6 :   rv = GetNativeLeafName(leafName);
      93           6 :   if (NS_FAILED(rv)) {
      94           0 :     return rv;
      95             :   }
      96             : 
      97           6 :   const int32_t lastDot = leafName.RFindChar('.');
      98             : #endif
      99             : 
     100           6 :   if (lastDot == kNotFound) {
     101           0 :     rootName = leafName;
     102             :   } else {
     103           6 :     suffix = Substring(leafName, lastDot);      // include '.'
     104           6 :     rootName = Substring(leafName, 0, lastDot); // strip suffix and dot
     105             :   }
     106             : 
     107           6 :   if (longName) {
     108             :     int32_t maxRootLength = (kMaxFilenameLength -
     109           0 :                              (pathName.Length() - leafName.Length()) -
     110           0 :                              suffix.Length() - kMaxSequenceNumberLength);
     111             : 
     112             :     // We cannot create an item inside a directory whose name is too long.
     113             :     // Also, ensure that at least one character remains after we truncate
     114             :     // the root name, as we don't want to end up with an empty leaf name.
     115           0 :     if (maxRootLength < 2) {
     116           0 :       return NS_ERROR_FILE_UNRECOGNIZED_PATH;
     117             :     }
     118             : 
     119             : #ifdef XP_WIN
     120             :     // ensure that we don't cut the name in mid-UTF16-character
     121             :     rootName.SetLength(NS_IS_LOW_SURROGATE(rootName[maxRootLength]) ?
     122             :                        maxRootLength - 1 : maxRootLength);
     123             :     SetLeafName(rootName + suffix);
     124             : #else
     125           0 :     if (NS_IsNativeUTF8()) {
     126             :       // ensure that we don't cut the name in mid-UTF8-character
     127             :       // (assume the name is valid UTF8 to begin with)
     128           0 :       while (UTF8traits::isInSeq(rootName[maxRootLength])) {
     129           0 :         --maxRootLength;
     130             :       }
     131             : 
     132             :       // Another check to avoid ending up with an empty leaf name.
     133           0 :       if (maxRootLength == 0 && suffix.IsEmpty()) {
     134           0 :         return NS_ERROR_FILE_UNRECOGNIZED_PATH;
     135             :       }
     136             :     }
     137             : 
     138           0 :     rootName.SetLength(maxRootLength);
     139           0 :     SetNativeLeafName(rootName + suffix);
     140             : #endif
     141           0 :     nsresult rvCreate = Create(aType, aAttributes);
     142           0 :     if (rvCreate != NS_ERROR_FILE_ALREADY_EXISTS) {
     143           0 :       return rvCreate;
     144             :     }
     145             :   }
     146             : 
     147           6 :   for (int indx = 1; indx < 10000; ++indx) {
     148             :     // start with "Picture-1.jpg" after "Picture.jpg" exists
     149             : #ifdef XP_WIN
     150             :     SetLeafName(rootName +
     151             :                 NS_ConvertASCIItoUTF16(nsPrintfCString("-%d", indx)) +
     152             :                 suffix);
     153             : #else
     154           6 :     SetNativeLeafName(rootName + nsPrintfCString("-%d", indx) + suffix);
     155             : #endif
     156           6 :     rv = Create(aType, aAttributes);
     157           6 :     if (NS_SUCCEEDED(rv) || rv != NS_ERROR_FILE_ALREADY_EXISTS) {
     158           6 :       return rv;
     159             :     }
     160             :   }
     161             : 
     162             :   // The disk is full, sort of
     163           0 :   return NS_ERROR_FILE_TOO_BIG;
     164             : }
     165             : 
     166             : #if defined(XP_WIN)
     167             : static const char16_t kPathSeparatorChar       = '\\';
     168             : #elif defined(XP_UNIX)
     169             : static const char16_t kPathSeparatorChar       = '/';
     170             : #else
     171             : #error Need to define file path separator for your platform
     172             : #endif
     173             : 
     174             : static void
     175           0 : SplitPath(char16_t* aPath, nsTArray<char16_t*>& aNodeArray)
     176             : {
     177           0 :   if (*aPath == 0) {
     178           0 :     return;
     179             :   }
     180             : 
     181           0 :   if (*aPath == kPathSeparatorChar) {
     182           0 :     aPath++;
     183             :   }
     184           0 :   aNodeArray.AppendElement(aPath);
     185             : 
     186           0 :   for (char16_t* cp = aPath; *cp != 0; ++cp) {
     187           0 :     if (*cp == kPathSeparatorChar) {
     188           0 :       *cp++ = 0;
     189           0 :       if (*cp == 0) {
     190           0 :         break;
     191             :       }
     192           0 :       aNodeArray.AppendElement(cp);
     193             :     }
     194             :   }
     195             : }
     196             : 
     197             : 
     198             : NS_IMETHODIMP
     199           0 : nsLocalFile::GetRelativeDescriptor(nsIFile* aFromFile, nsACString& aResult)
     200             : {
     201           0 :   if (NS_WARN_IF(!aFromFile)) {
     202           0 :     return NS_ERROR_INVALID_ARG;
     203             :   }
     204             : 
     205             :   //
     206             :   // aResult will be UTF-8 encoded
     207             :   //
     208             : 
     209             :   nsresult rv;
     210           0 :   aResult.Truncate(0);
     211             : 
     212           0 :   nsAutoString thisPath, fromPath;
     213           0 :   AutoTArray<char16_t*, 32> thisNodes;
     214           0 :   AutoTArray<char16_t*, 32> fromNodes;
     215             : 
     216           0 :   rv = GetPath(thisPath);
     217           0 :   if (NS_FAILED(rv)) {
     218           0 :     return rv;
     219             :   }
     220           0 :   rv = aFromFile->GetPath(fromPath);
     221           0 :   if (NS_FAILED(rv)) {
     222           0 :     return rv;
     223             :   }
     224             : 
     225             :   // get raw pointer to mutable string buffer
     226             :   char16_t* thisPathPtr;
     227           0 :   thisPath.BeginWriting(thisPathPtr);
     228             :   char16_t* fromPathPtr;
     229           0 :   fromPath.BeginWriting(fromPathPtr);
     230             : 
     231           0 :   SplitPath(thisPathPtr, thisNodes);
     232           0 :   SplitPath(fromPathPtr, fromNodes);
     233             : 
     234             :   size_t nodeIndex;
     235           0 :   for (nodeIndex = 0;
     236           0 :        nodeIndex < thisNodes.Length() && nodeIndex < fromNodes.Length();
     237             :        ++nodeIndex) {
     238             : #ifdef XP_WIN
     239             :     if (_wcsicmp(char16ptr_t(thisNodes[nodeIndex]),
     240             :                  char16ptr_t(fromNodes[nodeIndex]))) {
     241             :       break;
     242             :     }
     243             : #else
     244           0 :     if (nsCRT::strcmp(thisNodes[nodeIndex], fromNodes[nodeIndex])) {
     245           0 :       break;
     246             :     }
     247             : #endif
     248             :   }
     249             : 
     250           0 :   size_t branchIndex = nodeIndex;
     251           0 :   for (nodeIndex = branchIndex; nodeIndex < fromNodes.Length(); ++nodeIndex) {
     252           0 :     aResult.AppendLiteral("../");
     253             :   }
     254           0 :   for (nodeIndex = branchIndex; nodeIndex < thisNodes.Length(); ++nodeIndex) {
     255           0 :     NS_ConvertUTF16toUTF8 nodeStr(thisNodes[nodeIndex]);
     256           0 :     aResult.Append(nodeStr);
     257           0 :     if (nodeIndex + 1 < thisNodes.Length()) {
     258           0 :       aResult.Append('/');
     259             :     }
     260             :   }
     261             : 
     262           0 :   return NS_OK;
     263             : }
     264             : 
     265             : NS_IMETHODIMP
     266           2 : nsLocalFile::SetRelativeDescriptor(nsIFile* aFromFile,
     267             :                                    const nsACString& aRelativeDesc)
     268             : {
     269           2 :   NS_NAMED_LITERAL_CSTRING(kParentDirStr, "../");
     270             : 
     271           4 :   nsCOMPtr<nsIFile> targetFile;
     272           2 :   nsresult rv = aFromFile->Clone(getter_AddRefs(targetFile));
     273           2 :   if (NS_FAILED(rv)) {
     274           0 :     return rv;
     275             :   }
     276             : 
     277             :   //
     278             :   // aRelativeDesc is UTF-8 encoded
     279             :   //
     280             : 
     281           2 :   nsCString::const_iterator strBegin, strEnd;
     282           2 :   aRelativeDesc.BeginReading(strBegin);
     283           2 :   aRelativeDesc.EndReading(strEnd);
     284             : 
     285           2 :   nsCString::const_iterator nodeBegin(strBegin), nodeEnd(strEnd);
     286           2 :   nsCString::const_iterator pos(strBegin);
     287             : 
     288           4 :   nsCOMPtr<nsIFile> parentDir;
     289           2 :   while (FindInReadable(kParentDirStr, nodeBegin, nodeEnd)) {
     290           0 :     rv = targetFile->GetParent(getter_AddRefs(parentDir));
     291           0 :     if (NS_FAILED(rv)) {
     292           0 :       return rv;
     293             :     }
     294           0 :     if (!parentDir) {
     295           0 :       return NS_ERROR_FILE_UNRECOGNIZED_PATH;
     296             :     }
     297           0 :     targetFile = parentDir;
     298             : 
     299           0 :     nodeBegin = nodeEnd;
     300           0 :     pos = nodeEnd;
     301           0 :     nodeEnd = strEnd;
     302             :   }
     303             : 
     304           2 :   nodeBegin = nodeEnd = pos;
     305           6 :   while (nodeEnd != strEnd) {
     306           2 :     FindCharInReadable('/', nodeEnd, strEnd);
     307           2 :     targetFile->Append(NS_ConvertUTF8toUTF16(Substring(nodeBegin, nodeEnd)));
     308           2 :     if (nodeEnd != strEnd) { // If there's more left in the string, inc over the '/' nodeEnd is on.
     309           0 :       ++nodeEnd;
     310             :     }
     311           2 :     nodeBegin = nodeEnd;
     312             :   }
     313             : 
     314           2 :   return InitWithFile(targetFile);
     315             : }
     316             : 
     317             : NS_IMETHODIMP
     318           0 : nsLocalFile::GetRelativePath(nsIFile* aFromFile, nsACString& aResult)
     319             : {
     320           0 :   return GetRelativeDescriptor(aFromFile, aResult);
     321             : }
     322             : 
     323             : NS_IMETHODIMP
     324           0 : nsLocalFile::SetRelativePath(nsIFile* aFromFile,
     325             :                              const nsACString& aRelativePath)
     326             : {
     327           0 :   return SetRelativeDescriptor(aFromFile, aRelativePath);
     328           9 : }

Generated by: LCOV version 1.13