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:
smontagu@smontagu.org 2008-01-09 13:10:06 -08:00
Родитель 2087d1b0f5
Коммит 566e54aeaa
2 изменённых файлов: 122 добавлений и 18 удалений

Просмотреть файл

@ -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]);
}
}