Make CreateUnique use UTF-16 path names on Windows and correct some bugs with handling over-long filenames. Bug 364285, r=bsmedberg, blocking-firefox3=beltzner
This commit is contained in:
Родитель
3932b281df
Коммит
d01e9d3cfe
|
@ -1,4 +1,4 @@
|
|||
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
|
@ -45,6 +45,8 @@
|
|||
#include "nsReadableUtils.h"
|
||||
#include "nsPrintfCString.h"
|
||||
#include "nsCRT.h"
|
||||
#include "nsNativeCharsetUtils.h"
|
||||
#include "nsUTF8Utils.h"
|
||||
|
||||
#ifdef XP_WIN
|
||||
#include <string.h>
|
||||
|
@ -77,40 +79,91 @@ nsLocalFile::InitWithFile(nsILocalFile *aFile)
|
|||
|
||||
#define kMaxFilenameLength 255
|
||||
#define kMaxExtensionLength 100
|
||||
// requirement: kMaxExtensionLength < kMaxFilenameLength - 4
|
||||
#define kMaxSequenceNumberLength 5 // "-9999"
|
||||
// requirement: kMaxExtensionLength < kMaxFilenameLength - kMaxSequenceNumberLength
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsLocalFile::CreateUnique(PRUint32 type, PRUint32 attributes)
|
||||
{
|
||||
nsresult rv = Create(type, attributes);
|
||||
if (rv != NS_ERROR_FILE_ALREADY_EXISTS)
|
||||
nsresult rv;
|
||||
PRBool longName;
|
||||
|
||||
#ifdef XP_WIN
|
||||
nsAutoString pathName, leafName, rootName, suffix;
|
||||
rv = GetPath(pathName);
|
||||
#else
|
||||
nsCAutoString pathName, leafName, rootName, suffix;
|
||||
rv = GetNativePath(pathName);
|
||||
#endif
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
nsCAutoString leafName;
|
||||
longName = (pathName.Length() + kMaxSequenceNumberLength >
|
||||
kMaxFilenameLength);
|
||||
if (!longName)
|
||||
{
|
||||
rv = Create(type, attributes);
|
||||
if (rv != NS_ERROR_FILE_ALREADY_EXISTS)
|
||||
return rv;
|
||||
}
|
||||
|
||||
#ifdef XP_WIN
|
||||
rv = GetLeafName(leafName);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
const PRInt32 lastDot = leafName.RFindChar(PRUnichar('.'));
|
||||
#else
|
||||
rv = GetNativeLeafName(leafName);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
const char* lastDot = strrchr(leafName.get(), '.');
|
||||
char suffix[kMaxExtensionLength] = "";
|
||||
if (lastDot)
|
||||
const PRInt32 lastDot = leafName.RFindChar('.');
|
||||
#endif
|
||||
|
||||
if (lastDot == kNotFound)
|
||||
{
|
||||
PL_strncpyz(suffix, lastDot, sizeof(suffix)); // include '.'
|
||||
leafName.SetLength(lastDot - leafName.get()); // strip suffix and dot.
|
||||
rootName = leafName;
|
||||
}
|
||||
else
|
||||
{
|
||||
suffix = Substring(leafName, lastDot); // include '.'
|
||||
rootName = Substring(leafName, 0, lastDot); // strip suffix and dot
|
||||
}
|
||||
|
||||
PRUint32 maxRootLength = (kMaxFilenameLength - 4) - strlen(suffix) - 1;
|
||||
|
||||
if (leafName.Length() > maxRootLength)
|
||||
leafName.SetLength(maxRootLength);
|
||||
if (longName)
|
||||
{
|
||||
PRUint32 maxRootLength = (kMaxFilenameLength -
|
||||
(pathName.Length() - leafName.Length()) -
|
||||
suffix.Length() - kMaxSequenceNumberLength);
|
||||
#ifdef XP_WIN
|
||||
// ensure that we don't cut the name in mid-UTF16-character
|
||||
rootName.SetLength(NS_IS_LOW_SURROGATE(rootName[maxRootLength]) ?
|
||||
maxRootLength - 1 : maxRootLength);
|
||||
SetLeafName(rootName + suffix);
|
||||
#else
|
||||
if (NS_IsNativeUTF8())
|
||||
// ensure that we don't cut the name in mid-UTF8-character
|
||||
while (UTF8traits::isInSeq(rootName[maxRootLength]))
|
||||
--maxRootLength;
|
||||
rootName.SetLength(maxRootLength);
|
||||
SetNativeLeafName(rootName + suffix);
|
||||
#endif
|
||||
nsresult rv = Create(type, attributes);
|
||||
if (rv != NS_ERROR_FILE_ALREADY_EXISTS)
|
||||
return rv;
|
||||
}
|
||||
|
||||
for (int indx = 1; indx < 10000; indx++)
|
||||
{
|
||||
// start with "Picture-1.jpg" after "Picture.jpg" exists
|
||||
SetNativeLeafName(leafName +
|
||||
nsPrintfCString("-%d", indx) +
|
||||
nsDependentCString(suffix));
|
||||
|
||||
#ifdef XP_WIN
|
||||
SetLeafName(rootName +
|
||||
NS_ConvertASCIItoUTF16(nsPrintfCString("-%d", indx)) +
|
||||
suffix);
|
||||
#else
|
||||
SetNativeLeafName(rootName + nsPrintfCString("-%d", indx) + suffix);
|
||||
#endif
|
||||
rv = Create(type, attributes);
|
||||
if (NS_SUCCEEDED(rv) || rv != NS_ERROR_FILE_ALREADY_EXISTS)
|
||||
return rv;
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
const Ci = Components.interfaces;
|
||||
const Cc = Components.classes;
|
||||
|
||||
var nameArray = [
|
||||
"ascii", // ASCII
|
||||
"fran\u00E7ais", // Latin-1
|
||||
"\u0420\u0443\u0441\u0441\u043A\u0438\u0439", // Cyrillic
|
||||
"\u65E5\u672C\u8A9E", // Japanese
|
||||
"\u4E2D\u6587", // Chinese
|
||||
"\uD55C\uAD6D\uC5B4", // Korean
|
||||
"\uD801\uDC0F\uD801\uDC2D\uD801\uDC3B\uD801\uDC2B" // Deseret
|
||||
];
|
||||
|
||||
function getTempDir()
|
||||
{
|
||||
var dirService = Cc["@mozilla.org/file/directory_service;1"]
|
||||
.getService(Ci.nsIProperties);
|
||||
return dirService.get("TmpD", Ci.nsILocalFile);
|
||||
}
|
||||
|
||||
function create_file(fileName)
|
||||
{
|
||||
var outFile = getTempDir();
|
||||
outFile.append(fileName);
|
||||
outFile.createUnique(outFile.NORMAL_FILE_TYPE, 0600);
|
||||
|
||||
var stream = Cc["@mozilla.org/network/file-output-stream;1"]
|
||||
.createInstance(Ci.nsIFileOutputStream);
|
||||
stream.init(outFile, 0x02 | 0x08 | 0x20, 0600, 0);
|
||||
stream.write("foo", 3);
|
||||
stream.close();
|
||||
|
||||
do_check_eq(outFile.leafName.substr(0, fileName.length), fileName);
|
||||
|
||||
return outFile;
|
||||
}
|
||||
|
||||
function test_create(fileName)
|
||||
{
|
||||
var file1 = create_file(fileName);
|
||||
var file2 = create_file(fileName);
|
||||
file1.remove(false);
|
||||
file2.remove(false);
|
||||
}
|
||||
|
||||
function run_test()
|
||||
{
|
||||
for (var i = 0; i < nameArray.length; ++i) {
|
||||
test_create(nameArray[i]);
|
||||
}
|
||||
}
|
Загрузка…
Ссылка в новой задаче