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 write_to_file(TCHAR *path, unsigned long sharing, SECURITY_ATTRIBUTES *attributes, unsigned long disposition, unsigned long flags) {
\r
139 HANDLE ret = CreateFile(path, FILE_WRITE_DATA, sharing, attributes, disposition, flags, 0);
\r
141 if (SetFilePointer(ret, 0, 0, FILE_END) != INVALID_SET_FILE_POINTER) SetEndOfFile(ret);
\r
145 log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_CREATEFILE_FAILED, path, error_string(GetLastError()), 0);
\r
149 static void rotated_filename(TCHAR *path, TCHAR *rotated, unsigned long rotated_len, SYSTEMTIME *st) {
\r
156 TCHAR buffer[PATH_LENGTH];
\r
157 memmove(buffer, path, sizeof(buffer));
\r
158 TCHAR *ext = PathFindExtension(buffer);
\r
159 TCHAR extension[PATH_LENGTH];
\r
160 _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
162 _sntprintf_s(rotated, rotated_len, _TRUNCATE, _T("%s%s"), buffer, extension);
\r
165 void rotate_file(TCHAR *service_name, TCHAR *path, unsigned long seconds, unsigned long low, unsigned long high) {
\r
166 unsigned long error;
\r
170 GetSystemTime(&st);
\r
172 BY_HANDLE_FILE_INFORMATION info;
\r
174 /* Try to open the file to check if it exists and to get attributes. */
\r
175 HANDLE file = CreateFile(path, 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
\r
177 /* Get file attributes. */
\r
178 if (! GetFileInformationByHandle(file, &info)) {
\r
179 /* Reuse current time for rotation timestamp. */
\r
180 seconds = low = high = 0;
\r
181 SystemTimeToFileTime(&st, &info.ftLastWriteTime);
\r
187 error = GetLastError();
\r
188 if (error == ERROR_FILE_NOT_FOUND) return;
\r
189 log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_ROTATE_FILE_FAILED, service_name, path, _T("CreateFile()"), path, error_string(error), 0);
\r
190 /* Reuse current time for rotation timestamp. */
\r
191 seconds = low = high = 0;
\r
192 SystemTimeToFileTime(&st, &info.ftLastWriteTime);
\r
195 /* Check file age. */
\r
198 SystemTimeToFileTime(&st, &ft);
\r
201 s.LowPart = ft.dwLowDateTime;
\r
202 s.HighPart = ft.dwHighDateTime;
\r
203 s.QuadPart -= seconds * 10000000LL;
\r
204 ft.dwLowDateTime = s.LowPart;
\r
205 ft.dwHighDateTime = s.HighPart;
\r
206 if (CompareFileTime(&info.ftLastWriteTime, &ft) > 0) return;
\r
209 /* Check file size. */
\r
211 if (info.nFileSizeHigh < high) return;
\r
212 if (info.nFileSizeHigh == high && info.nFileSizeLow < low) return;
\r
215 /* Get new filename. */
\r
216 FileTimeToSystemTime(&info.ftLastWriteTime, &st);
\r
218 TCHAR rotated[PATH_LENGTH];
\r
219 rotated_filename(path, rotated, _countof(rotated), &st);
\r
222 if (MoveFile(path, rotated)) {
\r
223 log_event(EVENTLOG_INFORMATION_TYPE, NSSM_EVENT_ROTATED, service_name, path, rotated, 0);
\r
226 error = GetLastError();
\r
228 if (error == ERROR_FILE_NOT_FOUND) return;
\r
229 log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_ROTATE_FILE_FAILED, service_name, path, _T("MoveFile()"), rotated, error_string(error), 0);
\r
233 int get_output_handles(nssm_service_t *service, HKEY key, STARTUPINFO *si) {
\r
234 /* Allocate a new console so we get a fresh stdin, stdout and stderr. */
\r
235 if (si) alloc_console(service);
\r
238 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
239 service->stdin_sharing = service->stdin_disposition = service->stdin_flags = 0;
\r
240 ZeroMemory(service->stdin_path, _countof(service->stdin_path) * sizeof(TCHAR));
\r
243 if (si && service->stdin_path[0]) {
\r
244 si->hStdInput = CreateFile(service->stdin_path, FILE_READ_DATA, service->stdin_sharing, 0, service->stdin_disposition, service->stdin_flags, 0);
\r
245 if (! si->hStdInput) {
\r
246 log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_CREATEFILE_FAILED, service->stdin_path, error_string(GetLastError()), 0);
\r
252 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
253 service->stdout_sharing = service->stdout_disposition = service->stdout_flags = 0;
\r
254 ZeroMemory(service->stdout_path, _countof(service->stdout_path) * sizeof(TCHAR));
\r
257 if (si && service->stdout_path[0]) {
\r
258 if (service->rotate_files) rotate_file(service->name, service->stdout_path, service->rotate_seconds, service->rotate_bytes_low, service->rotate_bytes_high);
\r
259 HANDLE stdout_handle = write_to_file(service->stdout_path, service->stdout_sharing, 0, service->stdout_disposition, service->stdout_flags);
\r
260 if (! stdout_handle) return 4;
\r
262 if (service->rotate_files && service->rotate_stdout_online) {
\r
263 service->stdout_pipe = si->hStdOutput = 0;
\r
264 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
265 if (! service->stdout_thread) {
\r
266 CloseHandle(service->stdout_pipe);
\r
267 CloseHandle(si->hStdOutput);
\r
270 else service->stdout_thread = 0;
\r
272 if (! service->stdout_thread) {
\r
273 if (! DuplicateHandle(GetCurrentProcess(), stdout_handle, GetCurrentProcess(), &si->hStdOutput, 0, true, DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) {
\r
274 log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_DUPLICATEHANDLE_FAILED, NSSM_REG_STDOUT, _T("stdout"), error_string(GetLastError()), 0);
\r
277 service->rotate_stdout_online = NSSM_ROTATE_OFFLINE;
\r
282 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
283 service->stderr_sharing = service->stderr_disposition = service->stderr_flags = 0;
\r
284 ZeroMemory(service->stderr_path, _countof(service->stderr_path) * sizeof(TCHAR));
\r
287 if (service->stderr_path[0]) {
\r
288 /* Same as stdout? */
\r
289 if (str_equiv(service->stderr_path, service->stdout_path)) {
\r
290 service->stderr_sharing = service->stdout_sharing;
\r
291 service->stderr_disposition = service->stdout_disposition;
\r
292 service->stderr_flags = service->stdout_flags;
\r
293 service->rotate_stderr_online = NSSM_ROTATE_OFFLINE;
\r
296 /* Two handles to the same file will create a race. */
\r
297 if (! DuplicateHandle(GetCurrentProcess(), si->hStdOutput, GetCurrentProcess(), &si->hStdError, 0, true, DUPLICATE_SAME_ACCESS)) {
\r
298 log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_DUPLICATEHANDLE_FAILED, NSSM_REG_STDOUT, _T("stderr"), error_string(GetLastError()), 0);
\r
304 if (service->rotate_files) rotate_file(service->name, service->stderr_path, service->rotate_seconds, service->rotate_bytes_low, service->rotate_bytes_high);
\r
305 HANDLE stderr_handle = write_to_file(service->stderr_path, service->stderr_sharing, 0, service->stderr_disposition, service->stderr_flags);
\r
306 if (! stderr_handle) return 7;
\r
308 if (service->rotate_files && service->rotate_stderr_online) {
\r
309 service->stderr_pipe = si->hStdError = 0;
\r
310 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
311 if (! service->stderr_thread) {
\r
312 CloseHandle(service->stderr_pipe);
\r
313 CloseHandle(si->hStdError);
\r
316 else service->stderr_thread = 0;
\r
318 if (! service->stderr_thread) {
\r
319 if (! DuplicateHandle(GetCurrentProcess(), stderr_handle, GetCurrentProcess(), &si->hStdError, 0, true, DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) {
\r
320 log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_DUPLICATEHANDLE_FAILED, NSSM_REG_STDERR, _T("stderr"), error_string(GetLastError()), 0);
\r
323 service->rotate_stderr_online = NSSM_ROTATE_OFFLINE;
\r
328 if (! si) return 0;
\r
331 We need to set the startup_info flags to make the new handles
\r
332 inheritable by the new process.
\r
334 si->dwFlags |= STARTF_USESTDHANDLES;
\r
336 if (service->no_console) return 0;
\r
338 /* Redirect other handles. */
\r
339 if (! si->hStdInput) {
\r
340 if (! DuplicateHandle(GetCurrentProcess(), GetStdHandle(STD_INPUT_HANDLE), GetCurrentProcess(), &si->hStdInput, 0, true, DUPLICATE_SAME_ACCESS)) {
\r
341 log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_DUPLICATEHANDLE_FAILED, _T("STD_INPUT_HANDLE"), _T("stdin"), error_string(GetLastError()), 0);
\r
345 if (! si->hStdOutput) {
\r
346 if (! DuplicateHandle(GetCurrentProcess(), GetStdHandle(STD_OUTPUT_HANDLE), GetCurrentProcess(), &si->hStdOutput, 0, true, DUPLICATE_SAME_ACCESS)) {
\r
347 log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_DUPLICATEHANDLE_FAILED, _T("STD_OUTPUT_HANDLE"), _T("stdout"), error_string(GetLastError()), 0);
\r
351 if (! si->hStdError) {
\r
352 if (! DuplicateHandle(GetCurrentProcess(), GetStdHandle(STD_ERROR_HANDLE), GetCurrentProcess(), &si->hStdError, 0, true, DUPLICATE_SAME_ACCESS)) {
\r
353 log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_DUPLICATEHANDLE_FAILED, _T("STD_ERROR_HANDLE"), _T("stderr"), error_string(GetLastError()), 0);
\r
361 void close_output_handles(STARTUPINFO *si) {
\r
362 if (si->hStdInput) CloseHandle(si->hStdInput);
\r
363 if (si->hStdOutput) CloseHandle(si->hStdOutput);
\r
364 if (si->hStdError) CloseHandle(si->hStdError);
\r
368 Try multiple times to read from a file.
\r
369 Returns: 0 on success.
\r
370 1 on non-fatal error.
\r
373 static int try_read(logger_t *logger, void *address, unsigned long bufsize, unsigned long *in, int *complained) {
\r
375 unsigned long error;
\r
376 for (int tries = 0; tries < 5; tries++) {
\r
377 if (ReadFile(logger->read_handle, address, bufsize, in, 0)) return 0;
\r
379 error = GetLastError();
\r
381 /* Other end closed the pipe. */
\r
382 case ERROR_BROKEN_PIPE:
\r
384 goto complain_read;
\r
386 /* Couldn't lock the buffer. */
\r
387 case ERROR_NOT_ENOUGH_QUOTA:
\r
388 Sleep(2000 + tries * 3000);
\r
392 /* Write was cancelled by the other end. */
\r
393 case ERROR_OPERATION_ABORTED:
\r
395 goto complain_read;
\r
403 /* Ignore the error if we've been requested to exit anyway. */
\r
404 if (*logger->rotate_online != NSSM_ROTATE_ONLINE) return ret;
\r
405 if (! (*complained & COMPLAINED_READ)) log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_READFILE_FAILED, logger->service_name, logger->path, error_string(error), 0);
\r
406 *complained |= COMPLAINED_READ;
\r
411 Try multiple times to write to a file.
\r
412 Returns: 0 on success.
\r
413 1 on non-fatal error.
\r
416 static int try_write(logger_t *logger, void *address, unsigned long bufsize, unsigned long *out, int *complained) {
\r
418 unsigned long error;
\r
419 for (int tries = 0; tries < 5; tries++) {
\r
420 if (WriteFile(logger->write_handle, address, bufsize, out, 0)) return 0;
\r
422 error = GetLastError();
\r
423 if (error == ERROR_IO_PENDING) {
\r
424 /* Operation was successful pending flush to disk. */
\r
429 /* Other end closed the pipe. */
\r
430 case ERROR_BROKEN_PIPE:
\r
432 goto complain_write;
\r
434 /* Couldn't lock the buffer. */
\r
435 case ERROR_NOT_ENOUGH_QUOTA:
\r
436 /* Out of disk space. */
\r
437 case ERROR_DISK_FULL:
\r
438 Sleep(2000 + tries * 3000);
\r
443 /* We'll lose this line but try to read and write subsequent ones. */
\r
449 if (! (*complained & COMPLAINED_WRITE)) log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_WRITEFILE_FAILED, logger->service_name, logger->path, error_string(error), 0);
\r
450 *complained |= COMPLAINED_WRITE;
\r
454 /* Wrapper to be called in a new thread for logging. */
\r
455 unsigned long WINAPI log_and_rotate(void *arg) {
\r
456 logger_t *logger = (logger_t *) arg;
\r
457 if (! logger) return 1;
\r
460 BY_HANDLE_FILE_INFORMATION info;
\r
462 /* Find initial file size. */
\r
463 if (! GetFileInformationByHandle(logger->write_handle, &info)) logger->size = 0LL;
\r
466 l.HighPart = info.nFileSizeHigh;
\r
467 l.LowPart = info.nFileSizeLow;
\r
473 unsigned long in, out;
\r
474 unsigned long charsize = 0;
\r
475 unsigned long error;
\r
477 int complained = 0;
\r
480 /* Read data from the pipe. */
\r
482 ret = try_read(logger, address, sizeof(buffer), &in, &complained);
\r
484 CloseHandle(logger->read_handle);
\r
485 CloseHandle(logger->write_handle);
\r
486 HeapFree(GetProcessHeap(), 0, logger);
\r
489 else if (ret) continue;
\r
491 if (*logger->rotate_online == NSSM_ROTATE_ONLINE_ASAP || (logger->size && size + (__int64) in >= logger->size)) {
\r
492 /* Look for newline. */
\r
494 for (i = 0; i < in; i++) {
\r
495 if (buffer[i] == '\n') {
\r
496 if (! charsize) charsize = guess_charsize(address, in);
\r
499 /* Write up to the newline. */
\r
500 ret = try_write(logger, address, i, &out, &complained);
\r
502 HeapFree(GetProcessHeap(), 0, logger);
\r
503 CloseHandle(logger->read_handle);
\r
504 CloseHandle(logger->write_handle);
\r
507 size += (__int64) out;
\r
510 *logger->rotate_online = NSSM_ROTATE_ONLINE;
\r
511 TCHAR rotated[PATH_LENGTH];
\r
512 rotated_filename(logger->path, rotated, _countof(rotated), 0);
\r
515 Ideally we'd try the rename first then close the handle but
\r
516 MoveFile() will fail if the handle is still open so we must
\r
517 risk losing everything.
\r
519 CloseHandle(logger->write_handle);
\r
520 if (MoveFile(logger->path, rotated)) {
\r
521 log_event(EVENTLOG_INFORMATION_TYPE, NSSM_EVENT_ROTATED, logger->service_name, logger->path, rotated, 0);
\r
525 error = GetLastError();
\r
526 if (error != ERROR_FILE_NOT_FOUND) {
\r
527 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
528 complained |= COMPLAINED_ROTATE;
\r
529 /* We can at least try to re-open the existing file. */
\r
530 logger->disposition = OPEN_ALWAYS;
\r
535 logger->write_handle = write_to_file(logger->path, logger->sharing, 0, logger->disposition, logger->flags);
\r
536 if (! logger->write_handle) {
\r
537 error = GetLastError();
\r
538 log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_CREATEFILE_FAILED, logger->path, error_string(error), 0);
\r
539 /* Oh dear. Now we can't log anything further. */
\r
540 HeapFree(GetProcessHeap(), 0, logger);
\r
541 CloseHandle(logger->read_handle);
\r
542 CloseHandle(logger->write_handle);
\r
546 /* Resume writing after the newline. */
\r
547 address = (void *) ((char *) address + i);
\r
554 /* Write a BOM to the new file. */
\r
555 if (! charsize) charsize = guess_charsize(address, in);
\r
556 if (charsize == sizeof(wchar_t)) write_bom(logger, &out);
\r
557 size += (__int64) out;
\r
560 /* Write the data, if any. */
\r
561 if (! in) continue;
\r
563 ret = try_write(logger, address, in, &out, &complained);
\r
564 size += (__int64) out;
\r
566 HeapFree(GetProcessHeap(), 0, logger);
\r
567 CloseHandle(logger->read_handle);
\r
568 CloseHandle(logger->write_handle);
\r
573 HeapFree(GetProcessHeap(), 0, logger);
\r
574 CloseHandle(logger->read_handle);
\r
575 CloseHandle(logger->write_handle);
\r