3 #define COMPLAINED_READ (1 << 0)
\r
4 #define COMPLAINED_WRITE (1 << 1)
\r
5 #define COMPLAINED_ROTATE (1 << 2)
\r
7 static HANDLE create_logging_thread(logger_t *logger) {
\r
8 HANDLE thread_handle = CreateThread(NULL, 0, log_and_rotate, (void *) logger, 0, logger->tid_ptr);
\r
9 if (! thread_handle) log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_CREATETHREAD_FAILED, error_string(GetLastError()), 0);
\r
10 return thread_handle;
\r
13 static inline unsigned long guess_charsize(void *address, unsigned long bufsize) {
\r
14 if (IsTextUnicode(address, bufsize, 0)) return (unsigned long) sizeof(wchar_t);
\r
15 else return (unsigned long) sizeof(char);
\r
18 static inline void write_bom(logger_t *logger, unsigned long *out) {
\r
19 wchar_t bom = L'\ufeff';
\r
20 if (! WriteFile(logger->write_handle, (void *) &bom, sizeof(bom), out, 0)) {
\r
21 log_event(EVENTLOG_WARNING_TYPE, NSSM_EVENT_SOMEBODY_SET_UP_US_THE_BOM, logger->service_name, logger->path, error_string(GetLastError()), 0);
\r
25 /* Get path, share mode, creation disposition and flags for a stream. */
\r
26 int get_createfile_parameters(HKEY key, TCHAR *prefix, TCHAR *path, unsigned long *sharing, unsigned long default_sharing, unsigned long *disposition, unsigned long default_disposition, unsigned long *flags, unsigned long default_flags) {
\r
27 TCHAR value[NSSM_STDIO_LENGTH];
\r
30 if (_sntprintf_s(value, _countof(value), _TRUNCATE, _T("%s"), prefix) < 0) {
\r
31 log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_OUT_OF_MEMORY, prefix, _T("get_createfile_parameters()"), 0);
\r
34 switch (expand_parameter(key, value, path, MAX_PATH, true, false)) {
\r
35 case 0: if (! path[0]) return 0; break; /* OK. */
\r
36 default: return 2; /* Error. */
\r
40 if (_sntprintf_s(value, _countof(value), _TRUNCATE, _T("%s%s"), prefix, NSSM_REG_STDIO_SHARING) < 0) {
\r
41 log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_OUT_OF_MEMORY, NSSM_REG_STDIO_SHARING, _T("get_createfile_parameters()"), 0);
\r
44 switch (get_number(key, value, sharing, false)) {
\r
45 case 0: *sharing = default_sharing; break; /* Missing. */
\r
46 case 1: break; /* Found. */
\r
47 case -2: return 4; break; /* Error. */
\r
50 /* CreationDisposition. */
\r
51 if (_sntprintf_s(value, _countof(value), _TRUNCATE, _T("%s%s"), prefix, NSSM_REG_STDIO_DISPOSITION) < 0) {
\r
52 log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_OUT_OF_MEMORY, NSSM_REG_STDIO_DISPOSITION, _T("get_createfile_parameters()"), 0);
\r
55 switch (get_number(key, value, disposition, false)) {
\r
56 case 0: *disposition = default_disposition; break; /* Missing. */
\r
57 case 1: break; /* Found. */
\r
58 case -2: return 6; break; /* Error. */
\r
62 if (_sntprintf_s(value, _countof(value), _TRUNCATE, _T("%s%s"), prefix, NSSM_REG_STDIO_FLAGS) < 0) {
\r
63 log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_OUT_OF_MEMORY, NSSM_REG_STDIO_FLAGS, _T("get_createfile_parameters()"), 0);
\r
66 switch (get_number(key, value, flags, false)) {
\r
67 case 0: *flags = default_flags; break; /* Missing. */
\r
68 case 1: break; /* Found. */
\r
69 case -2: return 8; break; /* Error. */
\r
75 int set_createfile_parameter(HKEY key, TCHAR *prefix, TCHAR *suffix, unsigned long number) {
\r
76 TCHAR value[NSSM_STDIO_LENGTH];
\r
78 if (_sntprintf_s(value, _countof(value), _TRUNCATE, _T("%s%s"), prefix, suffix) < 0) {
\r
79 log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_OUT_OF_MEMORY, suffix, _T("set_createfile_parameter()"), 0);
\r
83 return set_number(key, value, number);
\r
86 int delete_createfile_parameter(HKEY key, TCHAR *prefix, TCHAR *suffix) {
\r
87 TCHAR value[NSSM_STDIO_LENGTH];
\r
89 if (_sntprintf_s(value, _countof(value), _TRUNCATE, _T("%s%s"), prefix, suffix) < 0) {
\r
90 log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_OUT_OF_MEMORY, suffix, _T("delete_createfile_parameter()"), 0);
\r
94 if (RegDeleteValue(key, value)) return 0;
\r
98 HANDLE append_to_file(TCHAR *path, unsigned long sharing, SECURITY_ATTRIBUTES *attributes, unsigned long disposition, unsigned long flags) {
\r
101 /* Try to append to the file first. */
\r
102 ret = CreateFile(path, FILE_APPEND_DATA, sharing, attributes, disposition, flags, 0);
\r
108 unsigned long error = GetLastError();
\r
109 if (error != ERROR_FILE_NOT_FOUND) {
\r
110 log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_CREATEFILE_FAILED, path, error_string(error), 0);
\r
114 /* It didn't exist. Create it. */
\r
115 return CreateFile(path, FILE_WRITE_DATA, sharing, attributes, disposition, flags, 0);
\r
118 static void rotated_filename(TCHAR *path, TCHAR *rotated, unsigned long rotated_len, SYSTEMTIME *st) {
\r
125 TCHAR buffer[MAX_PATH];
\r
126 memmove(buffer, path, sizeof(buffer));
\r
127 TCHAR *ext = PathFindExtension(buffer);
\r
128 TCHAR extension[MAX_PATH];
\r
129 _sntprintf_s(extension, _countof(extension), _TRUNCATE, _T("-%04u%02u%02uT%02u%02u%02u.%03u%s"), st->wYear, st->wMonth, st->wDay, st->wHour, st->wMinute, st->wSecond, st->wMilliseconds, ext);
\r
131 _sntprintf_s(rotated, rotated_len, _TRUNCATE, _T("%s%s"), buffer, extension);
\r
134 void rotate_file(TCHAR *service_name, TCHAR *path, unsigned long seconds, unsigned long low, unsigned long high) {
\r
135 unsigned long error;
\r
139 GetSystemTime(&st);
\r
141 BY_HANDLE_FILE_INFORMATION info;
\r
143 /* Try to open the file to check if it exists and to get attributes. */
\r
144 HANDLE file = CreateFile(path, 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
\r
146 /* Get file attributes. */
\r
147 if (! GetFileInformationByHandle(file, &info)) {
\r
148 /* Reuse current time for rotation timestamp. */
\r
149 seconds = low = high = 0;
\r
150 SystemTimeToFileTime(&st, &info.ftLastWriteTime);
\r
156 error = GetLastError();
\r
157 if (error == ERROR_FILE_NOT_FOUND) return;
\r
158 log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_ROTATE_FILE_FAILED, service_name, path, _T("CreateFile()"), path, error_string(error), 0);
\r
159 /* Reuse current time for rotation timestamp. */
\r
160 seconds = low = high = 0;
\r
161 SystemTimeToFileTime(&st, &info.ftLastWriteTime);
\r
164 /* Check file age. */
\r
167 SystemTimeToFileTime(&st, &ft);
\r
170 s.LowPart = ft.dwLowDateTime;
\r
171 s.HighPart = ft.dwHighDateTime;
\r
172 s.QuadPart -= seconds * 10000000LL;
\r
173 ft.dwLowDateTime = s.LowPart;
\r
174 ft.dwHighDateTime = s.HighPart;
\r
175 if (CompareFileTime(&info.ftLastWriteTime, &ft) > 0) return;
\r
178 /* Check file size. */
\r
180 if (info.nFileSizeHigh < high) return;
\r
181 if (info.nFileSizeHigh == high && info.nFileSizeLow < low) return;
\r
184 /* Get new filename. */
\r
185 FileTimeToSystemTime(&info.ftLastWriteTime, &st);
\r
187 TCHAR rotated[MAX_PATH];
\r
188 rotated_filename(path, rotated, _countof(rotated), &st);
\r
191 if (MoveFile(path, rotated)) {
\r
192 log_event(EVENTLOG_INFORMATION_TYPE, NSSM_EVENT_ROTATED, service_name, path, rotated, 0);
\r
195 error = GetLastError();
\r
197 if (error == ERROR_FILE_NOT_FOUND) return;
\r
198 log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_ROTATE_FILE_FAILED, service_name, path, _T("MoveFile()"), rotated, error_string(error), 0);
\r
202 int get_output_handles(nssm_service_t *service, HKEY key, STARTUPINFO *si) {
\r
203 bool set_flags = false;
\r
205 /* Standard security attributes allowing inheritance. */
\r
206 SECURITY_ATTRIBUTES attributes;
\r
207 ZeroMemory(&attributes, sizeof(attributes));
\r
208 attributes.bInheritHandle = true;
\r
211 if (get_createfile_parameters(key, NSSM_REG_STDIN, service->stdin_path, &service->stdin_sharing, NSSM_STDIN_SHARING, &service->stdin_disposition, NSSM_STDIN_DISPOSITION, &service->stdin_flags, NSSM_STDIN_FLAGS)) {
\r
212 service->stdin_sharing = service->stdin_disposition = service->stdin_flags = 0;
\r
213 ZeroMemory(service->stdin_path, _countof(service->stdin_path) * sizeof(TCHAR));
\r
216 if (si && service->stdin_path[0]) {
\r
217 si->hStdInput = CreateFile(service->stdin_path, FILE_READ_DATA, service->stdin_sharing, &attributes, service->stdin_disposition, service->stdin_flags, 0);
\r
218 if (! si->hStdInput) {
\r
219 log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_CREATEFILE_FAILED, service->stdin_path, error_string(GetLastError()), 0);
\r
225 ULARGE_INTEGER size;
\r
226 size.LowPart = service->rotate_bytes_low;
\r
227 size.HighPart = service->rotate_bytes_high;
\r
230 if (get_createfile_parameters(key, NSSM_REG_STDOUT, service->stdout_path, &service->stdout_sharing, NSSM_STDOUT_SHARING, &service->stdout_disposition, NSSM_STDOUT_DISPOSITION, &service->stdout_flags, NSSM_STDOUT_FLAGS)) {
\r
231 service->stdout_sharing = service->stdout_disposition = service->stdout_flags = 0;
\r
232 ZeroMemory(service->stdout_path, _countof(service->stdout_path) * sizeof(TCHAR));
\r
235 if (si && service->stdout_path[0]) {
\r
236 if (service->rotate_files) rotate_file(service->name, service->stdout_path, service->rotate_seconds, service->rotate_bytes_low, service->rotate_bytes_high);
\r
237 HANDLE stdout_handle = append_to_file(service->stdout_path, service->stdout_sharing, 0, service->stdout_disposition, service->stdout_flags);
\r
238 if (! stdout_handle) {
\r
239 log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_CREATEFILE_FAILED, service->stdout_path, error_string(GetLastError()), 0);
\r
243 /* Try online rotation only if a size threshold is set. */
\r
244 logger_t *stdout_logger = 0;
\r
245 if (service->rotate_files && service->rotate_stdout_online) {
\r
246 stdout_logger = (logger_t *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(logger_t));
\r
247 if (stdout_logger) {
\r
248 /* Pipe between application's stdout and our logging handle. */
\r
249 if (CreatePipe(&service->stdout_pipe, &si->hStdOutput, &attributes, 0)) {
\r
250 stdout_logger->service_name = service->name;
\r
251 stdout_logger->path = service->stdout_path;
\r
252 stdout_logger->sharing = service->stdout_sharing;
\r
253 stdout_logger->disposition = service->stdout_disposition;
\r
254 stdout_logger->flags = service->stdout_flags;
\r
255 stdout_logger->read_handle = service->stdout_pipe;
\r
256 stdout_logger->write_handle = stdout_handle;
\r
257 stdout_logger->size = (__int64) size.QuadPart;
\r
258 stdout_logger->tid_ptr = &service->stdout_tid;
\r
259 stdout_logger->rotate_online = &service->rotate_stdout_online;
\r
261 /* Logging thread. */
\r
262 service->stdout_thread = create_logging_thread(stdout_logger);
\r
263 if (! service->stdout_thread) {
\r
264 log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_CREATEPIPE_FAILED, service->name, service->stdout_path, error_string(GetLastError()));
\r
265 CloseHandle(service->stdout_pipe);
\r
266 CloseHandle(si->hStdOutput);
\r
267 service->stdout_tid = 0;
\r
270 else service->stdout_tid = 0;
\r
273 log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_OUT_OF_MEMORY, _T("stdout_logger"), _T("get_output_handles()"), 0);
\r
274 service->stdout_tid = 0;
\r
277 /* Fall through to try direct I/O. */
\r
278 if (! service->stdout_tid) log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_CREATEPIPE_FAILED, service->name, service->stdout_path, error_string(GetLastError()));
\r
281 if (! service->stdout_tid) {
\r
282 if (stdout_logger) HeapFree(GetProcessHeap(), 0, stdout_logger);
\r
283 if (! DuplicateHandle(GetCurrentProcess(), stdout_handle, GetCurrentProcess(), &si->hStdOutput, 0, true, DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) {
\r
284 log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_DUPLICATEHANDLE_FAILED, NSSM_REG_STDOUT, error_string(GetLastError()), 0);
\r
287 service->rotate_stdout_online = NSSM_ROTATE_OFFLINE;
\r
294 if (get_createfile_parameters(key, NSSM_REG_STDERR, service->stderr_path, &service->stderr_sharing, NSSM_STDERR_SHARING, &service->stderr_disposition, NSSM_STDERR_DISPOSITION, &service->stderr_flags, NSSM_STDERR_FLAGS)) {
\r
295 service->stderr_sharing = service->stderr_disposition = service->stderr_flags = 0;
\r
296 ZeroMemory(service->stderr_path, _countof(service->stderr_path) * sizeof(TCHAR));
\r
299 if (service->stderr_path[0]) {
\r
300 /* Same as stdout? */
\r
301 if (str_equiv(service->stderr_path, service->stdout_path)) {
\r
302 service->stderr_sharing = service->stdout_sharing;
\r
303 service->stderr_disposition = service->stdout_disposition;
\r
304 service->stderr_flags = service->stdout_flags;
\r
305 service->rotate_stderr_online = false;
\r
308 /* Two handles to the same file will create a race. */
\r
309 if (! DuplicateHandle(GetCurrentProcess(), si->hStdOutput, GetCurrentProcess(), &si->hStdError, 0, true, DUPLICATE_SAME_ACCESS)) {
\r
310 log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_DUPLICATEHANDLE_FAILED, NSSM_REG_STDOUT, error_string(GetLastError()), 0);
\r
316 if (service->rotate_files) rotate_file(service->name, service->stderr_path, service->rotate_seconds, service->rotate_bytes_low, service->rotate_bytes_high);
\r
317 HANDLE stderr_handle = append_to_file(service->stderr_path, service->stderr_sharing, 0, service->stderr_disposition, service->stderr_flags);
\r
318 if (! stderr_handle) {
\r
319 log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_CREATEFILE_FAILED, service->stderr_path, error_string(GetLastError()), 0);
\r
323 /* Try online rotation only if a size threshold is set. */
\r
324 logger_t *stderr_logger = 0;
\r
325 if (service->rotate_files && service->rotate_stderr_online) {
\r
326 stderr_logger = (logger_t *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(logger_t));
\r
327 if (stderr_logger) {
\r
328 /* Pipe between application's stderr and our logging handle. */
\r
329 if (CreatePipe(&service->stderr_pipe, &si->hStdError, &attributes, 0)) {
\r
330 stderr_logger->service_name = service->name;
\r
331 stderr_logger->path = service->stderr_path;
\r
332 stderr_logger->sharing = service->stderr_sharing;
\r
333 stderr_logger->disposition = service->stderr_disposition;
\r
334 stderr_logger->flags = service->stderr_flags;
\r
335 stderr_logger->read_handle = service->stderr_pipe;
\r
336 stderr_logger->write_handle = stderr_handle;
\r
337 stderr_logger->size = (__int64) size.QuadPart;
\r
338 stderr_logger->tid_ptr = &service->stderr_tid;
\r
339 stderr_logger->rotate_online = &service->rotate_stderr_online;
\r
341 /* Logging thread. */
\r
342 service->stderr_thread = create_logging_thread(stderr_logger);
\r
343 if (! service->stderr_thread) {
\r
344 log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_CREATEPIPE_FAILED, service->name, service->stderr_path, error_string(GetLastError()));
\r
345 CloseHandle(service->stderr_pipe);
\r
346 CloseHandle(si->hStdError);
\r
347 service->stderr_tid = 0;
\r
350 else service->stderr_tid = 0;
\r
353 log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_OUT_OF_MEMORY, _T("stderr_logger"), _T("get_output_handles()"), 0);
\r
354 service->stderr_tid = 0;
\r
357 /* Fall through to try direct I/O. */
\r
358 if (! service->stderr_tid) log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_CREATEPIPE_FAILED, service->name, service->stderr_path, error_string(GetLastError()));
\r
361 if (! service->stderr_tid) {
\r
362 if (stderr_logger) HeapFree(GetProcessHeap(), 0, stderr_logger);
\r
363 if (! DuplicateHandle(GetCurrentProcess(), stderr_handle, GetCurrentProcess(), &si->hStdError, 0, true, DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) {
\r
364 log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_DUPLICATEHANDLE_FAILED, NSSM_REG_STDERR, error_string(GetLastError()), 0);
\r
367 service->rotate_stderr_online = NSSM_ROTATE_OFFLINE;
\r
374 if (! set_flags) return 0;
\r
377 We need to set the startup_info flags to make the new handles
\r
378 inheritable by the new process.
\r
380 if (si) si->dwFlags |= STARTF_USESTDHANDLES;
\r
385 void close_output_handles(STARTUPINFO *si, bool close_stdout, bool close_stderr) {
\r
386 if (si->hStdInput) CloseHandle(si->hStdInput);
\r
387 if (si->hStdOutput && close_stdout) CloseHandle(si->hStdOutput);
\r
388 if (si->hStdError && close_stderr) CloseHandle(si->hStdError);
\r
391 void close_output_handles(STARTUPINFO *si) {
\r
392 return close_output_handles(si, true, true);
\r
396 Try multiple times to read from a file.
\r
397 Returns: 0 on success.
\r
398 1 on non-fatal error.
\r
401 static int try_read(logger_t *logger, void *address, unsigned long bufsize, unsigned long *in, int *complained) {
\r
403 unsigned long error;
\r
404 for (int tries = 0; tries < 5; tries++) {
\r
405 if (ReadFile(logger->read_handle, address, bufsize, in, 0)) return 0;
\r
407 error = GetLastError();
\r
409 /* Other end closed the pipe. */
\r
410 case ERROR_BROKEN_PIPE:
\r
412 goto complain_read;
\r
414 /* Couldn't lock the buffer. */
\r
415 case ERROR_NOT_ENOUGH_QUOTA:
\r
416 Sleep(2000 + tries * 3000);
\r
420 /* Write was cancelled by the other end. */
\r
421 case ERROR_OPERATION_ABORTED:
\r
423 goto complain_read;
\r
431 if (! (*complained & COMPLAINED_READ)) log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_READFILE_FAILED, logger->service_name, logger->path, error_string(error), 0);
\r
432 *complained |= COMPLAINED_READ;
\r
437 Try multiple times to write to a file.
\r
438 Returns: 0 on success.
\r
439 1 on non-fatal error.
\r
442 static int try_write(logger_t *logger, void *address, unsigned long bufsize, unsigned long *out, int *complained) {
\r
444 unsigned long error;
\r
445 for (int tries = 0; tries < 5; tries++) {
\r
446 if (WriteFile(logger->write_handle, address, bufsize, out, 0)) return 0;
\r
448 error = GetLastError();
\r
449 if (error == ERROR_IO_PENDING) {
\r
450 /* Operation was successful pending flush to disk. */
\r
455 /* Other end closed the pipe. */
\r
456 case ERROR_BROKEN_PIPE:
\r
458 goto complain_write;
\r
460 /* Couldn't lock the buffer. */
\r
461 case ERROR_NOT_ENOUGH_QUOTA:
\r
462 /* Out of disk space. */
\r
463 case ERROR_DISK_FULL:
\r
464 Sleep(2000 + tries * 3000);
\r
469 /* We'll lose this line but try to read and write subsequent ones. */
\r
475 if (! (*complained & COMPLAINED_WRITE)) log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_WRITEFILE_FAILED, logger->service_name, logger->path, error_string(error), 0);
\r
476 *complained |= COMPLAINED_WRITE;
\r
480 /* Wrapper to be called in a new thread for logging. */
\r
481 unsigned long WINAPI log_and_rotate(void *arg) {
\r
482 logger_t *logger = (logger_t *) arg;
\r
483 if (! logger) return 1;
\r
486 BY_HANDLE_FILE_INFORMATION info;
\r
488 /* Find initial file size. */
\r
489 if (! GetFileInformationByHandle(logger->write_handle, &info)) logger->size = 0LL;
\r
492 l.HighPart = info.nFileSizeHigh;
\r
493 l.LowPart = info.nFileSizeLow;
\r
499 unsigned long in, out;
\r
500 unsigned long charsize = 0;
\r
501 unsigned long error;
\r
503 int complained = 0;
\r
506 /* Read data from the pipe. */
\r
508 ret = try_read(logger, address, sizeof(buffer), &in, &complained);
\r
510 HeapFree(GetProcessHeap(), 0, logger);
\r
513 else if (ret) continue;
\r
515 if (*logger->rotate_online == NSSM_ROTATE_ONLINE_ASAP || (logger->size && size + (__int64) in >= logger->size)) {
\r
516 /* Look for newline. */
\r
518 for (i = 0; i < in; i++) {
\r
519 if (buffer[i] == '\n') {
\r
520 if (! charsize) charsize = guess_charsize(address, in);
\r
523 /* Write up to the newline. */
\r
524 ret = try_write(logger, address, i, &out, &complained);
\r
526 HeapFree(GetProcessHeap(), 0, logger);
\r
529 size += (__int64) out;
\r
532 *logger->rotate_online = NSSM_ROTATE_ONLINE;
\r
533 TCHAR rotated[MAX_PATH];
\r
534 rotated_filename(logger->path, rotated, _countof(rotated), 0);
\r
537 Ideally we'd try the rename first then close the handle but
\r
538 MoveFile() will fail if the handle is still open so we must
\r
539 risk losing everything.
\r
541 CloseHandle(logger->write_handle);
\r
542 if (MoveFile(logger->path, rotated)) {
\r
543 log_event(EVENTLOG_INFORMATION_TYPE, NSSM_EVENT_ROTATED, logger->service_name, logger->path, rotated, 0);
\r
547 error = GetLastError();
\r
548 if (error != ERROR_FILE_NOT_FOUND) {
\r
549 if (! (complained & COMPLAINED_ROTATE)) log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_ROTATE_FILE_FAILED, logger->service_name, logger->path, _T("MoveFile()"), rotated, error_string(error), 0);
\r
550 complained |= COMPLAINED_ROTATE;
\r
551 /* We can at least try to re-open the existing file. */
\r
552 logger->disposition = OPEN_ALWAYS;
\r
557 logger->write_handle = append_to_file(logger->path, logger->sharing, 0, logger->disposition, logger->flags);
\r
558 if (! logger->write_handle) {
\r
559 error = GetLastError();
\r
560 log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_CREATEFILE_FAILED, logger->path, error_string(error), 0);
\r
561 /* Oh dear. Now we can't log anything further. */
\r
562 HeapFree(GetProcessHeap(), 0, logger);
\r
566 /* Resume writing after the newline. */
\r
567 address = (void *) ((char *) address + i);
\r
574 /* Write a BOM to the new file. */
\r
575 if (! charsize) charsize = guess_charsize(address, in);
\r
576 if (charsize == sizeof(wchar_t)) write_bom(logger, &out);
\r
577 size += (__int64) out;
\r
580 /* Write the data, if any. */
\r
581 if (! in) continue;
\r
583 ret = try_write(logger, address, in, &out, &complained);
\r
584 size += (__int64) out;
\r
586 HeapFree(GetProcessHeap(), 0, logger);
\r
591 HeapFree(GetProcessHeap(), 0, logger);
\r