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 rotate_delay, unsigned long *tid_ptr, unsigned long *rotate_online, bool copy_and_truncate) {
\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
43 logger->rotate_delay = rotate_delay;
\r
44 logger->copy_and_truncate = copy_and_truncate;
\r
46 HANDLE thread_handle = CreateThread(NULL, 0, log_and_rotate, (void *) logger, 0, logger->tid_ptr);
\r
47 if (! thread_handle) {
\r
48 log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_CREATETHREAD_FAILED, error_string(GetLastError()), 0);
\r
49 HeapFree(GetProcessHeap(), 0, logger);
\r
52 return thread_handle;
\r
55 static inline unsigned long guess_charsize(void *address, unsigned long bufsize) {
\r
56 if (IsTextUnicode(address, bufsize, 0)) return (unsigned long) sizeof(wchar_t);
\r
57 else return (unsigned long) sizeof(char);
\r
60 static inline void write_bom(logger_t *logger, unsigned long *out) {
\r
61 wchar_t bom = L'\ufeff';
\r
62 if (! WriteFile(logger->write_handle, (void *) &bom, sizeof(bom), out, 0)) {
\r
63 log_event(EVENTLOG_WARNING_TYPE, NSSM_EVENT_SOMEBODY_SET_UP_US_THE_BOM, logger->service_name, logger->path, error_string(GetLastError()), 0);
\r
67 /* Get path, share mode, creation disposition and flags for a stream. */
\r
68 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, bool *copy_and_truncate) {
\r
69 TCHAR value[NSSM_STDIO_LENGTH];
\r
72 if (_sntprintf_s(value, _countof(value), _TRUNCATE, _T("%s"), prefix) < 0) {
\r
73 log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_OUT_OF_MEMORY, prefix, _T("get_createfile_parameters()"), 0);
\r
76 switch (expand_parameter(key, value, path, PATH_LENGTH, true, false)) {
\r
77 case 0: if (! path[0]) return 0; break; /* OK. */
\r
78 default: return 2; /* Error. */
\r
82 if (_sntprintf_s(value, _countof(value), _TRUNCATE, _T("%s%s"), prefix, NSSM_REG_STDIO_SHARING) < 0) {
\r
83 log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_OUT_OF_MEMORY, NSSM_REG_STDIO_SHARING, _T("get_createfile_parameters()"), 0);
\r
86 switch (get_number(key, value, sharing, false)) {
\r
87 case 0: *sharing = default_sharing; break; /* Missing. */
\r
88 case 1: break; /* Found. */
\r
89 case -2: return 4; break; /* Error. */
\r
92 /* CreationDisposition. */
\r
93 if (_sntprintf_s(value, _countof(value), _TRUNCATE, _T("%s%s"), prefix, NSSM_REG_STDIO_DISPOSITION) < 0) {
\r
94 log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_OUT_OF_MEMORY, NSSM_REG_STDIO_DISPOSITION, _T("get_createfile_parameters()"), 0);
\r
97 switch (get_number(key, value, disposition, false)) {
\r
98 case 0: *disposition = default_disposition; break; /* Missing. */
\r
99 case 1: break; /* Found. */
\r
100 case -2: return 6; break; /* Error. */
\r
104 if (_sntprintf_s(value, _countof(value), _TRUNCATE, _T("%s%s"), prefix, NSSM_REG_STDIO_FLAGS) < 0) {
\r
105 log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_OUT_OF_MEMORY, NSSM_REG_STDIO_FLAGS, _T("get_createfile_parameters()"), 0);
\r
108 switch (get_number(key, value, flags, false)) {
\r
109 case 0: *flags = default_flags; break; /* Missing. */
\r
110 case 1: break; /* Found. */
\r
111 case -2: return 8; break; /* Error. */
\r
114 /* Rotate with CopyFile() and SetEndOfFile(). */
\r
115 if (copy_and_truncate) {
\r
116 unsigned long data;
\r
117 if (_sntprintf_s(value, _countof(value), _TRUNCATE, _T("%s%s"), prefix, NSSM_REG_STDIO_COPY_AND_TRUNCATE) < 0) {
\r
118 log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_OUT_OF_MEMORY, NSSM_REG_STDIO_COPY_AND_TRUNCATE, _T("get_createfile_parameters()"), 0);
\r
121 switch (get_number(key, value, &data, false)) {
\r
122 case 0: *copy_and_truncate = false; break; /* Missing. */
\r
123 case 1: /* Found. */
\r
124 if (data) *copy_and_truncate = true;
\r
125 else *copy_and_truncate = false;
\r
127 case -2: return 9; break; /* Error. */
\r
134 int set_createfile_parameter(HKEY key, TCHAR *prefix, TCHAR *suffix, unsigned long number) {
\r
135 TCHAR value[NSSM_STDIO_LENGTH];
\r
137 if (_sntprintf_s(value, _countof(value), _TRUNCATE, _T("%s%s"), prefix, suffix) < 0) {
\r
138 log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_OUT_OF_MEMORY, suffix, _T("set_createfile_parameter()"), 0);
\r
142 return set_number(key, value, number);
\r
145 int delete_createfile_parameter(HKEY key, TCHAR *prefix, TCHAR *suffix) {
\r
146 TCHAR value[NSSM_STDIO_LENGTH];
\r
148 if (_sntprintf_s(value, _countof(value), _TRUNCATE, _T("%s%s"), prefix, suffix) < 0) {
\r
149 log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_OUT_OF_MEMORY, suffix, _T("delete_createfile_parameter()"), 0);
\r
153 if (RegDeleteValue(key, value)) return 0;
\r
157 HANDLE write_to_file(TCHAR *path, unsigned long sharing, SECURITY_ATTRIBUTES *attributes, unsigned long disposition, unsigned long flags) {
\r
158 HANDLE ret = CreateFile(path, FILE_WRITE_DATA, sharing, attributes, disposition, flags, 0);
\r
160 if (SetFilePointer(ret, 0, 0, FILE_END) != INVALID_SET_FILE_POINTER) SetEndOfFile(ret);
\r
164 log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_CREATEFILE_FAILED, path, error_string(GetLastError()), 0);
\r
168 static void rotated_filename(TCHAR *path, TCHAR *rotated, unsigned long rotated_len, SYSTEMTIME *st) {
\r
175 TCHAR buffer[PATH_LENGTH];
\r
176 memmove(buffer, path, sizeof(buffer));
\r
177 TCHAR *ext = PathFindExtension(buffer);
\r
178 TCHAR extension[PATH_LENGTH];
\r
179 _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
181 _sntprintf_s(rotated, rotated_len, _TRUNCATE, _T("%s%s"), buffer, extension);
\r
184 void rotate_file(TCHAR *service_name, TCHAR *path, unsigned long seconds, unsigned long delay, unsigned long low, unsigned long high, bool copy_and_truncate) {
\r
185 unsigned long error;
\r
189 GetSystemTime(&st);
\r
191 BY_HANDLE_FILE_INFORMATION info;
\r
193 /* Try to open the file to check if it exists and to get attributes. */
\r
194 HANDLE file = CreateFile(path, 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
\r
196 /* Get file attributes. */
\r
197 if (! GetFileInformationByHandle(file, &info)) {
\r
198 /* Reuse current time for rotation timestamp. */
\r
199 seconds = low = high = 0;
\r
200 SystemTimeToFileTime(&st, &info.ftLastWriteTime);
\r
206 error = GetLastError();
\r
207 if (error == ERROR_FILE_NOT_FOUND) return;
\r
208 log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_ROTATE_FILE_FAILED, service_name, path, _T("CreateFile()"), path, error_string(error), 0);
\r
209 /* Reuse current time for rotation timestamp. */
\r
210 seconds = low = high = 0;
\r
211 SystemTimeToFileTime(&st, &info.ftLastWriteTime);
\r
214 /* Check file age. */
\r
217 SystemTimeToFileTime(&st, &ft);
\r
220 s.LowPart = ft.dwLowDateTime;
\r
221 s.HighPart = ft.dwHighDateTime;
\r
222 s.QuadPart -= seconds * 10000000LL;
\r
223 ft.dwLowDateTime = s.LowPart;
\r
224 ft.dwHighDateTime = s.HighPart;
\r
225 if (CompareFileTime(&info.ftLastWriteTime, &ft) > 0) return;
\r
228 /* Check file size. */
\r
230 if (info.nFileSizeHigh < high) return;
\r
231 if (info.nFileSizeHigh == high && info.nFileSizeLow < low) return;
\r
234 /* Get new filename. */
\r
235 FileTimeToSystemTime(&info.ftLastWriteTime, &st);
\r
237 TCHAR rotated[PATH_LENGTH];
\r
238 rotated_filename(path, rotated, _countof(rotated), &st);
\r
243 if (copy_and_truncate) {
\r
244 function = _T("CopyFile()");
\r
245 if (CopyFile(path, rotated, TRUE)) {
\r
246 file = write_to_file(path, NSSM_STDOUT_SHARING, 0, NSSM_STDOUT_DISPOSITION, NSSM_STDOUT_FLAGS);
\r
248 SetFilePointer(file, 0, 0, FILE_BEGIN);
\r
249 SetEndOfFile(file);
\r
255 function = _T("MoveFile()");
\r
256 if (! MoveFile(path, rotated)) ok = false;
\r
259 log_event(EVENTLOG_INFORMATION_TYPE, NSSM_EVENT_ROTATED, service_name, path, rotated, 0);
\r
262 error = GetLastError();
\r
264 if (error == ERROR_FILE_NOT_FOUND) return;
\r
265 log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_ROTATE_FILE_FAILED, service_name, path, function, rotated, error_string(error), 0);
\r
269 int get_output_handles(nssm_service_t *service, STARTUPINFO *si) {
\r
270 if (! si) return 1;
\r
272 /* Allocate a new console so we get a fresh stdin, stdout and stderr. */
\r
273 alloc_console(service);
\r
276 if (service->stdin_path[0]) {
\r
277 si->hStdInput = CreateFile(service->stdin_path, FILE_READ_DATA, service->stdin_sharing, 0, service->stdin_disposition, service->stdin_flags, 0);
\r
278 if (! si->hStdInput) {
\r
279 log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_CREATEFILE_FAILED, service->stdin_path, error_string(GetLastError()), 0);
\r
285 if (service->stdout_path[0]) {
\r
286 if (service->rotate_files) rotate_file(service->name, service->stdout_path, service->rotate_seconds, service->rotate_bytes_low, service->rotate_bytes_high, service->rotate_delay, service->stdout_copy_and_truncate);
\r
287 HANDLE stdout_handle = write_to_file(service->stdout_path, service->stdout_sharing, 0, service->stdout_disposition, service->stdout_flags);
\r
288 if (! stdout_handle) return 4;
\r
290 if (service->rotate_files && service->rotate_stdout_online) {
\r
291 service->stdout_pipe = si->hStdOutput = 0;
\r
292 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->rotate_delay, &service->stdout_tid, &service->rotate_stdout_online, service->stdout_copy_and_truncate);
\r
293 if (! service->stdout_thread) {
\r
294 CloseHandle(service->stdout_pipe);
\r
295 CloseHandle(si->hStdOutput);
\r
298 else service->stdout_thread = 0;
\r
300 if (! service->stdout_thread) {
\r
301 if (! DuplicateHandle(GetCurrentProcess(), stdout_handle, GetCurrentProcess(), &si->hStdOutput, 0, true, DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) {
\r
302 log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_DUPLICATEHANDLE_FAILED, NSSM_REG_STDOUT, _T("stdout"), error_string(GetLastError()), 0);
\r
305 service->rotate_stdout_online = NSSM_ROTATE_OFFLINE;
\r
310 if (service->stderr_path[0]) {
\r
311 /* Same as stdout? */
\r
312 if (str_equiv(service->stderr_path, service->stdout_path)) {
\r
313 service->stderr_sharing = service->stdout_sharing;
\r
314 service->stderr_disposition = service->stdout_disposition;
\r
315 service->stderr_flags = service->stdout_flags;
\r
316 service->rotate_stderr_online = NSSM_ROTATE_OFFLINE;
\r
318 /* Two handles to the same file will create a race. */
\r
319 if (! DuplicateHandle(GetCurrentProcess(), si->hStdOutput, GetCurrentProcess(), &si->hStdError, 0, true, DUPLICATE_SAME_ACCESS)) {
\r
320 log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_DUPLICATEHANDLE_FAILED, NSSM_REG_STDOUT, _T("stderr"), error_string(GetLastError()), 0);
\r
325 if (service->rotate_files) rotate_file(service->name, service->stderr_path, service->rotate_seconds, service->rotate_bytes_low, service->rotate_bytes_high, service->rotate_delay, service->stderr_copy_and_truncate);
\r
326 HANDLE stderr_handle = write_to_file(service->stderr_path, service->stderr_sharing, 0, service->stderr_disposition, service->stderr_flags);
\r
327 if (! stderr_handle) return 7;
\r
329 if (service->rotate_files && service->rotate_stderr_online) {
\r
330 service->stderr_pipe = si->hStdError = 0;
\r
331 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->rotate_delay, &service->stderr_tid, &service->rotate_stderr_online, service->stderr_copy_and_truncate);
\r
332 if (! service->stderr_thread) {
\r
333 CloseHandle(service->stderr_pipe);
\r
334 CloseHandle(si->hStdError);
\r
337 else service->stderr_thread = 0;
\r
339 if (! service->stderr_thread) {
\r
340 if (! DuplicateHandle(GetCurrentProcess(), stderr_handle, GetCurrentProcess(), &si->hStdError, 0, true, DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) {
\r
341 log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_DUPLICATEHANDLE_FAILED, NSSM_REG_STDERR, _T("stderr"), error_string(GetLastError()), 0);
\r
344 service->rotate_stderr_online = NSSM_ROTATE_OFFLINE;
\r
350 We need to set the startup_info flags to make the new handles
\r
351 inheritable by the new process.
\r
353 si->dwFlags |= STARTF_USESTDHANDLES;
\r
355 if (service->no_console) return 0;
\r
357 /* Redirect other handles. */
\r
358 if (! si->hStdInput) {
\r
359 if (! DuplicateHandle(GetCurrentProcess(), GetStdHandle(STD_INPUT_HANDLE), GetCurrentProcess(), &si->hStdInput, 0, true, DUPLICATE_SAME_ACCESS)) {
\r
360 log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_DUPLICATEHANDLE_FAILED, _T("STD_INPUT_HANDLE"), _T("stdin"), error_string(GetLastError()), 0);
\r
364 if (! si->hStdOutput) {
\r
365 if (! DuplicateHandle(GetCurrentProcess(), GetStdHandle(STD_OUTPUT_HANDLE), GetCurrentProcess(), &si->hStdOutput, 0, true, DUPLICATE_SAME_ACCESS)) {
\r
366 log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_DUPLICATEHANDLE_FAILED, _T("STD_OUTPUT_HANDLE"), _T("stdout"), error_string(GetLastError()), 0);
\r
370 if (! si->hStdError) {
\r
371 if (! DuplicateHandle(GetCurrentProcess(), GetStdHandle(STD_ERROR_HANDLE), GetCurrentProcess(), &si->hStdError, 0, true, DUPLICATE_SAME_ACCESS)) {
\r
372 log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_DUPLICATEHANDLE_FAILED, _T("STD_ERROR_HANDLE"), _T("stderr"), error_string(GetLastError()), 0);
\r
380 void close_output_handles(STARTUPINFO *si) {
\r
381 if (si->hStdInput) CloseHandle(si->hStdInput);
\r
382 if (si->hStdOutput) CloseHandle(si->hStdOutput);
\r
383 if (si->hStdError) CloseHandle(si->hStdError);
\r
387 Try multiple times to read from a file.
\r
388 Returns: 0 on success.
\r
389 1 on non-fatal error.
\r
392 static int try_read(logger_t *logger, void *address, unsigned long bufsize, unsigned long *in, int *complained) {
\r
394 unsigned long error;
\r
395 for (int tries = 0; tries < 5; tries++) {
\r
396 if (ReadFile(logger->read_handle, address, bufsize, in, 0)) return 0;
\r
398 error = GetLastError();
\r
400 /* Other end closed the pipe. */
\r
401 case ERROR_BROKEN_PIPE:
\r
403 goto complain_read;
\r
405 /* Couldn't lock the buffer. */
\r
406 case ERROR_NOT_ENOUGH_QUOTA:
\r
407 Sleep(2000 + tries * 3000);
\r
411 /* Write was cancelled by the other end. */
\r
412 case ERROR_OPERATION_ABORTED:
\r
414 goto complain_read;
\r
422 /* Ignore the error if we've been requested to exit anyway. */
\r
423 if (*logger->rotate_online != NSSM_ROTATE_ONLINE) return ret;
\r
424 if (! (*complained & COMPLAINED_READ)) log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_READFILE_FAILED, logger->service_name, logger->path, error_string(error), 0);
\r
425 *complained |= COMPLAINED_READ;
\r
430 Try multiple times to write to a file.
\r
431 Returns: 0 on success.
\r
432 1 on non-fatal error.
\r
435 static int try_write(logger_t *logger, void *address, unsigned long bufsize, unsigned long *out, int *complained) {
\r
437 unsigned long error;
\r
438 for (int tries = 0; tries < 5; tries++) {
\r
439 if (WriteFile(logger->write_handle, address, bufsize, out, 0)) return 0;
\r
441 error = GetLastError();
\r
442 if (error == ERROR_IO_PENDING) {
\r
443 /* Operation was successful pending flush to disk. */
\r
448 /* Other end closed the pipe. */
\r
449 case ERROR_BROKEN_PIPE:
\r
451 goto complain_write;
\r
453 /* Couldn't lock the buffer. */
\r
454 case ERROR_NOT_ENOUGH_QUOTA:
\r
455 /* Out of disk space. */
\r
456 case ERROR_DISK_FULL:
\r
457 Sleep(2000 + tries * 3000);
\r
462 /* We'll lose this line but try to read and write subsequent ones. */
\r
468 if (! (*complained & COMPLAINED_WRITE)) log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_WRITEFILE_FAILED, logger->service_name, logger->path, error_string(error), 0);
\r
469 *complained |= COMPLAINED_WRITE;
\r
473 /* Wrapper to be called in a new thread for logging. */
\r
474 unsigned long WINAPI log_and_rotate(void *arg) {
\r
475 logger_t *logger = (logger_t *) arg;
\r
476 if (! logger) return 1;
\r
479 BY_HANDLE_FILE_INFORMATION info;
\r
481 /* Find initial file size. */
\r
482 if (! GetFileInformationByHandle(logger->write_handle, &info)) logger->size = 0LL;
\r
485 l.HighPart = info.nFileSizeHigh;
\r
486 l.LowPart = info.nFileSizeLow;
\r
492 unsigned long in, out;
\r
493 unsigned long charsize = 0;
\r
494 unsigned long error;
\r
496 int complained = 0;
\r
499 /* Read data from the pipe. */
\r
501 ret = try_read(logger, address, sizeof(buffer), &in, &complained);
\r
503 CloseHandle(logger->read_handle);
\r
504 CloseHandle(logger->write_handle);
\r
505 HeapFree(GetProcessHeap(), 0, logger);
\r
508 else if (ret) continue;
\r
510 if (*logger->rotate_online == NSSM_ROTATE_ONLINE_ASAP || (logger->size && size + (__int64) in >= logger->size)) {
\r
511 /* Look for newline. */
\r
513 for (i = 0; i < in; i++) {
\r
514 if (buffer[i] == '\n') {
\r
515 if (! charsize) charsize = guess_charsize(address, in);
\r
518 /* Write up to the newline. */
\r
519 ret = try_write(logger, address, i, &out, &complained);
\r
521 HeapFree(GetProcessHeap(), 0, logger);
\r
522 CloseHandle(logger->read_handle);
\r
523 CloseHandle(logger->write_handle);
\r
526 size += (__int64) out;
\r
529 *logger->rotate_online = NSSM_ROTATE_ONLINE;
\r
530 TCHAR rotated[PATH_LENGTH];
\r
531 rotated_filename(logger->path, rotated, _countof(rotated), 0);
\r
534 Ideally we'd try the rename first then close the handle but
\r
535 MoveFile() will fail if the handle is still open so we must
\r
536 risk losing everything.
\r
538 if (logger->copy_and_truncate) FlushFileBuffers(logger->write_handle);
\r
539 CloseHandle(logger->write_handle);
\r
542 if (logger->copy_and_truncate) {
\r
543 function = _T("CopyFile()");
\r
544 if (CopyFile(logger->path, rotated, TRUE)) {
\r
545 HANDLE file = write_to_file(logger->path, NSSM_STDOUT_SHARING, 0, NSSM_STDOUT_DISPOSITION, NSSM_STDOUT_FLAGS);
\r
546 Sleep(logger->rotate_delay);
\r
547 SetFilePointer(file, 0, 0, FILE_BEGIN);
\r
548 SetEndOfFile(file);
\r
554 function = _T("MoveFile()");
\r
555 if (! MoveFile(logger->path, rotated)) ok = false;
\r
558 log_event(EVENTLOG_INFORMATION_TYPE, NSSM_EVENT_ROTATED, logger->service_name, logger->path, rotated, 0);
\r
562 error = GetLastError();
\r
563 if (error != ERROR_FILE_NOT_FOUND) {
\r
564 if (! (complained & COMPLAINED_ROTATE)) log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_ROTATE_FILE_FAILED, logger->service_name, logger->path, function, rotated, error_string(error), 0);
\r
565 complained |= COMPLAINED_ROTATE;
\r
566 /* We can at least try to re-open the existing file. */
\r
567 logger->disposition = OPEN_ALWAYS;
\r
572 logger->write_handle = write_to_file(logger->path, logger->sharing, 0, logger->disposition, logger->flags);
\r
573 if (! logger->write_handle) {
\r
574 error = GetLastError();
\r
575 log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_CREATEFILE_FAILED, logger->path, error_string(error), 0);
\r
576 /* Oh dear. Now we can't log anything further. */
\r
577 HeapFree(GetProcessHeap(), 0, logger);
\r
578 CloseHandle(logger->read_handle);
\r
579 CloseHandle(logger->write_handle);
\r
583 /* Resume writing after the newline. */
\r
584 address = (void *) ((char *) address + i);
\r
591 /* Write a BOM to the new file. */
\r
592 if (! charsize) charsize = guess_charsize(address, in);
\r
593 if (charsize == sizeof(wchar_t)) write_bom(logger, &out);
\r
594 size += (__int64) out;
\r
597 /* Write the data, if any. */
\r
598 if (! in) continue;
\r
600 ret = try_write(logger, address, in, &out, &complained);
\r
601 size += (__int64) out;
\r
603 HeapFree(GetProcessHeap(), 0, logger);
\r
604 CloseHandle(logger->read_handle);
\r
605 CloseHandle(logger->write_handle);
\r
610 HeapFree(GetProcessHeap(), 0, logger);
\r
611 CloseHandle(logger->read_handle);
\r
612 CloseHandle(logger->write_handle);
\r