Skip to content

Replace _fsopen on Windows to allow the opened file to be used by logrotate (supporting move and delete operations) #251

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 83 additions & 1 deletion loguru.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,83 @@ namespace loguru
typedef FILE* FileAbs;
#endif


#if defined(_WIN32) && LOGURU_WITH_FILEABS
#include <stdio.h>
#include <fcntl.h>
#include <io.h>
#define NOMINMAX
#include <windows.h>

/**
* Opens the file whose name is the string pointed to by file and associates
* a stream with it.
* Credit to Xavier Roche http://blog.httrack.com/blog/2013/10/05/creating-deletable-and-movable-files-on-windows
**/
FILE* fopen_unixlike(const char* file, const char* mode) {
DWORD dwDesiredAccess = 0;
DWORD dwCreationDisposition = 0;
const DWORD dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL;
const DWORD dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
size_t i = 0;

HANDLE handle = NULL;
int fd = 0;

#if defined(_WIN32) && !defined(__CYGWIN__)
if (strcmp(file, "/dev/null") == 0)
file = "NUL";
#endif

/* Infer flags. */
for (i = 0; mode[i] != '\0'; i++) {
switch (mode[i]) {
case 'r':
dwDesiredAccess |= GENERIC_READ;
dwCreationDisposition = OPEN_EXISTING;
break;
case 'a':
dwDesiredAccess |= FILE_APPEND_DATA;
dwCreationDisposition = OPEN_ALWAYS;
break;
case 'w':
dwDesiredAccess |= GENERIC_WRITE;
dwCreationDisposition = CREATE_ALWAYS;
break;
case '+':
dwDesiredAccess |= GENERIC_READ;
dwDesiredAccess |= GENERIC_WRITE;
break;
}
}

/* Create the file. */
handle = CreateFileA(file,
dwDesiredAccess,
dwShareMode,
NULL,
dwCreationDisposition,
dwFlagsAndAttributes,
NULL);
if (handle == INVALID_HANDLE_VALUE) {
return NULL;
}

/* Associates a C run-time file descriptor with a file HANDLE. */
fd = _open_osfhandle((intptr_t)handle, _O_BINARY);
if (fd == -1) {
CloseHandle(handle);
return NULL;
}

/* Associates a stream with a C run-time file descriptor. */
return _fdopen(fd, mode);
}

#define _fsopen(file, mode, ...) fopen_unixlike(file, mode) // replace _fsopen
// for files created by it is not movable and deletable
#endif

struct Callback
{
std::string id;
Expand Down Expand Up @@ -358,7 +435,11 @@ namespace loguru
if (!create_directories(file_abs->path)) {
LOG_F(ERROR, "Failed to create directories to '" LOGURU_FMT(s) "'", file_abs->path);
}
file_abs->fp = fopen(file_abs->path, file_abs->mode_str);
#ifdef _WIN32
file_abs->fp = _fsopen(file_abs->path, file_abs->mode_str, _SH_DENYNO);
#else
file_abs->fp = fopen(file_abs->path, file_abs->mode_str);
#endif
if (!file_abs->fp) {
LOG_F(ERROR, "Failed to open '" LOGURU_FMT(s) "'", file_abs->path);
} else {
Expand Down Expand Up @@ -537,6 +618,7 @@ namespace loguru
{
VLOG_F(g_internal_verbosity, "atexit");
flush();
remove_all_callbacks();
}

static void install_signal_handlers(const SignalOptions& signal_options);
Expand Down