Skip to content

Commit 886ca22

Browse files
authored
Merge pull request #858 from readdle/win-multibyte-paths-6.1
🍒[6.1] Handle multibyte path strings on Windows
2 parents 0d67182 + 48b4a64 commit 886ca22

File tree

2 files changed

+48
-12
lines changed

2 files changed

+48
-12
lines changed

src/io.c

+41-11
Original file line numberDiff line numberDiff line change
@@ -407,9 +407,13 @@ dispatch_io_create_f(dispatch_io_type_t type, dispatch_fd_t fd,
407407
}
408408

409409
#if defined(_WIN32)
410-
#define _is_separator(ch) ((ch) == '/' || (ch) == '\\')
410+
#define _is_separator(ch) ((ch) == L'/' || (ch) == L'\\')
411+
#define _dispatch_stat _wstati64
412+
typedef struct _stati64 _dispatch_stat_t;
411413
#else
412414
#define _is_separator(ch) ((ch) == '/')
415+
#define _dispatch_stat stat
416+
typedef struct stat _dispatch_stat_t;
413417
#endif
414418

415419
dispatch_io_t
@@ -424,33 +428,51 @@ dispatch_io_create_with_path(dispatch_io_type_t type, const char *path,
424428
if (PathIsRelativeA(path)) {
425429
return DISPATCH_BAD_INPUT;
426430
}
431+
int cchLength = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, path, -1, NULL, 0);
432+
if (!cchLength) {
433+
dispatch_assert(GetLastError() == ERROR_NO_UNICODE_TRANSLATION);
434+
return DISPATCH_BAD_INPUT;
435+
}
436+
dispatch_io_path_data_t path_data = malloc(sizeof(*path_data) + sizeof(WCHAR) * cchLength);
437+
if (!path_data) {
438+
return DISPATCH_OUT_OF_MEMORY;
439+
}
440+
path_data->pathlen = cchLength - 1; // Don't include terminating null character
441+
cchLength = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, path, -1, path_data->path, cchLength);
442+
if (!cchLength) {
443+
free(path_data);
444+
// We already checked the input when measuring buffer length.
445+
// Any error at this point seems fatal.
446+
DISPATCH_INTERNAL_CRASH(GetLastError(), "MultiByteToWideChar");
447+
return DISPATCH_BAD_INPUT;
448+
}
427449
#else
428450
if (!_is_separator(*path)) {
429451
return DISPATCH_BAD_INPUT;
430452
}
431-
#endif
432453
size_t pathlen = strlen(path);
433454
dispatch_io_path_data_t path_data = malloc(sizeof(*path_data) + pathlen+1);
434455
if (!path_data) {
435456
return DISPATCH_OUT_OF_MEMORY;
436457
}
458+
path_data->pathlen = pathlen;
459+
memcpy(path_data->path, path, pathlen + 1);
460+
#endif
437461
dispatch_io_t channel = _dispatch_io_create(type);
438462
channel->fd = -1;
439463
_dispatch_channel_debug("create with path %s", channel, path);
440464
channel->fd_actual = -1;
441465
path_data->channel = channel;
442466
path_data->oflag = oflag;
443467
path_data->mode = mode;
444-
path_data->pathlen = pathlen;
445-
memcpy(path_data->path, path, pathlen + 1);
446468
_dispatch_retain(queue);
447469
_dispatch_retain(channel);
448470
dispatch_async(channel->queue, ^{
449471
int err = 0;
450-
struct stat st;
472+
_dispatch_stat_t st;
451473
_dispatch_io_syscall_switch_noerr(err,
452474
#if defined(_WIN32)
453-
stat(path_data->path, &st),
475+
_dispatch_stat(path_data->path, &st),
454476
#else
455477
(path_data->oflag & O_NOFOLLOW) == O_NOFOLLOW
456478
#if __APPLE__
@@ -465,7 +487,7 @@ dispatch_io_create_with_path(dispatch_io_type_t type, const char *path,
465487
if ((path_data->oflag & O_CREAT) &&
466488
!_is_separator(*(path_data->path + path_data->pathlen - 1))) {
467489
// Check parent directory
468-
char *c = NULL;
490+
dispatch_io_path_char_t *c = NULL;
469491
for (ssize_t i = (ssize_t)path_data->pathlen - 1; i >= 0; i--) {
470492
if (_is_separator(path_data->path[i])) {
471493
c = &path_data->path[i];
@@ -476,7 +498,7 @@ dispatch_io_create_with_path(dispatch_io_type_t type, const char *path,
476498
*c = 0;
477499
int perr;
478500
_dispatch_io_syscall_switch_noerr(perr,
479-
stat(path_data->path, &st),
501+
_dispatch_stat(path_data->path, &st),
480502
case 0:
481503
// Since the parent directory exists, open() will
482504
// create a regular file after the fd_entry has
@@ -486,7 +508,7 @@ dispatch_io_create_with_path(dispatch_io_type_t type, const char *path,
486508
break;
487509
);
488510
#if defined(_WIN32)
489-
*c = '\\';
511+
*c = L'\\';
490512
#else
491513
*c = '/';
492514
#endif
@@ -602,7 +624,11 @@ dispatch_io_create_with_io(dispatch_io_type_t type, dispatch_io_t in_channel,
602624
mode_t mode = in_channel->fd_entry->stat.mode;
603625
dev_t dev = in_channel->fd_entry->stat.dev;
604626
size_t path_data_len = sizeof(struct dispatch_io_path_data_s) +
627+
#if defined(_WIN32)
628+
sizeof(WCHAR) * (in_channel->fd_entry->path_data->pathlen + 1);
629+
#else
605630
in_channel->fd_entry->path_data->pathlen + 1;
631+
#endif
606632
dispatch_io_path_data_t path_data = malloc(path_data_len);
607633
memcpy(path_data, in_channel->fd_entry->path_data,
608634
path_data_len);
@@ -1292,7 +1318,7 @@ _dispatch_fd_entry_unguard(dispatch_fd_entry_t fd_entry) { (void)fd_entry; }
12921318
#endif // DISPATCH_USE_GUARDED_FD
12931319

12941320
static inline dispatch_fd_t
1295-
_dispatch_fd_entry_guarded_open(dispatch_fd_entry_t fd_entry, const char *path,
1321+
_dispatch_fd_entry_guarded_open(dispatch_fd_entry_t fd_entry, const dispatch_io_path_char_t *path,
12961322
int oflag, mode_t mode) {
12971323
#if DISPATCH_USE_GUARDED_FD
12981324
guardid_t guard = (uintptr_t)fd_entry;
@@ -1333,7 +1359,7 @@ _dispatch_fd_entry_guarded_open(dispatch_fd_entry_t fd_entry, const char *path,
13331359
} else if (oflag & _O_TRUNC) {
13341360
dwCreationDisposition = TRUNCATE_EXISTING;
13351361
}
1336-
return (dispatch_fd_t)CreateFile(path, dwDesiredAccess,
1362+
return (dispatch_fd_t)CreateFileW(path, dwDesiredAccess,
13371363
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL,
13381364
dwCreationDisposition, 0, NULL);
13391365
#else
@@ -1597,7 +1623,11 @@ _dispatch_fd_entry_create_with_path(dispatch_io_path_data_t path_data,
15971623
// On devs lock queue
15981624
dispatch_fd_entry_t fd_entry = _dispatch_fd_entry_create(
15991625
path_data->channel->queue);
1626+
#if defined(_WIN32)
1627+
_dispatch_fd_entry_debug("create: path %S", fd_entry, path_data->path);
1628+
#else
16001629
_dispatch_fd_entry_debug("create: path %s", fd_entry, path_data->path);
1630+
#endif
16011631
if (S_ISREG(mode)) {
16021632
#if defined(_WIN32)
16031633
_dispatch_disk_init(fd_entry, 0);

src/io_internal.h

+7-1
Original file line numberDiff line numberDiff line change
@@ -79,12 +79,18 @@ struct dispatch_stream_s {
7979

8080
typedef struct dispatch_stream_s *dispatch_stream_t;
8181

82+
#if defined(_WIN32)
83+
typedef WCHAR dispatch_io_path_char_t;
84+
#else
85+
typedef char dispatch_io_path_char_t;
86+
#endif
87+
8288
struct dispatch_io_path_data_s {
8389
dispatch_io_t channel;
8490
int oflag;
8591
mode_t mode;
8692
size_t pathlen;
87-
char path[];
93+
dispatch_io_path_char_t path[];
8894
};
8995

9096
typedef struct dispatch_io_path_data_s *dispatch_io_path_data_t;

0 commit comments

Comments
 (0)