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 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23 
24 #include "FileAppender.h"
25 #include "Message.h"
26 
27 #include <winpr/crt.h>
28 #include <winpr/environment.h>
29 #include <winpr/file.h>
30 #include <winpr/path.h>
31 
32 struct _wLogFileAppender
33 {
34 	WLOG_APPENDER_COMMON();
35 
36 	char* FileName;
37 	char* FilePath;
38 	char* FullFileName;
39 	FILE* FileDescriptor;
40 };
41 typedef struct _wLogFileAppender wLogFileAppender;
42 
WLog_FileAppender_SetOutputFileName(wLogFileAppender * appender,const char * filename)43 static BOOL WLog_FileAppender_SetOutputFileName(wLogFileAppender* appender, const char* filename)
44 {
45 	appender->FileName = _strdup(filename);
46 
47 	if (!appender->FileName)
48 		return FALSE;
49 
50 	return TRUE;
51 }
52 
WLog_FileAppender_SetOutputFilePath(wLogFileAppender * appender,const char * filepath)53 static BOOL WLog_FileAppender_SetOutputFilePath(wLogFileAppender* appender, const char* filepath)
54 {
55 	appender->FilePath = _strdup(filepath);
56 
57 	if (!appender->FilePath)
58 		return FALSE;
59 
60 	return TRUE;
61 }
62 
WLog_FileAppender_Open(wLog * log,wLogAppender * appender)63 static BOOL WLog_FileAppender_Open(wLog* log, wLogAppender* appender)
64 {
65 	wLogFileAppender* fileAppender;
66 
67 	if (!log || !appender)
68 		return FALSE;
69 
70 	fileAppender = (wLogFileAppender*)appender;
71 
72 	if (!fileAppender->FilePath)
73 	{
74 		fileAppender->FilePath = GetKnownSubPath(KNOWN_PATH_TEMP, "wlog");
75 
76 		if (!fileAppender->FilePath)
77 			return FALSE;
78 	}
79 
80 	if (!fileAppender->FileName)
81 	{
82 		fileAppender->FileName = (char*)malloc(MAX_PATH);
83 
84 		if (!fileAppender->FileName)
85 			return FALSE;
86 
87 		sprintf_s(fileAppender->FileName, MAX_PATH, "%" PRIu32 ".log", GetCurrentProcessId());
88 	}
89 
90 	if (!fileAppender->FullFileName)
91 	{
92 		fileAppender->FullFileName =
93 		    GetCombinedPath(fileAppender->FilePath, fileAppender->FileName);
94 
95 		if (!fileAppender->FullFileName)
96 			return FALSE;
97 	}
98 
99 	if (!winpr_PathFileExists(fileAppender->FilePath))
100 	{
101 		if (!winpr_PathMakePath(fileAppender->FilePath, 0))
102 			return FALSE;
103 
104 		UnixChangeFileMode(fileAppender->FilePath, 0xFFFF);
105 	}
106 
107 	fileAppender->FileDescriptor = winpr_fopen(fileAppender->FullFileName, "a+");
108 
109 	if (!fileAppender->FileDescriptor)
110 		return FALSE;
111 
112 	return TRUE;
113 }
114 
WLog_FileAppender_Close(wLog * log,wLogAppender * appender)115 static BOOL WLog_FileAppender_Close(wLog* log, wLogAppender* appender)
116 {
117 	wLogFileAppender* fileAppender;
118 
119 	if (!log || !appender)
120 		return FALSE;
121 
122 	fileAppender = (wLogFileAppender*)appender;
123 
124 	if (!fileAppender->FileDescriptor)
125 		return TRUE;
126 
127 	fclose(fileAppender->FileDescriptor);
128 	fileAppender->FileDescriptor = NULL;
129 	return TRUE;
130 }
131 
WLog_FileAppender_WriteMessage(wLog * log,wLogAppender * appender,wLogMessage * message)132 static BOOL WLog_FileAppender_WriteMessage(wLog* log, wLogAppender* appender, wLogMessage* message)
133 {
134 	FILE* fp;
135 	char prefix[WLOG_MAX_PREFIX_SIZE];
136 	wLogFileAppender* fileAppender;
137 
138 	if (!log || !appender || !message)
139 		return FALSE;
140 
141 	fileAppender = (wLogFileAppender*)appender;
142 	fp = fileAppender->FileDescriptor;
143 
144 	if (!fp)
145 		return FALSE;
146 
147 	message->PrefixString = prefix;
148 	WLog_Layout_GetMessagePrefix(log, appender->Layout, message);
149 	fprintf(fp, "%s%s\n", message->PrefixString, message->TextString);
150 	fflush(fp); /* slow! */
151 	return TRUE;
152 }
153 
154 static int g_DataId = 0;
155 
WLog_FileAppender_WriteDataMessage(wLog * log,wLogAppender * appender,wLogMessage * message)156 static BOOL WLog_FileAppender_WriteDataMessage(wLog* log, wLogAppender* appender,
157                                                wLogMessage* message)
158 {
159 	int DataId;
160 	char* FullFileName;
161 
162 	if (!log || !appender || !message)
163 		return FALSE;
164 
165 	DataId = g_DataId++;
166 	FullFileName = WLog_Message_GetOutputFileName(DataId, "dat");
167 	WLog_DataMessage_Write(FullFileName, message->Data, message->Length);
168 	free(FullFileName);
169 	return TRUE;
170 }
171 
172 static int g_ImageId = 0;
173 
WLog_FileAppender_WriteImageMessage(wLog * log,wLogAppender * appender,wLogMessage * message)174 static BOOL WLog_FileAppender_WriteImageMessage(wLog* log, wLogAppender* appender,
175                                                 wLogMessage* message)
176 {
177 	int ImageId;
178 	char* FullFileName;
179 
180 	if (!log || !appender || !message)
181 		return FALSE;
182 
183 	ImageId = g_ImageId++;
184 	FullFileName = WLog_Message_GetOutputFileName(ImageId, "bmp");
185 	WLog_ImageMessage_Write(FullFileName, message->ImageData, message->ImageWidth,
186 	                        message->ImageHeight, message->ImageBpp);
187 	free(FullFileName);
188 	return TRUE;
189 }
190 
WLog_FileAppender_Set(wLogAppender * appender,const char * setting,void * value)191 static BOOL WLog_FileAppender_Set(wLogAppender* appender, const char* setting, void* value)
192 {
193 	wLogFileAppender* fileAppender = (wLogFileAppender*)appender;
194 
195 	/* Just check the value string is not empty */
196 	if (!value || (strnlen(value, 2) == 0))
197 		return FALSE;
198 
199 	if (!strcmp("outputfilename", setting))
200 		return WLog_FileAppender_SetOutputFileName(fileAppender, (const char*)value);
201 	else if (!strcmp("outputfilepath", setting))
202 		return WLog_FileAppender_SetOutputFilePath(fileAppender, (const char*)value);
203 	else
204 		return FALSE;
205 
206 	return TRUE;
207 }
208 
WLog_FileAppender_Free(wLogAppender * appender)209 static void WLog_FileAppender_Free(wLogAppender* appender)
210 {
211 	wLogFileAppender* fileAppender = NULL;
212 
213 	if (appender)
214 	{
215 		fileAppender = (wLogFileAppender*)appender;
216 		free(fileAppender->FileName);
217 		free(fileAppender->FilePath);
218 		free(fileAppender->FullFileName);
219 		free(fileAppender);
220 	}
221 }
222 
WLog_FileAppender_New(wLog * log)223 wLogAppender* WLog_FileAppender_New(wLog* log)
224 {
225 	LPSTR env;
226 	LPCSTR name;
227 	DWORD nSize;
228 	wLogFileAppender* FileAppender;
229 	FileAppender = (wLogFileAppender*)calloc(1, sizeof(wLogFileAppender));
230 
231 	if (!FileAppender)
232 		return NULL;
233 
234 	FileAppender->Type = WLOG_APPENDER_FILE;
235 	FileAppender->Open = WLog_FileAppender_Open;
236 	FileAppender->Close = WLog_FileAppender_Close;
237 	FileAppender->WriteMessage = WLog_FileAppender_WriteMessage;
238 	FileAppender->WriteDataMessage = WLog_FileAppender_WriteDataMessage;
239 	FileAppender->WriteImageMessage = WLog_FileAppender_WriteImageMessage;
240 	FileAppender->Free = WLog_FileAppender_Free;
241 	FileAppender->Set = WLog_FileAppender_Set;
242 	name = "WLOG_FILEAPPENDER_OUTPUT_FILE_PATH";
243 	nSize = GetEnvironmentVariableA(name, NULL, 0);
244 
245 	if (nSize)
246 	{
247 		BOOL status;
248 		env = (LPSTR)malloc(nSize);
249 
250 		if (!env)
251 			goto error_free;
252 
253 		if (GetEnvironmentVariableA(name, env, nSize) != nSize - 1)
254 		{
255 			free(env);
256 			goto error_free;
257 		}
258 
259 		status = WLog_FileAppender_SetOutputFilePath(FileAppender, env);
260 		free(env);
261 
262 		if (!status)
263 			goto error_free;
264 	}
265 
266 	name = "WLOG_FILEAPPENDER_OUTPUT_FILE_NAME";
267 	nSize = GetEnvironmentVariableA(name, NULL, 0);
268 
269 	if (nSize)
270 	{
271 		BOOL status = FALSE;
272 		env = (LPSTR)malloc(nSize);
273 
274 		if (!env)
275 			goto error_output_file_name;
276 
277 		if (GetEnvironmentVariableA(name, env, nSize) == nSize - 1)
278 			status = WLog_FileAppender_SetOutputFileName(FileAppender, env);
279 		free(env);
280 
281 		if (!status)
282 			goto error_output_file_name;
283 	}
284 
285 	return (wLogAppender*)FileAppender;
286 error_output_file_name:
287 	free(FileAppender->FilePath);
288 error_free:
289 	free(FileAppender);
290 	return NULL;
291 }
292