Coverage Report

Created: 2026-07-30 07:06

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/FreeRDP/winpr/libwinpr/utils/wlog/FileAppender.c
Line
Count
Source
1
/**
2
 * WinPR: Windows Portable Runtime
3
 * WinPR Logger
4
 *
5
 * Copyright 2013 Marc-Andre Moreau <marcandre.moreau@gmail.com>
6
 *
7
 * Licensed under the Apache License, Version 2.0 (the "License");
8
 * you may not use this file except in compliance with the License.
9
 * You may obtain a copy of the License at
10
 *
11
 *     http://www.apache.org/licenses/LICENSE-2.0
12
 *
13
 * Unless required by applicable law or agreed to in writing, software
14
 * distributed under the License is distributed on an "AS IS" BASIS,
15
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
 * See the License for the specific language governing permissions and
17
 * limitations under the License.
18
 */
19
20
#include <winpr/config.h>
21
22
#include "FileAppender.h"
23
#include "Message.h"
24
25
#include <winpr/crt.h>
26
#include <winpr/environment.h>
27
#include <winpr/file.h>
28
#include <winpr/path.h>
29
30
typedef struct
31
{
32
  wLogAppender common;
33
34
  char* FileName;
35
  char* FilePath;
36
  char* FullFileName;
37
  FILE* FileDescriptor;
38
} wLogFileAppender;
39
40
static BOOL WLog_FileAppender_SetOutputFileName(wLogFileAppender* appender, const char* filename)
41
0
{
42
0
  WINPR_ASSERT(appender);
43
0
  WINPR_ASSERT(filename);
44
45
0
  appender->FileName = _strdup(filename);
46
47
0
  return appender->FileName != nullptr;
48
0
}
49
50
static BOOL WLog_FileAppender_SetOutputFilePath(wLogFileAppender* appender, const char* filepath)
51
0
{
52
0
  appender->FilePath = _strdup(filepath);
53
54
0
  return appender->FilePath != nullptr;
55
0
}
56
57
static BOOL WLog_FileAppender_Open(wLog* log, wLogAppender* appender)
58
0
{
59
0
  wLogFileAppender* fileAppender = nullptr;
60
61
0
  if (!log || !appender)
62
0
    return FALSE;
63
64
0
  fileAppender = (wLogFileAppender*)appender;
65
66
0
  if (!fileAppender->FilePath)
67
0
  {
68
0
    fileAppender->FilePath = GetKnownSubPath(KNOWN_PATH_TEMP, "wlog");
69
70
0
    if (!fileAppender->FilePath)
71
0
      return FALSE;
72
0
  }
73
74
0
  if (!fileAppender->FileName)
75
0
  {
76
0
    fileAppender->FileName = (char*)malloc(MAX_PATH);
77
78
0
    if (!fileAppender->FileName)
79
0
      return FALSE;
80
81
0
    (void)sprintf_s(fileAppender->FileName, MAX_PATH, "%" PRIu32 ".log", GetCurrentProcessId());
82
0
  }
83
84
0
  if (!fileAppender->FullFileName)
85
0
  {
86
0
    fileAppender->FullFileName =
87
0
        GetCombinedPath(fileAppender->FilePath, fileAppender->FileName);
88
89
0
    if (!fileAppender->FullFileName)
90
0
      return FALSE;
91
0
  }
92
93
0
  if (!winpr_PathFileExists(fileAppender->FilePath))
94
0
  {
95
0
    if (!winpr_PathMakePath(fileAppender->FilePath, nullptr))
96
0
      return FALSE;
97
98
0
    UnixChangeFileMode(fileAppender->FilePath, 0xFFFF);
99
0
  }
100
101
0
  fileAppender->FileDescriptor = winpr_fopen(fileAppender->FullFileName, "a+");
102
103
0
  return fileAppender->FileDescriptor != nullptr;
104
0
}
105
106
static BOOL WLog_FileAppender_Close(wLog* log, wLogAppender* appender)
107
0
{
108
0
  wLogFileAppender* fileAppender = nullptr;
109
110
0
  if (!log || !appender)
111
0
    return FALSE;
112
113
0
  fileAppender = (wLogFileAppender*)appender;
114
115
0
  if (!fileAppender->FileDescriptor)
116
0
    return TRUE;
117
118
0
  (void)fclose(fileAppender->FileDescriptor);
119
0
  fileAppender->FileDescriptor = nullptr;
120
0
  return TRUE;
121
0
}
122
123
static BOOL WLog_FileAppender_WriteMessage(wLog* log, wLogAppender* appender,
124
                                           const wLogMessage* cmessage)
125
0
{
126
0
  if (!log || !appender || !cmessage)
127
0
    return FALSE;
128
129
0
  wLogFileAppender* fileAppender = (wLogFileAppender*)appender;
130
0
  FILE* fp = fileAppender->FileDescriptor;
131
132
0
  if (!fp)
133
0
    return FALSE;
134
135
0
  char prefix[WLOG_MAX_PREFIX_SIZE] = WINPR_C_ARRAY_INIT;
136
0
  WLog_Layout_GetMessagePrefix(log, appender->Layout, cmessage, prefix, sizeof(prefix));
137
0
  (void)fprintf(fp, "%s%s\n", prefix, cmessage->TextString);
138
0
  (void)fflush(fp); /* slow! */
139
0
  return TRUE;
140
0
}
141
142
static int g_DataId = 0;
143
144
static BOOL WLog_FileAppender_WriteDataMessage(wLog* log, wLogAppender* appender,
145
                                               const wLogMessage* message)
