Skip to content

Commit 18735d8

Browse files
zandersocommit-bot@chromium.org
authored andcommitted
[dart:io, windwos] Try a shorter temp directory name first
Windows paths are limited to 260 characters including the null terminator in most cases. This makes characters in paths a precious commodity. Currently creating a temporary directory in Dart will append a UUID to the user-provided prefix. UUIDs consume 36 characters of a path. If a temporary directory is created inside of another temporary directory, this adds up to 72 characters or about 28% of the available real estate. This change first attempts to use a shorter suffix generated from a random uint32_t using Crypto::GetRandomBytes. If that fails, then it falls back on using the UUID. Change-Id: I15a413746316028b39b6ff915b1b2b19cbf62a5e Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/147341 Commit-Queue: Zach Anderson <[email protected]> Reviewed-by: Zichang Guo <[email protected]> Reviewed-by: Siva Annamalai <[email protected]>
1 parent fcf56ea commit 18735d8

File tree

1 file changed

+55
-6
lines changed

1 file changed

+55
-6
lines changed

runtime/bin/directory_win.cc

Lines changed: 55 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,13 @@
1111
#include <sys/stat.h> // NOLINT
1212

1313
#include "bin/dartutils.h"
14+
#include "bin/crypto.h"
1415
#include "bin/file.h"
1516
#include "bin/namespace.h"
1617
#include "bin/utils.h"
1718
#include "bin/utils_win.h"
1819
#include "platform/syslog.h"
20+
#include "platform/utils.h"
1921

2022
#undef DeleteFile
2123

@@ -384,12 +386,8 @@ const char* Directory::SystemTemp(Namespace* namespc) {
384386
return path.AsScopedString();
385387
}
386388

387-
const char* Directory::CreateTemp(Namespace* namespc, const char* prefix) {
388-
// Returns a new, unused directory name, adding characters to the
389-
// end of prefix.
390-
// Creates this directory, with a default security
391-
// descriptor inherited from its parent directory.
392-
// The return value is Dart_ScopeAllocated.
389+
// Creates a new temporary directory with a UUID as suffix.
390+
static const char* CreateTempFromUUID(const char* prefix) {
393391
PathBuffer path;
394392
Utf8ToWideScope system_prefix(prefix);
395393
if (!path.AddW(system_prefix.wide())) {
@@ -423,6 +421,57 @@ const char* Directory::CreateTemp(Namespace* namespc, const char* prefix) {
423421
return path.AsScopedString();
424422
}
425423

424+
// Creates a new, unused directory, adding characters to the end of prefix, and
425+
// returns the directory's name.
426+
//
427+
// Creates this directory, with a default security descriptor inherited from its
428+
// parent directory. The return value is Dart_ScopeAllocated.
429+
//
430+
// First, attempts appending a suffix created from a random uint32_t. If that
431+
// name is already taken, falls back on using a UUID for the suffix.
432+
//
433+
// Note: More attempts at finding an available short suffix would more reliably
434+
// avoid a uuid suffix. We choose one attempt here because it is simpler, and
435+
// to have a small bound on the number of calls to CreateDirectoryW().
436+
const char* Directory::CreateTemp(Namespace* namespc, const char* prefix) {
437+
PathBuffer path;
438+
Utf8ToWideScope system_prefix(prefix);
439+
if (!path.AddW(system_prefix.wide())) {
440+
return NULL;
441+
}
442+
443+
// Adding 8 hex digits.
444+
if (path.length() > MAX_LONG_PATH - 8) {
445+
// No fallback, there won't be enough room for the UUID, either.
446+
return NULL;
447+
}
448+
449+
// First try a short suffix using the rng, then if that fails fall back on
450+
// a uuid.
451+
uint32_t suffix_bytes = 0;
452+
const int kSuffixSize = sizeof(suffix_bytes);
453+
if (!Crypto::GetRandomBytes(
454+
kSuffixSize, reinterpret_cast<uint8_t*>(&suffix_bytes))) {
455+
// Getting random bytes failed, maybe the UUID will work?
456+
return CreateTempFromUUID(prefix);
457+
}
458+
459+
// Two digits per byte plus null.
460+
char suffix[kSuffixSize * 2 + 1];
461+
Utils::SNPrint(suffix, sizeof(suffix), "%x", suffix_bytes);
462+
if (!path.Add(suffix)) {
463+
// Adding to the path failed, maybe because of low-memory. Don't fall back.
464+
return NULL;
465+
}
466+
467+
if (!CreateDirectoryW(path.AsStringW(), NULL)) {
468+
// Creation failed, possibly because an entry with the name already exists.
469+
// Fall back to using the UUID suffix.
470+
return CreateTempFromUUID(prefix);
471+
}
472+
return path.AsScopedString();
473+
}
474+
426475
bool Directory::Delete(Namespace* namespc,
427476
const char* dir_name,
428477
bool recursive) {

0 commit comments

Comments
 (0)