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(TCHAR *service_name, TCHAR *path, unsigned long sharing, unsigned long disposition, unsigned long flags, HANDLE *read_handle_ptr, HANDLE *pipe_handle_ptr, HANDLE *write_handle_ptr, unsigned long rotate_bytes_low, unsigned long rotate_bytes_high, unsigned long *tid_ptr, unsigned long *rotate_online) {
\r
10 /* Pipe between application's stdout/stderr and our logging handle. */
\r
11 if (read_handle_ptr && ! *read_handle_ptr) {
\r
12 if (pipe_handle_ptr && ! *pipe_handle_ptr) {
\r
13 if (CreatePipe(read_handle_ptr, pipe_handle_ptr, 0, 0)) {
\r
14 SetHandleInformation(*pipe_handle_ptr, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT);
\r
17 log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_CREATEPIPE_FAILED, service_name, path, error_string(GetLastError()));
\r
23 logger_t *logger = (logger_t *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(logger_t));
\r
25 log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_OUT_OF_MEMORY, _T("logger"), _T("create_logging_thread()"), 0);
\r
29 ULARGE_INTEGER size;
\r
30 size.LowPart = rotate_bytes_low;
\r
31 size.HighPart = rotate_bytes_high;
\r
33 logger->service_name = service_name;
\r
34 logger->path = path;
\r
35 logger->sharing = sharing;
\r
36 logger->disposition = disposition;
\r
37 logger->flags = flags;
\r
38 logger->read_handle = *read_handle_ptr;
\r
39 logger->write_handle = *write_handle_ptr;
\r
40 logger->size = (__int64) size.QuadPart;
\r
41 logger->tid_ptr = tid_ptr;
\r
42 logger->rotate_online = rotate_online;
\r
44 HANDLE thread_handle = CreateThread(NULL, 0, log_and_rotate, (void *) logger, 0, logger->tid_ptr);
\r
45 if (! thread_handle) {
\r
46 log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_CREATETHREAD_FAILED, error_string(GetLastError()), 0);
\r
47 HeapFree(GetProcessHeap(), 0, logger);
\r
50 return thread_handle;
\r
53 static inline unsigned long guess_charsize(void *address, unsigned long bufsize) {
\r
54 if (IsTextUnicode(address, bufsize, 0)) return (unsigned long) sizeof(wchar_t);
\r
55 else return (unsigned long) sizeof(char);
\r
58 static inline void write_bom(logger_t *logger, unsigned long *out) {
\r
59 wchar_t bom = L'\ufeff';
\r
60 if (! WriteFile(logger->write_handle, (void *) &bom, sizeof(bom), out, 0)) {
\r
61 log_event(EVENTLOG_WARNING_TYPE, NSSM_EVENT_SOMEBODY_SET_UP_US_THE_BOM, logger->service_name, logger->path, error_string(GetLastError()), 0);
\r
65 /* Get path, share mode, creation disposition and flags for a stream. */
\r
66 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
67 TCHAR value[NSSM_STDIO_LENGTH];
\r
70 if (_sntprintf_s(value, _countof(value), _TRUNCATE, _T("%s"), prefix) < 0) {
\r
71 log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_OUT_OF_MEMORY, prefix, _T("get_createfile_parameters()"), 0);
\r
74 switch (expand_parameter(key, value, path, PATH_LENGTH, true, false)) {
\r
75 case 0: if (! path[0]) return 0; break; /* OK. */
\r
76 default: return 2; /* Error. */
\r
80 if (_sntprintf_s(value, _countof(value), _TRUNCATE, _T("%s%s"), prefix, NSSM_REG_STDIO_SHARING) < 0) {
\r
81 log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_OUT_OF_MEMORY, NSSM_REG_STDIO_SHARING, _T("get_createfile_parameters()"), 0);
\r
84 switch (get_number(key, value, sharing, false)) {
\r
85 case 0: *sharing = default_sharing; break; /* Missing. */
\r
86 case 1: break; /* Found. */
\r
87 case -2: return 4; break; /* Error. */
\r
90 /* CreationDisposition. */
\r
91 if (_sntprintf_s(value, _countof(value), _TRUNCATE, _T("%s%s"), prefix, NSSM_REG_STDIO_DISPOSITION) < 0) {
\r
92 log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_OUT_OF_MEMORY, NSSM_REG_STDIO_DISPOSITION, _T("get_createfile_parameters()"), 0);
\r
95 switch (get_number(key, value, disposition, false)) {
\r
96 case 0: *disposition = default_disposition; break; /* Missing. */
\r
97 case 1: break; /* Found. */
\r
98 case -2: return 6; break; /* Error. */
\r
102 if (_sntprintf_s(value, _countof(value), _TRUNCATE, _T("%s%s"), prefix, NSSM_REG_STDIO_FLAGS) < 0) {
\r
103 log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_OUT_OF_MEMORY, NSSM_REG_STDIO_FLAGS, _T("get_createfile_parameters()"), 0);
\r
106 switch (get_number(key, value, flags, false)) {
\r
107 case 0: *flags = default_flags; break; /* Missing. */
\r
108 case 1: break; /* Found. */
\r
109 case -2: return 8; break; /* Error. */
\r
115 int set_createfile_parameter(HKEY key, TCHAR *prefix, TCHAR *suffix, unsigned long number) {
\r
116 TCHAR value[NSSM_STDIO_LENGTH];
\r
118 if (_sntprintf_s(value, _countof(value), _TRUNCATE, _T("%s%s"), prefix, suffix) < 0) {
\r
119 log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_OUT_OF_MEMORY, suffix, _T("set_createfile_parameter()"), 0);
\r
123 return set_number(key, value, number);
\r
126 int delete_createfile_parameter(HKEY key, TCHAR *prefix, TCHAR *suffix) {
\r
127 TCHAR value[NSSM_STDIO_LENGTH];
\r
129 if (_sntprintf_s(value, _countof(value), _TRUNCATE, _T("%s%s"), prefix, suffix) < 0) {
\r
130 log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_OUT_OF_MEMORY, suffix, _T("delete_createfile_parameter()"), 0);
\r
134 if (RegDeleteValue(key, value)) return 0;
\r
138 HANDLE append_to_file(TCHAR *path, unsigned long sharing, SECURITY_ATTRIBUTES *attributes, unsigned long disposition, unsigned long flags) {
\r
141 /* Try to append to the file first. */
\r
142 ret = CreateFile(path, FILE_APPEND_DATA, sharing, attributes, disposition, flags, 0);
\r
148 unsigned long error = GetLastError();
\r
149 if (error != ERROR_FILE_NOT_FOUND) {
\r
150 log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_CREATEFILE_FAILED, path, error_string(error), 0);
\r
154 /* It didn't exist. Create it. */
\r
155 ret = CreateFile(path, FILE_WRITE_DATA, sharing, attributes, disposition, flags, 0);
\r
156 if (! ret) log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_CREATEFILE_FAILED, path, error_string(GetLastError()), 0);
\r
161 static void rotated_filename(TCHAR *path, TCHAR *rotated, unsigned long rotated_len, SYSTEMTIME *st) {
\r
168 TCHAR buffer[PATH_LENGTH];
\r
169 memmove(buffer, path, sizeof(buffer));
\r
170 TCHAR *ext = PathFindExtension(buffer);
\r
171 TCHAR extension[PATH_LENGTH];
\r
172 _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
174 _sntprintf_s(rotated, rotated_len, _TRUNCATE, _T("%s%s"), buffer, extension);
\r
177 void rotate_file(TCHAR *service_name, TCHAR *path, unsigned long seconds, unsigned long low, unsigned long high) {
\r
178 unsigned long error;
\r
182 GetSystemTime(&st);
\r
184 BY_HANDLE_FILE_INFORMATION info;
\r
186 /* Try to open the file to check if it exists and to get attributes. */
\r
187 HANDLE file = CreateFile(path, 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
\r
189 /* Get file attributes. */
\r
190 if (! GetFileInformationByHandle(file, &info)) {
\r
191 /* Reuse current time for rotation timestamp. */
\r
192 seconds = low = high = 0;
\r
193 SystemTimeToFileTime(&st, &info.ftLastWriteTime);
\r
199 error = GetLastError();
\r
200 if (error == ERROR_FILE_NOT_FOUND) return;
\r
201 log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_ROTATE_FILE_FAILED, service_name, path, _T("CreateFile()"), path, error_string(error), 0);
\r
202 /* Reuse current time for rotation timestamp. */
\r
203 seconds = low = high = 0;
\r
204 SystemTimeToFileTime(&st, &info.ftLastWriteTime);
\r
207 /* Check file age. */
\r
210 SystemTimeToFileTime(&st, &ft);
\r
213 s.LowPart = ft.dwLowDateTime;
\r
214 s.HighPart = ft.dwHighDateTime;
\r
215 s.QuadPart -= seconds * 10000000LL;
\r
216 ft.dwLowDateTime = s.LowPart;
\r
217 ft.dwHighDateTime = s.HighPart;
\r
218 if (CompareFileTime(&info.ftLastWriteTime, &ft) > 0) return;
\r
221 /* Check file size. */
\r
223 if (info.nFileSizeHigh < high) return;
\r
224 if (info.nFileSizeHigh == high && info.nFileSizeLow < low) return;
\r
227 /* Get new filename. */
\r
228 FileTimeToSystemTime(&info.ftLastWriteTime, &st);
\r
230 TCHAR rotated[PATH_LENGTH];
\r
231 rotated_filename(path, rotated, _countof(rotated), &st);
\r
234 if (MoveFile(path, rotated)) {
\r
235 log_event(EVENTLOG_INFORMATION_TYPE, NSSM_EVENT_ROTATED, service_name, path, rotated, 0);
\r
238 error = GetLastError();
\r
240 if (error == ERROR_FILE_NOT_FOUND) return;
\r
241 log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_ROTATE_FILE_FAILED, service_name, path, _T("MoveFile()"), rotated, error_string(error), 0);
\r
245 int get_output_handles(nssm_service_t *service, HKEY key, STARTUPINFO *si) {
\r
246 bool set_flags = false;
\r
248 /* Standard security attributes allowing inheritance. */
\r
249 SECURITY_ATTRIBUTES attributes;
\r
250 ZeroMemory(&attributes, sizeof(attributes));
\r
251 attributes.bInheritHandle = true;
\r
254 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
255 service->stdout_sharing = service->stdout_disposition = service->stdout_flags = 0;
\r
256 ZeroMemory(service->stdout_path, _countof(service->stdout_path) * sizeof(TCHAR));
\r
259 if (si && service->stdout_path[0]) {
\r
260 if (service->rotate_files) rotate_file(service->name, service->stdout_path, service->rotate_seconds, service->rotate_bytes_low, service->rotate_bytes_high);
\r
261 HANDLE stdout_handle = append_to_file(service->stdout_path, service->stdout_sharing, 0, service->stdout_disposition, service->stdout_flags);
\r
262 if (! stdout_handle) return 4;
\r
264 if (service->rotate_files && service->rotate_stdout_online) {
\r
265 service->stdout_pipe = si->hStdOutput = 0;
\r
266 service->stdout_thread = create_logging_thread(service->name, service->stdout_path, service->stdout_sharing, service->stdout_disposition, service->stdout_flags, &service->stdout_pipe, &si->hStdOutput, &stdout_handle, service->rotate_bytes_low, service->rotate_bytes_high, &service->stdout_tid, &service->rotate_stdout_online);
\r
267 if (! service->stdout_thread) {
\r
268 CloseHandle(service->stdout_pipe);
\r
269 CloseHandle(si->hStdOutput);
\r
272 else service->stdout_thread = 0;
\r
274 if (! service->stdout_thread) {
\r
275 if (! DuplicateHandle(GetCurrentProcess(), stdout_handle, GetCurrentProcess(), &si->hStdOutput, 0, true, DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) {
\r
276 log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_DUPLICATEHANDLE_FAILED, NSSM_REG_STDOUT, _T("stdout"), error_string(GetLastError()), 0);
\r
279 service->rotate_stdout_online = NSSM_ROTATE_OFFLINE;
\r
286 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
287 service->stderr_sharing = service->stderr_disposition = service->stderr_flags = 0;
\r
288 ZeroMemory(service->stderr_path, _countof(service->stderr_path) * sizeof(TCHAR));
\r
291 if (service->stderr_path[0]) {
\r
292 /* Same as stdout? */
\r
293 if (str_equiv(service->stderr_path, service->stdout_path)) {
\r
294 service->stderr_sharing = service->stdout_sharing;
\r
295 service->stderr_disposition = service->stdout_disposition;
\r
296 service->stderr_flags = service->stdout_flags;
\r
297 service->rotate_stderr_online = NSSM_ROTATE_OFFLINE;
\r
300 /* Two handles to the same file will create a race. */
\r
301 if (! DuplicateHandle(GetCurrentProcess(), si->hStdOutput, GetCurrentProcess(), &si->hStdError, 0, true, DUPLICATE_SAME_ACCESS)) {
\r
302 log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_DUPLICATEHANDLE_FAILED, NSSM_REG_STDOUT, _T("stderr"), error_string(GetLastError()), 0);
\r
308 if (service->rotate_files) rotate_file(service->name, service->stderr_path, service->rotate_seconds, service->rotate_bytes_low, service->rotate_bytes_high);
\r
309 HANDLE stderr_handle = append_to_file(service->stderr_path, service->stderr_sharing, 0, service->stderr_disposition, service->stderr_flags);
\r
310 if (! stderr_handle) return 7;
\r
312 if (service->rotate_files && service->rotate_stderr_online) {
\r
313 service->stderr_pipe = si->hStdError = 0;
\r
314 service->stderr_thread = create_logging_thread(service->name, service->stderr_path, service->stderr_sharing, service->stderr_disposition, service->stderr_flags, &service->stderr_pipe, &si->hStdError, &stderr_handle, service->rotate_bytes_low, service->rotate_bytes_high, &service->stderr_tid, &service->rotate_stderr_online);
\r
315 if (! service->stderr_thread) {
\r
316 CloseHandle(service->stderr_pipe);
\r
317 CloseHandle(si->hStdError);
\r
320 else service->stderr_thread = 0;
\r
322 if (! service->stderr_thread) {
\r
323 if (! DuplicateHandle(GetCurrentProcess(), stderr_handle, GetCurrentProcess(), &si->hStdError, 0, true, DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) {
\r
324 log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_DUPLICATEHANDLE_FAILED, NSSM_REG_STDERR, _T("stderr"), error_string(GetLastError()), 0);
\r
327 service->rotate_stderr_online = NSSM_ROTATE_OFFLINE;
\r
335 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
336 service->stdin_sharing = service->stdin_disposition = service->stdin_flags = 0;
\r
337 ZeroMemory(service->stdin_path, _countof(service->stdin_path) * sizeof(TCHAR));
\r
340 if (si && service->stdin_path[0]) {
\r
341 if (str_equiv(service->stdin_path, _T("|"))) {
\r
342 /* Fake stdin with a pipe. */
\r
345 None of this is necessary if we aren't redirecting stdout and/or
\r
348 If we don't redirect any handles the application will start and be
\r
349 quite happy with its console. If we start it with
\r
350 STARTF_USESTDHANDLES set it will interpret a NULL value for
\r
351 hStdInput as meaning no input. Because the service starts with
\r
352 no stdin we can't just pass GetStdHandle(STD_INPUT_HANDLE) to
\r
355 The only way we can successfully redirect the application's output
\r
356 while preventing programs which exit after reading all input from
\r
357 exiting prematurely is to create a pipe between ourselves and the
\r
358 application but write nothing to it.
\r
360 if (! CreatePipe(&si->hStdInput, &service->stdin_pipe, 0, 0)) {
\r
361 log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_STDIN_CREATEPIPE_FAILED, service->name, error_string(GetLastError()), 0);
\r
364 SetHandleInformation(si->hStdInput, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT);
\r
368 si->hStdInput = CreateFile(service->stdin_path, FILE_READ_DATA, service->stdin_sharing, &attributes, service->stdin_disposition, service->stdin_flags, 0);
\r
369 if (! si->hStdInput) {
\r
370 log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_CREATEFILE_FAILED, service->stdin_path, error_string(GetLastError()), 0);
\r
378 if (! set_flags) return 0;
\r
381 We need to set the startup_info flags to make the new handles
\r
382 inheritable by the new process.
\r
384 if (si) si->dwFlags |= STARTF_USESTDHANDLES;
\r
389 void close_output_handles(STARTUPINFO *si) {
\r
390 if (si->hStdInput) CloseHandle(si->hStdInput);
\r
391 if (si->hStdOutput) CloseHandle(si->hStdOutput);
\r
392 if (si->hStdError) CloseHandle(si->hStdError);
\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 /* Ignore the error if we've been requested to exit anyway. */
\r
432 if (*logger->rotate_online != NSSM_ROTATE_ONLINE) return ret;
\r
433 if (! (*complained & COMPLAINED_READ)) log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_READFILE_FAILED, logger->service_name, logger->path, error_string(error), 0);
\r
434 *complained |= COMPLAINED_READ;
\r
439 Try multiple times to write to a file.
\r
440 Returns: 0 on success.
\r
441 1 on non-fatal error.
\r
444 static int try_write(logger_t *logger, void *address, unsigned long bufsize, unsigned long *out, int *complained) {
\r
446 unsigned long error;
\r
447 for (int tries = 0; tries < 5; tries++) {
\r
448 if (WriteFile(logger->write_handle, address, bufsize, out, 0)) return 0;
\r
450 error = GetLastError();
\r
451 if (error == ERROR_IO_PENDING) {
\r
452 /* Operation was successful pending flush to disk. */
\r
457 /* Other end closed the pipe. */
\r
458 case ERROR_BROKEN_PIPE:
\r
460 goto complain_write;
\r
462 /* Couldn't lock the buffer. */
\r
463 case ERROR_NOT_ENOUGH_QUOTA:
\r
464 /* Out of disk space. */
\r
465 case ERROR_DISK_FULL:
\r
466 Sleep(2000 + tries * 3000);
\r
471 /* We'll lose this line but try to read and write subsequent ones. */
\r
477 if (! (*complained & COMPLAINED_WRITE)) log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_WRITEFILE_FAILED, logger->service_name, logger->path, error_string(error), 0);
\r
478 *complained |= COMPLAINED_WRITE;
\r
482 /* Wrapper to be called in a new thread for logging. */
\r
483 unsigned long WINAPI log_and_rotate(void *arg) {
\r
484 logger_t *logger = (logger_t *) arg;
\r
485 if (! logger) return 1;
\r
488 BY_HANDLE_FILE_INFORMATION info;
\r
490 /* Find initial file size. */
\r
491 if (! GetFileInformationByHandle(logger->write_handle, &info)) logger->size = 0LL;
\r
494 l.HighPart = info.nFileSizeHigh;
\r
495 l.LowPart = info.nFileSizeLow;
\r
501 unsigned long in, out;
\r
502 unsigned long charsize = 0;
\r
503 unsigned long error;
\r
505 int complained = 0;
\r
508 /* Read data from the pipe. */
\r
510 ret = try_read(logger, address, sizeof(buffer), &in, &complained);
\r
512 CloseHandle(logger->read_handle);
\r
513 CloseHandle(logger->write_handle);
\r
514 HeapFree(GetProcessHeap(), 0, logger);
\r
517 else if (ret) continue;
\r
519 if (*logger->rotate_online == NSSM_ROTATE_ONLINE_ASAP || (logger->size && size + (__int64) in >= logger->size)) {
\r
520 /* Look for newline. */
\r
522 for (i = 0; i < in; i++) {
\r
523 if (buffer[i] == '\n') {
\r
524 if (! charsize) charsize = guess_charsize(address, in);
\r
527 /* Write up to the newline. */
\r
528 ret = try_write(logger, address, i, &out, &complained);
\r
530 HeapFree(GetProcessHeap(), 0, logger);
\r
531 CloseHandle(logger->read_handle);
\r
532 CloseHandle(logger->write_handle);
\r
535 size += (__int64) out;
\r
538 *logger->rotate_online = NSSM_ROTATE_ONLINE;
\r
539 TCHAR rotated[PATH_LENGTH];
\r
540 rotated_filename(logger->path, rotated, _countof(rotated), 0);
\r
543 Ideally we'd try the rename first then close the handle but
\r
544 MoveFile() will fail if the handle is still open so we must
\r
545 risk losing everything.
\r
547 CloseHandle(logger->write_handle);
\r
548 if (MoveFile(logger->path, rotated)) {
\r
549 log_event(EVENTLOG_INFORMATION_TYPE, NSSM_EVENT_ROTATED, logger->service_name, logger->path, rotated, 0);
\r
553 error = GetLastError();
\r
554 if (error != ERROR_FILE_NOT_FOUND) {
\r
555 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
556 complained |= COMPLAINED_ROTATE;
\r
557 /* We can at least try to re-open the existing file. */
\r
558 logger->disposition = OPEN_ALWAYS;
\r
563 logger->write_handle = append_to_file(logger->path, logger->sharing, 0, logger->disposition, logger->flags);
\r
564 if (! logger->write_handle) {
\r
565 error = GetLastError();
\r
566 log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_CREATEFILE_FAILED, logger->path, error_string(error), 0);
\r
567 /* Oh dear. Now we can't log anything further. */
\r
568 HeapFree(GetProcessHeap(), 0, logger);
\r
569 CloseHandle(logger->read_handle);
\r
570 CloseHandle(logger->write_handle);
\r
574 /* Resume writing after the newline. */
\r
575 address = (void *) ((char *) address + i);
\r
582 /* Write a BOM to the new file. */
\r
583 if (! charsize) charsize = guess_charsize(address, in);
\r
584 if (charsize == sizeof(wchar_t)) write_bom(logger, &out);
\r
585 size += (__int64) out;
\r
588 /* Write the data, if any. */
\r
589 if (! in) continue;
\r
591 ret = try_write(logger, address, in, &out, &complained);
\r
592 size += (__int64) out;
\r
594 HeapFree(GetProcessHeap(), 0, logger);
\r
595 CloseHandle(logger->read_handle);
\r
596 CloseHandle(logger->write_handle);
\r
601 HeapFree(GetProcessHeap(), 0, logger);
\r
602 CloseHandle(logger->read_handle);
\r
603 CloseHandle(logger->write_handle);
\r