146
0
{
147
0
  if (!log || !appender || !message)
148
0
    return FALSE;
149
150
0
  const int DataId = g_DataId++;
151
0
  char* FullFileName = WLog_Message_GetOutputFileName(DataId, "dat");
152
0
  WLog_DataMessage_Write(FullFileName, message->Data, message->Length);
153
0
  free(FullFileName);
154
0
  return TRUE;
155
0
}
156
157
static int g_ImageId = 0;
158
159
static BOOL WLog_FileAppender_WriteImageMessage(wLog* log, wLogAppender* appender,
160
                                                const wLogMessage* message)
161
0
{
162
0
  if (!log || !appender || !message)
163
0
    return FALSE;
164
165
0
  const int ImageId = g_ImageId++;
166
0
  char* FullFileName = WLog_Message_GetOutputFileName(ImageId, "bmp");
167
0
  WLog_ImageMessage_Write(FullFileName, message->ImageData, message->ImageWidth,
168
0
                          message->ImageHeight, message->ImageBpp);
169
0
  free(FullFileName);
170
0
  return TRUE;
171
0
}
172
173
static BOOL WLog_FileAppender_Set(wLogAppender* appender, const char* setting, void* value)
174
0
{
175
0
  wLogFileAppender* fileAppender = (wLogFileAppender*)appender;
176
177
  /* Just check the value string is not empty */
178
0
  if (!value || (strnlen(value, 2) == 0))
179
0
    return FALSE;
180
181
0
  if (!strcmp("outputfilename", setting))
182
0
    return WLog_FileAppender_SetOutputFileName(fileAppender, (const char*)value);
183
184
0
  if (!strcmp("outputfilepath", setting))
185
0
    return WLog_FileAppender_SetOutputFilePath(fileAppender, (const char*)value);
186
187
0
  return FALSE;
188
0
}
189
190
static void WLog_FileAppender_Free(wLogAppender* appender)
191
0
{
192
0
  wLogFileAppender* fileAppender = nullptr;
193
194
0
  if (appender)
195
0
  {
196
0
    fileAppender = (wLogFileAppender*)appender;
197
0
    free(fileAppender->FileName);
198
0
    free(fileAppender->FilePath);
199
0
    free(fileAppender->FullFileName);
200
0
    free(fileAppender);
201
0
  }
202
0
}
203
204
wLogAppender* WLog_FileAppender_New(WINPR_ATTR_UNUSED wLog* log)
205
0
{
206
0
  LPSTR env = nullptr;
207
0
  LPCSTR name = nullptr;
208
0
  DWORD nSize = 0;
209
0
  wLogFileAppender* FileAppender = nullptr;
210
0
  FileAppender = (wLogFileAppender*)calloc(1, sizeof(wLogFileAppender));
211
212
0
  if (!FileAppender)
213
0
    return nullptr;
214
215
0
  FileAppender->common.Type = WLOG_APPENDER_FILE;
216
0
  FileAppender->common.Open = WLog_FileAppender_Open;
217
0
  FileAppender->common.Close = WLog_FileAppender_Close;
218
0
  FileAppender->common.WriteMessage = WLog_FileAppender_WriteMessage;
219
0
  FileAppender->common.WriteDataMessage = WLog_FileAppender_WriteDataMessage;
220
0
  FileAppender->common.WriteImageMessage = WLog_FileAppender_WriteImageMessage;
221
0
  FileAppender->common.Free = WLog_FileAppender_Free;
222
0
  FileAppender->common.Set = WLog_FileAppender_Set;
223
0
  name = "WLOG_FILEAPPENDER_OUTPUT_FILE_PATH";
224
0
  nSize = GetEnvironmentVariableA(name, nullptr, 0);
225
226
0
  if (nSize)
227
0
  {
228
0
    BOOL status = 0;
229
0
    env = (LPSTR)malloc(nSize);
230
231
0
    if (!env)
232
0
      goto error_free;
233
234
0
    if (GetEnvironmentVariableA(name, env, nSize) != nSize - 1)
235
0
    {
236
0
      free(env);
237
0
      goto error_free;
238
0
    }
239
240
0
    status = WLog_FileAppender_SetOutputFilePath(FileAppender, env);
241
0
    free(env);
242
243
0
    if (!status)
244
0
      goto error_free;
245
0
  }
246
247
0
  name = "WLOG_FILEAPPENDER_OUTPUT_FILE_NAME";
248
0
  nSize = GetEnvironmentVariableA(name, nullptr, 0);
249
250
0
  if (nSize)
251
0
  {
252
0
    BOOL status = FALSE;
253
0
    env = (LPSTR)malloc(nSize);
254
255
0
    if (!env)
256
0
      goto error_output_file_name;
257
258
0
    if (GetEnvironmentVariableA(name, env, nSize) == nSize - 1)
259
0
      status = WLog_FileAppender_SetOutputFileName(FileAppender, env);
260
0
    free(env);
261
262
0
    if (!status)
263
0
      goto error_output_file_name;
264
0
  }
265
266
0
  return (wLogAppender*)FileAppender;
267
0
error_output_file_name:
268
0
  free(FileAppender->FilePath);
269
0
error_free:
270
0
  free(FileAppender);
271
0
  return nullptr;
272
0
}