Skip to content

Commit 318f6e5

Browse files
Merge pull request #494 from adierking/iopath
io: fix dispatch_io_create_with_path() on Windows
2 parents 4169c8d + ca80621 commit 318f6e5

File tree

3 files changed

+53
-14
lines changed

3 files changed

+53
-14
lines changed

src/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,7 @@ target_link_libraries(dispatch
245245
if(CMAKE_SYSTEM_NAME STREQUAL Windows)
246246
target_link_libraries(dispatch
247247
PRIVATE
248+
ShLwApi
248249
WS2_32
249250
WinMM
250251
synchronization)

src/io.c

Lines changed: 51 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -406,15 +406,29 @@ dispatch_io_create_f(dispatch_io_type_t type, dispatch_fd_t fd,
406406
^(int error){ cleanup_handler(context, error); });
407407
}
408408

409+
#if defined(_WIN32)
410+
#define _is_separator(ch) ((ch) == '/' || (ch) == '\\')
411+
#else
412+
#define _is_separator(ch) ((ch) == '/')
413+
#endif
414+
409415
dispatch_io_t
410416
dispatch_io_create_with_path(dispatch_io_type_t type, const char *path,
411417
int oflag, mode_t mode, dispatch_queue_t queue,
412418
void (^cleanup_handler)(int error))
413419
{
414-
if ((type != DISPATCH_IO_STREAM && type != DISPATCH_IO_RANDOM) ||
415-
!(*path == '/')) {
420+
if (type != DISPATCH_IO_STREAM && type != DISPATCH_IO_RANDOM) {
421+
return DISPATCH_BAD_INPUT;
422+
}
423+
#if defined(_WIN32)
424+
if (PathIsRelativeA(path)) {
425+
return DISPATCH_BAD_INPUT;
426+
}
427+
#else
428+
if (!_is_separator(*path)) {
416429
return DISPATCH_BAD_INPUT;
417430
}
431+
#endif
418432
size_t pathlen = strlen(path);
419433
dispatch_io_path_data_t path_data = malloc(sizeof(*path_data) + pathlen+1);
420434
if (!path_data) {
@@ -449,9 +463,15 @@ dispatch_io_create_with_path(dispatch_io_type_t type, const char *path,
449463
break;
450464
default:
451465
if ((path_data->oflag & O_CREAT) &&
452-
(*(path_data->path + path_data->pathlen - 1) != '/')) {
466+
!_is_separator(*(path_data->path + path_data->pathlen - 1))) {
453467
// Check parent directory
454-
char *c = strrchr(path_data->path, '/');
468+
char *c = NULL;
469+
for (ssize_t i = (ssize_t)path_data->pathlen - 1; i >= 0; i--) {
470+
if (_is_separator(path_data->path[i])) {
471+
c = &path_data->path[i];
472+
break;
473+
}
474+
}
455475
dispatch_assert(c);
456476
*c = 0;
457477
int perr;
@@ -465,7 +485,11 @@ dispatch_io_create_with_path(dispatch_io_type_t type, const char *path,
465485
err = 0;
466486
break;
467487
);
488+
#if defined(_WIN32)
489+
*c = '\\';
490+
#else
468491
*c = '/';
492+
#endif
469493
}
470494
break;
471495
);
@@ -1287,18 +1311,31 @@ _dispatch_fd_entry_guarded_open(dispatch_fd_entry_t fd_entry, const char *path,
12871311
#if defined(_WIN32)
12881312
(void)mode;
12891313
DWORD dwDesiredAccess = 0;
1290-
if (oflag & _O_RDWR)
1291-
dwDesiredAccess = GENERIC_READ | GENERIC_WRITE;
1292-
else if (oflag & _O_RDONLY)
1293-
dwDesiredAccess = GENERIC_READ;
1294-
else if (oflag & _O_WRONLY)
1295-
dwDesiredAccess = GENERIC_WRITE;
1314+
switch (oflag & (_O_RDONLY | _O_WRONLY | _O_RDWR)) {
1315+
case _O_RDONLY:
1316+
dwDesiredAccess = GENERIC_READ;
1317+
break;
1318+
case _O_WRONLY:
1319+
dwDesiredAccess = GENERIC_WRITE;
1320+
break;
1321+
case _O_RDWR:
1322+
dwDesiredAccess = GENERIC_READ | GENERIC_WRITE;
1323+
break;
1324+
}
12961325
DWORD dwCreationDisposition = OPEN_EXISTING;
1297-
if (oflag & _O_CREAT)
1326+
if (oflag & _O_CREAT) {
12981327
dwCreationDisposition = OPEN_ALWAYS;
1299-
if (oflag & _O_TRUNC)
1300-
dwCreationDisposition = CREATE_ALWAYS;
1301-
return (dispatch_fd_t)CreateFile(path, dwDesiredAccess, 0, NULL, dwCreationDisposition, 0, NULL);
1328+
if (oflag & _O_EXCL) {
1329+
dwCreationDisposition = CREATE_NEW;
1330+
} else if (oflag & _O_TRUNC) {
1331+
dwCreationDisposition = CREATE_ALWAYS;
1332+
}
1333+
} else if (oflag & _O_TRUNC) {
1334+
dwCreationDisposition = TRUNCATE_EXISTING;
1335+
}
1336+
return (dispatch_fd_t)CreateFile(path, dwDesiredAccess,
1337+
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL,
1338+
dwCreationDisposition, 0, NULL);
13021339
#else
13031340
return open(path, oflag, mode);
13041341
#endif

src/shims/generic_win_stubs.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
#include <Windows.h>
88
#include <crtdbg.h>
9+
#include <Shlwapi.h>
910

1011
#include <io.h>
1112
#include <process.h>

0 commit comments

Comments
 (0)