FreeRDP
persistent.c
1 
20 #include <freerdp/config.h>
21 
22 #include <winpr/crt.h>
23 #include <winpr/stream.h>
24 #include <winpr/assert.h>
25 
26 #include <freerdp/freerdp.h>
27 #include <freerdp/constants.h>
28 
29 #include <freerdp/cache/persistent.h>
30 
31 struct rdp_persistent_cache
32 {
33  FILE* fp;
34  BOOL write;
35  int version;
36  int count;
37  char* filename;
38  BYTE* bmpData;
39  UINT32 bmpSize;
40 };
41 
42 static const char sig_str[] = "RDP8bmp";
43 
44 int persistent_cache_get_version(rdpPersistentCache* persistent)
45 {
46  WINPR_ASSERT(persistent);
47  return persistent->version;
48 }
49 
50 int persistent_cache_get_count(rdpPersistentCache* persistent)
51 {
52  WINPR_ASSERT(persistent);
53  return persistent->count;
54 }
55 
56 static int persistent_cache_read_entry_v2(rdpPersistentCache* persistent,
58 {
59  PERSISTENT_CACHE_ENTRY_V2 entry2 = { 0 };
60 
61  WINPR_ASSERT(persistent);
62  WINPR_ASSERT(entry);
63 
64  if (fread((void*)&entry2, sizeof(entry2), 1, persistent->fp) != 1)
65  return -1;
66 
67  entry->key64 = entry2.key64;
68  entry->width = entry2.width;
69  entry->height = entry2.height;
70  entry->size = entry2.width * entry2.height * 4;
71  entry->flags = entry2.flags;
72 
73  entry->data = persistent->bmpData;
74 
75  if (fread((void*)entry->data, 0x4000, 1, persistent->fp) != 1)
76  return -1;
77 
78  return 1;
79 }
80 
81 static int persistent_cache_write_entry_v2(rdpPersistentCache* persistent,
82  const PERSISTENT_CACHE_ENTRY* entry)
83 {
84  PERSISTENT_CACHE_ENTRY_V2 entry2 = { 0 };
85 
86  WINPR_ASSERT(persistent);
87  WINPR_ASSERT(entry);
88  entry2.key64 = entry->key64;
89  entry2.width = entry->width;
90  entry2.height = entry->height;
91  entry2.size = entry->size;
92  entry2.flags = entry->flags;
93 
94  if (!entry2.flags)
95  entry2.flags = 0x00000011;
96 
97  if (fwrite(&entry2, sizeof(entry2), 1, persistent->fp) != 1)
98  return -1;
99 
100  if (fwrite(entry->data, entry->size, 1, persistent->fp) != 1)
101  return -1;
102 
103  if (0x4000 > entry->size)
104  {
105  const size_t padding = 0x4000 - entry->size;
106 
107  if (fwrite(persistent->bmpData, padding, 1, persistent->fp) != 1)
108  return -1;
109  }
110 
111  persistent->count++;
112 
113  return 1;
114 }
115 
116 static int persistent_cache_read_v2(rdpPersistentCache* persistent)
117 {
118  WINPR_ASSERT(persistent);
119  while (1)
120  {
121  PERSISTENT_CACHE_ENTRY_V2 entry = { 0 };
122 
123  if (fread((void*)&entry, sizeof(entry), 1, persistent->fp) != 1)
124  break;
125 
126  if (fseek(persistent->fp, 0x4000, SEEK_CUR) != 0)
127  break;
128 
129  persistent->count++;
130  }
131 
132  return 1;
133 }
134 
135 static int persistent_cache_read_entry_v3(rdpPersistentCache* persistent,
136  PERSISTENT_CACHE_ENTRY* entry)
137 {
138  PERSISTENT_CACHE_ENTRY_V3 entry3 = { 0 };
139 
140  WINPR_ASSERT(persistent);
141  WINPR_ASSERT(entry);
142 
143  if (fread(&entry3, sizeof(entry3), 1, persistent->fp) != 1)
144  return -1;
145 
146  entry->key64 = entry3.key64;
147  entry->width = entry3.width;
148  entry->height = entry3.height;
149  const UINT64 size = 4ull * entry3.width * entry3.height;
150  if (size > UINT32_MAX)
151  return -1;
152  entry->size = (UINT32)size;
153  entry->flags = 0;
154 
155  if (entry->size > persistent->bmpSize)
156  {
157  persistent->bmpSize = entry->size;
158  BYTE* bmpData = (BYTE*)winpr_aligned_recalloc(persistent->bmpData, persistent->bmpSize,
159  sizeof(BYTE), 32);
160 
161  if (!bmpData)
162  return -1;
163 
164  persistent->bmpData = bmpData;
165  }
166 
167  entry->data = persistent->bmpData;
168 
169  if (fread((void*)entry->data, entry->size, 1, persistent->fp) != 1)
170  return -1;
171 
172  return 1;
173 }
174 
175 static int persistent_cache_write_entry_v3(rdpPersistentCache* persistent,
176  const PERSISTENT_CACHE_ENTRY* entry)
177 {
178  PERSISTENT_CACHE_ENTRY_V3 entry3 = { 0 };
179 
180  WINPR_ASSERT(persistent);
181  WINPR_ASSERT(entry);
182 
183  entry3.key64 = entry->key64;
184  entry3.width = entry->width;
185  entry3.height = entry->height;
186 
187  if (fwrite((void*)&entry3, sizeof(entry3), 1, persistent->fp) != 1)
188  return -1;
189 
190  if (fwrite((void*)entry->data, entry->size, 1, persistent->fp) != 1)
191  return -1;
192 
193  persistent->count++;
194 
195  return 1;
196 }
197 
198 static int persistent_cache_read_v3(rdpPersistentCache* persistent)
199 {
200  WINPR_ASSERT(persistent);
201  while (1)
202  {
203  PERSISTENT_CACHE_ENTRY_V3 entry = { 0 };
204 
205  if (fread((void*)&entry, sizeof(entry), 1, persistent->fp) != 1)
206  break;
207 
208  if (_fseeki64(persistent->fp, (4LL * entry.width * entry.height), SEEK_CUR) != 0)
209  break;
210 
211  persistent->count++;
212  }
213 
214  return 1;
215 }
216 
217 int persistent_cache_read_entry(rdpPersistentCache* persistent, PERSISTENT_CACHE_ENTRY* entry)
218 {
219  WINPR_ASSERT(persistent);
220  WINPR_ASSERT(entry);
221 
222  if (persistent->version == 3)
223  return persistent_cache_read_entry_v3(persistent, entry);
224  else if (persistent->version == 2)
225  return persistent_cache_read_entry_v2(persistent, entry);
226 
227  return -1;
228 }
229 
230 int persistent_cache_write_entry(rdpPersistentCache* persistent,
231  const PERSISTENT_CACHE_ENTRY* entry)
232 {
233  WINPR_ASSERT(persistent);
234  WINPR_ASSERT(entry);
235 
236  if (persistent->version == 3)
237  return persistent_cache_write_entry_v3(persistent, entry);
238  else if (persistent->version == 2)
239  return persistent_cache_write_entry_v2(persistent, entry);
240 
241  return -1;
242 }
243 
244 static int persistent_cache_open_read(rdpPersistentCache* persistent)
245 {
246  BYTE sig[8] = { 0 };
247  int status = 1;
248  long offset = 0;
249 
250  WINPR_ASSERT(persistent);
251  persistent->fp = winpr_fopen(persistent->filename, "rb");
252 
253  if (!persistent->fp)
254  return -1;
255 
256  if (fread(sig, 8, 1, persistent->fp) != 1)
257  return -1;
258 
259  if (memcmp(sig, sig_str, sizeof(sig_str)) == 0)
260  persistent->version = 3;
261  else
262  persistent->version = 2;
263 
264  (void)fseek(persistent->fp, 0, SEEK_SET);
265 
266  if (persistent->version == 3)
267  {
269 
270  if (fread(&header, sizeof(header), 1, persistent->fp) != 1)
271  return -1;
272 
273  status = persistent_cache_read_v3(persistent);
274  offset = sizeof(header);
275  }
276  else
277  {
278  status = persistent_cache_read_v2(persistent);
279  offset = 0;
280  }
281 
282  (void)fseek(persistent->fp, offset, SEEK_SET);
283 
284  return status;
285 }
286 
287 static int persistent_cache_open_write(rdpPersistentCache* persistent)
288 {
289  WINPR_ASSERT(persistent);
290 
291  persistent->fp = winpr_fopen(persistent->filename, "w+b");
292 
293  if (!persistent->fp)
294  return -1;
295 
296  if (persistent->version == 3)
297  {
298  PERSISTENT_CACHE_HEADER_V3 header = { 0 };
299  memcpy(header.sig, sig_str, MIN(sizeof(header.sig), sizeof(sig_str)));
300  header.flags = 0x00000006;
301 
302  if (fwrite(&header, sizeof(header), 1, persistent->fp) != 1)
303  return -1;
304  }
305 
306  ZeroMemory(persistent->bmpData, persistent->bmpSize);
307 
308  return 1;
309 }
310 
311 int persistent_cache_open(rdpPersistentCache* persistent, const char* filename, BOOL write,
312  UINT32 version)
313 {
314  WINPR_ASSERT(persistent);
315  WINPR_ASSERT(filename);
316  persistent->write = write;
317 
318  persistent->filename = _strdup(filename);
319 
320  if (!persistent->filename)
321  return -1;
322 
323  if (persistent->write)
324  {
325  WINPR_ASSERT(version <= INT32_MAX);
326  persistent->version = (int)version;
327  return persistent_cache_open_write(persistent);
328  }
329 
330  return persistent_cache_open_read(persistent);
331 }
332 
333 int persistent_cache_close(rdpPersistentCache* persistent)
334 {
335  WINPR_ASSERT(persistent);
336  if (persistent->fp)
337  {
338  (void)fclose(persistent->fp);
339  persistent->fp = NULL;
340  }
341 
342  return 1;
343 }
344 
345 rdpPersistentCache* persistent_cache_new(void)
346 {
347  rdpPersistentCache* persistent = calloc(1, sizeof(rdpPersistentCache));
348 
349  if (!persistent)
350  return NULL;
351 
352  persistent->bmpSize = 0x4000;
353  persistent->bmpData = calloc(1, persistent->bmpSize);
354 
355  if (!persistent->bmpData)
356  {
357  free(persistent);
358  return NULL;
359  }
360 
361  return persistent;
362 }
363 
364 void persistent_cache_free(rdpPersistentCache* persistent)
365 {
366  if (!persistent)
367  return;
368 
369  persistent_cache_close(persistent);
370 
371  free(persistent->filename);
372 
373  winpr_aligned_free(persistent->bmpData);
374 
375  free(persistent);
376 }
Definition: persistent.h:59
Definition: persistent.h:50
Definition: persistent.h:70