xpcom/io/nsLocalFileCommon.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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

mercurial