Coverage Report

Created: 2024-05-20 06:11

/src/FreeRDP/channels/drive/client/drive_file.c
Line
Count
Source (jump to first uncovered line)
1
/**
2
 * FreeRDP: A Remote Desktop Protocol Implementation
3
 * File System Virtual Channel
4
 *
5
 * Copyright 2010-2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
6
 * Copyright 2010-2011 Vic Lee
7
 * Copyright 2012 Gerald Richter
8
 * Copyright 2015 Thincast Technologies GmbH
9
 * Copyright 2015 DI (FH) Martin Haimberger <martin.haimberger@thincast.com>
10
 * Copyright 2016 Inuvika Inc.
11
 * Copyright 2016 David PHAM-VAN <d.phamvan@inuvika.com>
12
 * Copyright 2017 Armin Novak <armin.novak@thincast.com>
13
 * Copyright 2017 Thincast Technologies GmbH
14
 *
15
 * Licensed under the Apache License, Version 2.0 (the "License");
16
 * you may not use this file except in compliance with the License.
17
 * You may obtain a copy of the License at
18
 *
19
 *     http://www.apache.org/licenses/LICENSE-2.0
20
 *
21
 * Unless required by applicable law or agreed to in writing, software
22
 * distributed under the License is distributed on an "AS IS" BASIS,
23
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
24
 * See the License for the specific language governing permissions and
25
 * limitations under the License.
26
 */
27
28
#include <freerdp/config.h>
29
30
#include <errno.h>
31
#include <stdio.h>
32
#include <stdlib.h>
33
#include <string.h>
34
#include <time.h>
35
36
#include <winpr/wtypes.h>
37
#include <winpr/crt.h>
38
#include <winpr/string.h>
39
#include <winpr/path.h>
40
#include <winpr/file.h>
41
#include <winpr/stream.h>
42
43
#include <freerdp/channels/rdpdr.h>
44
45
#include "drive_file.h"
46
47
#ifdef WITH_DEBUG_RDPDR
48
#define DEBUG_WSTR(msg, wstr)                              \
49
  do                                                     \
50
  {                                                      \
51
    char lpstr[1024] = { 0 };                          \
52
    ConvertWCharToUtf8(wstr, lpstr, ARRAYSIZE(lpstr)); \
53
    WLog_DBG(TAG, msg, lpstr);                         \
54
  } while (0)
55
#else
56
#define DEBUG_WSTR(msg, wstr) \
57
0
  do                        \
58
0
  {                         \
59
0
  } while (0)
60
#endif
61
62
static BOOL drive_file_fix_path(WCHAR* path, size_t length)
63
0
{
64
0
  if ((length == 0) || (length > UINT32_MAX))
65
0
    return FALSE;
66
67
0
  WINPR_ASSERT(path);
68
69
0
  for (size_t i = 0; i < length; i++)
70
0
  {
71
0
    if (path[i] == L'\\')
72
0
      path[i] = L'/';
73
0
  }
74
75
#ifdef WIN32
76
77
  if ((length == 3) && (path[1] == L':') && (path[2] == L'/'))
78
    return FALSE;
79
80
#else
81
82
0
  if ((length == 1) && (path[0] == L'/'))
83
0
    return FALSE;
84
85
0
#endif
86
87
0
  if ((length > 0) && (path[length - 1] == L'/'))
88
0
    path[length - 1] = L'\0';
89
90
0
  return TRUE;
91
0
}
92
93
static WCHAR* drive_file_combine_fullpath(const WCHAR* base_path, const WCHAR* path,
94
                                          size_t PathWCharLength)
95
0
{
96
0
  BOOL ok = FALSE;
97
0
  WCHAR* fullpath = NULL;
98
0
  size_t length = 0;
99
100
0
  if (!base_path || (!path && (PathWCharLength > 0)))
101
0
    goto fail;
102
103
0
  const size_t base_path_length = _wcsnlen(base_path, MAX_PATH);
104
0
  length = base_path_length + PathWCharLength + 1;
105
0
  fullpath = (WCHAR*)calloc(length, sizeof(WCHAR));
106
107
0
  if (!fullpath)
108
0
    goto fail;
109
110
0
  CopyMemory(fullpath, base_path, base_path_length * sizeof(WCHAR));
111
0
  if (path)
112
0
    CopyMemory(&fullpath[base_path_length], path, PathWCharLength * sizeof(WCHAR));
113
114
0
  if (!drive_file_fix_path(fullpath, length))
115
0
    goto fail;
116
117
  /* Ensure the path does not contain sequences like '..' */
118
0
  WCHAR dotdotbuffer[6] = { 0 };
119
0
  const WCHAR* dotdot = InitializeConstWCharFromUtf8("..", dotdotbuffer, ARRAYSIZE(dotdotbuffer));
120
0
  if (_wcsstr(&fullpath[base_path_length], dotdot))
121
0
  {
122
0
    char abuffer[MAX_PATH] = { 0 };
123
0
    ConvertWCharToUtf8(&fullpath[base_path_length], abuffer, ARRAYSIZE(abuffer));
124
125
0
    WLog_WARN(TAG, "[rdpdr] received invalid file path '%s' from server, aborting!",
126
0
              &abuffer[base_path_length]);
127
0
    goto fail;
128
0
  }
129
130
0
  ok = TRUE;
131
0
fail:
132
0
  if (!ok)
133
0
  {
134
0
    free(fullpath);
135
0
    fullpath = NULL;
136
0
  }
137
0
  return fullpath;
138
0
}
139
140
static BOOL drive_file_set_fullpath(DRIVE_FILE* file, WCHAR* fullpath)
141
0
{
142
0
  if (!file || !fullpath)
143
0
    return FALSE;
144
145
0
  const size_t len = _wcslen(fullpath);
146
0
  free(file->fullpath);
147
0
  file->fullpath = NULL;
148
149
0
  if (len == 0)
150
0
    return TRUE;
151
152
0
  file->fullpath = fullpath;
153
154
0
  const WCHAR sep[] = { PathGetSeparatorW(PATH_STYLE_NATIVE), '\0' };
155
0
  WCHAR* filename = _wcsrchr(file->fullpath, *sep);
156
0
  if (filename && _wcsncmp(filename, sep, ARRAYSIZE(sep)) == 0)
157
0
    *filename = '\0';
158
159
0
  return TRUE;
160
0
}
161
162
static BOOL drive_file_init(DRIVE_FILE* file)
163
0
{
164
0
  UINT CreateDisposition = 0;
165
0
  DWORD dwAttr = GetFileAttributesW(file->fullpath);
166
167
0
  if (dwAttr != INVALID_FILE_ATTRIBUTES)
168
0
  {
169
    /* The file exists */
170
0
    file->is_dir = (dwAttr & FILE_ATTRIBUTE_DIRECTORY) != 0;
171
172
0
    if (file->is_dir)
173
0
    {
174
0
      if (file->CreateDisposition == FILE_CREATE)
175
0
      {
176
0
        SetLastError(ERROR_ALREADY_EXISTS);
177
0
        return FALSE;
178
0
      }
179
180
0
      if (file->CreateOptions & FILE_NON_DIRECTORY_FILE)
181
0
      {
182
0
        SetLastError(ERROR_ACCESS_DENIED);
183
0
        return FALSE;
184
0
      }
185
186
0
      return TRUE;
187
0
    }
188
0
    else
189
0
    {
190
0
      if (file->CreateOptions & FILE_DIRECTORY_FILE)
191
0
      {
192
0
        SetLastError(ERROR_DIRECTORY);
193
0
        return FALSE;
194
0
      }
195
0
    }
196
0
  }
197
0
  else
198
0
  {
199
0
    file->is_dir = ((file->CreateOptions & FILE_DIRECTORY_FILE) ? TRUE : FALSE);
200
201
0
    if (file->is_dir)
202
0
    {
203
      /* Should only create the directory if the disposition allows for it */
204
0
      if ((file->CreateDisposition == FILE_OPEN_IF) ||
205
0
          (file->CreateDisposition == FILE_CREATE))
206
0
      {
207
0
        if (CreateDirectoryW(file->fullpath, NULL) != 0)
208
0
        {
209
0
          return TRUE;
210
0
        }
211
0
      }
212
213
0
      SetLastError(ERROR_FILE_NOT_FOUND);
214
0
      return FALSE;
215
0
    }
216
0
  }
217
218
0
  if (file->file_handle == INVALID_HANDLE_VALUE)
219
0
  {
220
0
    switch (file->CreateDisposition)
221
0
    {
222
0
      case FILE_SUPERSEDE: /* If the file already exists, replace it with the given file. If
223
                              it does not, create the given file. */
224
0
        CreateDisposition = CREATE_ALWAYS;
225
0
        break;
226
227
0
      case FILE_OPEN: /* If the file already exists, open it instead of creating a new file.
228
                         If it does not, fail the request and do not create a new file. */
229
0
        CreateDisposition = OPEN_EXISTING;
230
0
        break;
231
232
0
      case FILE_CREATE: /* If the file already exists, fail the request and do not create or
233
                           open the given file. If it does not, create the given file. */
234
0
        CreateDisposition = CREATE_NEW;
235
0
        break;
236
237
0
      case FILE_OPEN_IF: /* If the file already exists, open it. If it does not, create the
238
                            given file. */
239
0
        CreateDisposition = OPEN_ALWAYS;
240
0
        break;
241
242
0
      case FILE_OVERWRITE: /* If the file already exists, open it and overwrite it. If it does
243
                              not, fail the request. */
244
0
        CreateDisposition = TRUNCATE_EXISTING;
245
0
        break;
246
247
0
      case FILE_OVERWRITE_IF: /* If the file already exists, open it and overwrite it. If it
248
                                 does not, create the given file. */
249
0
        CreateDisposition = CREATE_ALWAYS;
250
0
        break;
251
252
0
      default:
253
0
        break;
254
0
    }
255
256
0
#ifndef WIN32
257
0
    file->SharedAccess = 0;
258
0
#endif
259
0
    file->file_handle = CreateFileW(file->fullpath, file->DesiredAccess, file->SharedAccess,
260
0
                                    NULL, CreateDisposition, file->FileAttributes, NULL);
261
0
  }
262
263
#ifdef WIN32
264
  if (file->file_handle == INVALID_HANDLE_VALUE)
265
  {
266
    /* Get the error message, if any. */
267
    DWORD errorMessageID = GetLastError();
268
269
    if (errorMessageID != 0)
270
    {
271
      LPSTR messageBuffer = NULL;
272
      size_t size =
273
          FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
274
                             FORMAT_MESSAGE_IGNORE_INSERTS,
275
                         NULL, errorMessageID, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
276
                         (LPSTR)&messageBuffer, 0, NULL);
277
      WLog_ERR(TAG, "Error in drive_file_init: %s %s", messageBuffer, file->fullpath);
278
      /* Free the buffer. */
279
      LocalFree(messageBuffer);
280
      /* restore original error code */
281
      SetLastError(errorMessageID);
282
    }
283
  }
284
#endif
285
286
0
  return file->file_handle != INVALID_HANDLE_VALUE;
287
0
}
288
289
DRIVE_FILE* drive_file_new(const WCHAR* base_path, const WCHAR* path, UINT32 PathWCharLength,
290
                           UINT32 id, UINT32 DesiredAccess, UINT32 CreateDisposition,
291
                           UINT32 CreateOptions, UINT32 FileAttributes, UINT32 SharedAccess)
292
0
{
293
0
  DRIVE_FILE* file = NULL;
294
295
0
  if (!base_path || (!path && (PathWCharLength > 0)))
296
0
    return NULL;
297
298
0
  file = (DRIVE_FILE*)calloc(1, sizeof(DRIVE_FILE));
299
300
0
  if (!file)
301
0
  {
302
0
    WLog_ERR(TAG, "calloc failed!");
303
0
    return NULL;
304
0
  }
305
306
0
  file->file_handle = INVALID_HANDLE_VALUE;
307
0
  file->find_handle = INVALID_HANDLE_VALUE;
308
0
  file->id = id;
309
0
  file->basepath = base_path;
310
0
  file->FileAttributes = FileAttributes;
311
0
  file->DesiredAccess = DesiredAccess;
312
0
  file->CreateDisposition = CreateDisposition;
313
0
  file->CreateOptions = CreateOptions;
314
0
  file->SharedAccess = SharedAccess;
315
0
  drive_file_set_fullpath(file, drive_file_combine_fullpath(base_path, path, PathWCharLength));
316
317
0
  if (!drive_file_init(file))
318
0
  {
319
0
    DWORD lastError = GetLastError();
320
0
    drive_file_free(file);
321
0
    SetLastError(lastError);
322
0
    return NULL;
323
0
  }
324
325
0
  return file;
326
0
}
327
328
BOOL drive_file_free(DRIVE_FILE* file)
329
0
{
330
0
  BOOL rc = FALSE;
331
332
0
  if (!file)
333
0
    return FALSE;
334
335
0
  if (file->file_handle != INVALID_HANDLE_VALUE)
336
0
  {
337
0
    CloseHandle(file->file_handle);
338
0
    file->file_handle = INVALID_HANDLE_VALUE;
339
0
  }
340
341
0
  if (file->find_handle != INVALID_HANDLE_VALUE)
342
0
  {
343
0
    FindClose(file->find_handle);
344
0
    file->find_handle = INVALID_HANDLE_VALUE;
345
0
  }
346
347
0
  if (file->delete_pending)
348
0
  {
349
0
    if (file->is_dir)
350
0
    {
351
0
      if (!winpr_RemoveDirectory_RecursiveW(file->fullpath))
352
0
        goto fail;
353
0
    }
354
0
    else if (!DeleteFileW(file->fullpath))
355
0
      goto fail;
356
0
  }
357
358
0
  rc = TRUE;
359
0
fail:
360
0
  DEBUG_WSTR("Free %s", file->fullpath);
361
0
  free(file->fullpath);
362
0
  free(file);
363
0
  return rc;
364
0
}
365
366
BOOL drive_file_seek(DRIVE_FILE* file, UINT64 Offset)
367
0
{
368
0
  LARGE_INTEGER loffset;
369
370
0
  if (!file)
371
0
    return FALSE;
372
373
0
  if (Offset > INT64_MAX)
374
0
    return FALSE;
375
376
0
  loffset.QuadPart = (LONGLONG)Offset;
377
0
  return SetFilePointerEx(file->file_handle, loffset, NULL, FILE_BEGIN);
378
0
}
379
380
BOOL drive_file_read(DRIVE_FILE* file, BYTE* buffer, UINT32* Length)
381
0
{
382
0
  DWORD read = 0;
383
384
0
  if (!file || !buffer || !Length)
385
0
    return FALSE;
386
387
0
  DEBUG_WSTR("Read file %s", file->fullpath);
388
389
0
  if (ReadFile(file->file_handle, buffer, *Length, &read, NULL))
390
0
  {
391
0
    *Length = read;
392
0
    return TRUE;
393
0
  }
394
395
0
  return FALSE;
396
0
}
397
398
BOOL drive_file_write(DRIVE_FILE* file, const BYTE* buffer, UINT32 Length)
399
0
{
400
0
  DWORD written = 0;
401
402
0
  if (!file || !buffer)
403
0
    return FALSE;
404
405
0
  DEBUG_WSTR("Write file %s", file->fullpath);
406
407
0
  while (Length > 0)
408
0
  {
409
0
    if (!WriteFile(file->file_handle, buffer, Length, &written, NULL))
410
0
      return FALSE;
411
412
0
    Length -= written;
413
0
    buffer += written;
414
0
  }
415
416
0
  return TRUE;
417
0
}
418
419
static BOOL drive_file_query_from_handle_information(const DRIVE_FILE* file,
420
                                                     const BY_HANDLE_FILE_INFORMATION* info,
421
                                                     UINT32 FsInformationClass, wStream* output)
422
0
{
423
0
  switch (FsInformationClass)
424
0
  {
425
0
    case FileBasicInformation:
426
427
      /* http://msdn.microsoft.com/en-us/library/cc232094.aspx */
428
0
      if (!Stream_EnsureRemainingCapacity(output, 4 + 36))
429
0
        return FALSE;
430
431
0
      Stream_Write_UINT32(output, 36);                                    /* Length */
432
0
      Stream_Write_UINT32(output, info->ftCreationTime.dwLowDateTime);    /* CreationTime */
433
0
      Stream_Write_UINT32(output, info->ftCreationTime.dwHighDateTime);   /* CreationTime */
434
0
      Stream_Write_UINT32(output, info->ftLastAccessTime.dwLowDateTime);  /* LastAccessTime */
435
0
      Stream_Write_UINT32(output, info->ftLastAccessTime.dwHighDateTime); /* LastAccessTime */
436
0
      Stream_Write_UINT32(output, info->ftLastWriteTime.dwLowDateTime);   /* LastWriteTime */
437
0
      Stream_Write_UINT32(output, info->ftLastWriteTime.dwHighDateTime);  /* LastWriteTime */
438
0
      Stream_Write_UINT32(output, info->ftLastWriteTime.dwLowDateTime);   /* ChangeTime */
439
0
      Stream_Write_UINT32(output, info->ftLastWriteTime.dwHighDateTime);  /* ChangeTime */
440
0
      Stream_Write_UINT32(output, info->dwFileAttributes);                /* FileAttributes */
441
      /* Reserved(4), MUST NOT be added! */
442
0
      break;
443
444
0
    case FileStandardInformation:
445
446
      /*  http://msdn.microsoft.com/en-us/library/cc232088.aspx */
447
0
      if (!Stream_EnsureRemainingCapacity(output, 4 + 22))
448
0
        return FALSE;
449
450
0
      Stream_Write_UINT32(output, 22);                          /* Length */
451
0
      Stream_Write_UINT32(output, info->nFileSizeLow);          /* AllocationSize */
452
0
      Stream_Write_UINT32(output, info->nFileSizeHigh);         /* AllocationSize */
453
0
      Stream_Write_UINT32(output, info->nFileSizeLow);          /* EndOfFile */
454
0
      Stream_Write_UINT32(output, info->nFileSizeHigh);         /* EndOfFile */
455
0
      Stream_Write_UINT32(output, info->nNumberOfLinks);        /* NumberOfLinks */
456
0
      Stream_Write_UINT8(output, file->delete_pending ? 1 : 0); /* DeletePending */
457
0
      Stream_Write_UINT8(output, info->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY
458
0
                                     ? TRUE
459
0
                                     : FALSE); /* Directory */
460
      /* Reserved(2), MUST NOT be added! */
461
0
      break;
462
463
0
    case FileAttributeTagInformation:
464
465
      /* http://msdn.microsoft.com/en-us/library/cc232093.aspx */
466
0
      if (!Stream_EnsureRemainingCapacity(output, 4 + 8))
467
0
        return FALSE;
468
469
0
      Stream_Write_UINT32(output, 8);                      /* Length */
470
0
      Stream_Write_UINT32(output, info->dwFileAttributes); /* FileAttributes */
471
0
      Stream_Write_UINT32(output, 0);                      /* ReparseTag */
472
0
      break;
473
474
0
    default:
475
      /* Unhandled FsInformationClass */
476
0
      return FALSE;
477
0
  }
478
479
0
  return TRUE;
480
0
}
481
482
static BOOL drive_file_query_from_attributes(const DRIVE_FILE* file,
483
                                             const WIN32_FILE_ATTRIBUTE_DATA* attrib,
484
                                             UINT32 FsInformationClass, wStream* output)
485
0
{
486
0
  switch (FsInformationClass)
487
0
  {
488
0
    case FileBasicInformation:
489
490
      /* http://msdn.microsoft.com/en-us/library/cc232094.aspx */
491
0
      if (!Stream_EnsureRemainingCapacity(output, 4 + 36))
492
0
        return FALSE;
493
494
0
      Stream_Write_UINT32(output, 36);                                    /* Length */
495
0
      Stream_Write_UINT32(output, attrib->ftCreationTime.dwLowDateTime);  /* CreationTime */
496
0
      Stream_Write_UINT32(output, attrib->ftCreationTime.dwHighDateTime); /* CreationTime */
497
0
      Stream_Write_UINT32(output,
498
0
                          attrib->ftLastAccessTime.dwLowDateTime); /* LastAccessTime */
499
0
      Stream_Write_UINT32(output,
500
0
                          attrib->ftLastAccessTime.dwHighDateTime);       /* LastAccessTime */
501
0
      Stream_Write_UINT32(output, attrib->ftLastWriteTime.dwLowDateTime); /* LastWriteTime */
502
0
      Stream_Write_UINT32(output, attrib->ftLastWriteTime.dwHighDateTime); /* LastWriteTime */
503
0
      Stream_Write_UINT32(output, attrib->ftLastWriteTime.dwLowDateTime);  /* ChangeTime */
504
0
      Stream_Write_UINT32(output, attrib->ftLastWriteTime.dwHighDateTime); /* ChangeTime */
505
0
      Stream_Write_UINT32(output, attrib->dwFileAttributes); /* FileAttributes */
506
      /* Reserved(4), MUST NOT be added! */
507
0
      break;
508
509
0
    case FileStandardInformation:
510
511
      /*  http://msdn.microsoft.com/en-us/library/cc232088.aspx */
512
0
      if (!Stream_EnsureRemainingCapacity(output, 4 + 22))
513
0
        return FALSE;
514
515
0
      Stream_Write_UINT32(output, 22);                          /* Length */
516
0
      Stream_Write_UINT32(output, attrib->nFileSizeLow);        /* AllocationSize */
517
0
      Stream_Write_UINT32(output, attrib->nFileSizeHigh);       /* AllocationSize */
518
0
      Stream_Write_UINT32(output, attrib->nFileSizeLow);        /* EndOfFile */
519
0
      Stream_Write_UINT32(output, attrib->nFileSizeHigh);       /* EndOfFile */
520
0
      Stream_Write_UINT32(output, 0);                           /* NumberOfLinks */
521
0
      Stream_Write_UINT8(output, file->delete_pending ? 1 : 0); /* DeletePending */
522
0
      Stream_Write_UINT8(output, attrib->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY
523
0
                                     ? TRUE
524
0
                                     : FALSE); /* Directory */
525
      /* Reserved(2), MUST NOT be added! */
526
0
      break;
527
528
0
    case FileAttributeTagInformation:
529
530
      /* http://msdn.microsoft.com/en-us/library/cc232093.aspx */
531
0
      if (!Stream_EnsureRemainingCapacity(output, 4 + 8))
532
0
        return FALSE;
533
534
0
      Stream_Write_UINT32(output, 8);                        /* Length */
535
0
      Stream_Write_UINT32(output, attrib->dwFileAttributes); /* FileAttributes */
536
0
      Stream_Write_UINT32(output, 0);                        /* ReparseTag */
537
0
      break;
538
539
0
    default:
540
      /* Unhandled FsInformationClass */
541
0
      return FALSE;
542
0
  }
543
544
0
  return TRUE;
545
0
}
546
547
BOOL drive_file_query_information(DRIVE_FILE* file, UINT32 FsInformationClass, wStream* output)
548
0
{
549
0
  BY_HANDLE_FILE_INFORMATION fileInformation = { 0 };
550
0
  BOOL status = 0;
551
0
  HANDLE hFile = NULL;
552
553
0
  if (!file || !output)
554
0
    return FALSE;
555
556
0
  hFile = CreateFileW(file->fullpath, 0, FILE_SHARE_DELETE, NULL, OPEN_EXISTING,
557
0
                      FILE_ATTRIBUTE_NORMAL, NULL);
558
0
  if (hFile != INVALID_HANDLE_VALUE)
559
0
  {
560
0
    status = GetFileInformationByHandle(hFile, &fileInformation);
561
0
    CloseHandle(hFile);
562
0
    if (!status)
563
0
      goto out_fail;
564
565
0
    if (!drive_file_query_from_handle_information(file, &fileInformation, FsInformationClass,
566
0
                                                  output))
567
0
      goto out_fail;
568
569
0
    return TRUE;
570
0
  }
571
572
  /* If we failed before (i.e. if information for a drive is queried) fall back to
573
   * GetFileAttributesExW */
574
0
  WIN32_FILE_ATTRIBUTE_DATA fileAttributes = { 0 };
575
0
  if (!GetFileAttributesExW(file->fullpath, GetFileExInfoStandard, &fileAttributes))
576
0
    goto out_fail;
577
578
0
  if (!drive_file_query_from_attributes(file, &fileAttributes, FsInformationClass, output))
579
0
    goto out_fail;
580
581
0
  return TRUE;
582
0
out_fail:
583
0
  Stream_Write_UINT32(output, 0); /* Length */
584
0
  return FALSE;
585
0
}
586
587
BOOL drive_file_set_information(DRIVE_FILE* file, UINT32 FsInformationClass, UINT32 Length,
588
                                wStream* input)
589
0
{
590
0
  INT64 size = 0;
591
0
  WCHAR* fullpath = NULL;
592
0
  ULARGE_INTEGER liCreationTime;
593
0
  ULARGE_INTEGER liLastAccessTime;
594
0
  ULARGE_INTEGER liLastWriteTime;
595
0
  ULARGE_INTEGER liChangeTime;
596
0
  FILETIME ftCreationTime;
597
0
  FILETIME ftLastAccessTime;
598
0
  FILETIME ftLastWriteTime;
599
0
  FILETIME* pftCreationTime = NULL;
600
0
  FILETIME* pftLastAccessTime = NULL;
601
0
  FILETIME* pftLastWriteTime = NULL;
602
0
  UINT32 FileAttributes = 0;
603
0
  UINT32 FileNameLength = 0;
604
0
  LARGE_INTEGER liSize;
605
0
  UINT8 delete_pending = 0;
606
0
  UINT8 ReplaceIfExists = 0;
607
0
  DWORD attr = 0;
608
609
0
  if (!file || !input)
610
0
    return FALSE;
611
612
0
  switch (FsInformationClass)
613
0
  {
614
0
    case FileBasicInformation:
615
0
      if (!Stream_CheckAndLogRequiredLength(TAG, input, 36))
616
0
        return FALSE;
617
618
      /* http://msdn.microsoft.com/en-us/library/cc232094.aspx */
619
0
      Stream_Read_UINT64(input, liCreationTime.QuadPart);
620
0
      Stream_Read_UINT64(input, liLastAccessTime.QuadPart);
621
0
      Stream_Read_UINT64(input, liLastWriteTime.QuadPart);
622
0
      Stream_Read_UINT64(input, liChangeTime.QuadPart);
623
0
      Stream_Read_UINT32(input, FileAttributes);
624
625
0
      if (!PathFileExistsW(file->fullpath))
626
0
        return FALSE;
627
628
0
      if (file->file_handle == INVALID_HANDLE_VALUE)
629
0
      {
630
0
        WLog_ERR(TAG, "Unable to set file time %s (%" PRId32 ")", file->fullpath,
631
0
                 GetLastError());
632
0
        return FALSE;
633
0
      }
634
635
0
      if (liCreationTime.QuadPart != 0)
636
0
      {
637
0
        ftCreationTime.dwHighDateTime = liCreationTime.u.HighPart;
638
0
        ftCreationTime.dwLowDateTime = liCreationTime.u.LowPart;
639
0
        pftCreationTime = &ftCreationTime;
640
0
      }
641
642
0
      if (liLastAccessTime.QuadPart != 0)
643
0
      {
644
0
        ftLastAccessTime.dwHighDateTime = liLastAccessTime.u.HighPart;
645
0
        ftLastAccessTime.dwLowDateTime = liLastAccessTime.u.LowPart;
646
0
        pftLastAccessTime = &ftLastAccessTime;
647
0
      }
648
649
0
      if (liLastWriteTime.QuadPart != 0)
650
0
      {
651
0
        ftLastWriteTime.dwHighDateTime = liLastWriteTime.u.HighPart;
652
0
        ftLastWriteTime.dwLowDateTime = liLastWriteTime.u.LowPart;
653
0
        pftLastWriteTime = &ftLastWriteTime;
654
0
      }
655
656
0
      if (liChangeTime.QuadPart != 0 && liChangeTime.QuadPart > liLastWriteTime.QuadPart)
657
0
      {
658
0
        ftLastWriteTime.dwHighDateTime = liChangeTime.u.HighPart;
659
0
        ftLastWriteTime.dwLowDateTime = liChangeTime.u.LowPart;
660
0
        pftLastWriteTime = &ftLastWriteTime;
661
0
      }
662
663
0
      DEBUG_WSTR("SetFileTime %s", file->fullpath);
664
665
0
      SetFileAttributesW(file->fullpath, FileAttributes);
666
0
      if (!SetFileTime(file->file_handle, pftCreationTime, pftLastAccessTime,
667
0
                       pftLastWriteTime))
668
0
      {
669
0
        WLog_ERR(TAG, "Unable to set file time to %s", file->fullpath);
670
0
        return FALSE;
671
0
      }
672
673
0
      break;
674
675
0
    case FileEndOfFileInformation:
676
677
    /* http://msdn.microsoft.com/en-us/library/cc232067.aspx */
678
0
    case FileAllocationInformation:
679
0
      if (!Stream_CheckAndLogRequiredLength(TAG, input, 8))
680
0
        return FALSE;
681
682
      /* http://msdn.microsoft.com/en-us/library/cc232076.aspx */
683
0
      Stream_Read_INT64(input, size);
684
685
0
      if (file->file_handle == INVALID_HANDLE_VALUE)
686
0
      {
687
0
        WLog_ERR(TAG, "Unable to truncate %s to %" PRId64 " (%" PRId32 ")", file->fullpath,
688
0
                 size, GetLastError());
689
0
        return FALSE;
690
0
      }
691
692
0
      liSize.QuadPart = size;
693
694
0
      if (!SetFilePointerEx(file->file_handle, liSize, NULL, FILE_BEGIN))
695
0
      {
696
0
        WLog_ERR(TAG, "Unable to truncate %s to %" PRId64 " (%" PRId32 ")", file->fullpath,
697
0
                 size, GetLastError());
698
0
        return FALSE;
699
0
      }
700
701
0
      DEBUG_WSTR("Truncate %s", file->fullpath);
702
703
0
      if (SetEndOfFile(file->file_handle) == 0)
704
0
      {
705
0
        WLog_ERR(TAG, "Unable to truncate %s to %" PRId64 " (%" PRId32 ")", file->fullpath,
706
0
                 size, GetLastError());
707
0
        return FALSE;
708
0
      }
709
710
0
      break;
711
712
0
    case FileDispositionInformation:
713
714
      /* http://msdn.microsoft.com/en-us/library/cc232098.aspx */
715
      /* http://msdn.microsoft.com/en-us/library/cc241371.aspx */
716
0
      if (file->is_dir && !PathIsDirectoryEmptyW(file->fullpath))
717
0
        break; /* TODO: SetLastError ??? */
718
719
0
      if (Length)
720
0
      {
721
0
        if (!Stream_CheckAndLogRequiredLength(TAG, input, 1))
722
0
          return FALSE;
723
724
0
        Stream_Read_UINT8(input, delete_pending);
725
0
      }
726
0
      else
727
0
        delete_pending = 1;
728
729
0
      if (delete_pending)
730
0
      {
731
0
        DEBUG_WSTR("SetDeletePending %s", file->fullpath);
732
0
        attr = GetFileAttributesW(file->fullpath);
733
734
0
        if (attr & FILE_ATTRIBUTE_READONLY)
735
0
        {
736
0
          SetLastError(ERROR_ACCESS_DENIED);
737
0
          return FALSE;
738
0
        }
739
0
      }
740
741
0
      file->delete_pending = delete_pending;
742
0
      break;
743
744
0
    case FileRenameInformation:
745
0
      if (!Stream_CheckAndLogRequiredLength(TAG, input, 6))
746
0
        return FALSE;
747
748
      /* http://msdn.microsoft.com/en-us/library/cc232085.aspx */
749
0
      Stream_Read_UINT8(input, ReplaceIfExists);
750
0
      Stream_Seek_UINT8(input); /* RootDirectory */
751
0
      Stream_Read_UINT32(input, FileNameLength);
752
753
0
      if (!Stream_CheckAndLogRequiredLength(TAG, input, FileNameLength))
754
0
        return FALSE;
755
756
0
      fullpath = drive_file_combine_fullpath(file->basepath, Stream_ConstPointer(input),
757
0
                                             FileNameLength / sizeof(WCHAR));
758
759
0
      if (!fullpath)
760
0
        return FALSE;
761
762
#ifdef _WIN32
763
764
      if (file->file_handle != INVALID_HANDLE_VALUE)
765
      {
766
        CloseHandle(file->file_handle);
767
        file->file_handle = INVALID_HANDLE_VALUE;
768
      }
769
770
#endif
771
0
      DEBUG_WSTR("MoveFileExW %s", file->fullpath);
772
773
0
      if (MoveFileExW(file->fullpath, fullpath,
774
0
                      MOVEFILE_COPY_ALLOWED |
775
0
                          (ReplaceIfExists ? MOVEFILE_REPLACE_EXISTING : 0)))
776
0
      {
777
0
        if (!drive_file_set_fullpath(file, fullpath))
778
0
          return FALSE;
779
0
      }
780
0
      else
781
0
      {
782
0
        free(fullpath);
783
0
        return FALSE;
784
0
      }
785
786
#ifdef _WIN32
787
      drive_file_init(file);
788
#endif
789
0
      break;
790
791
0
    default:
792
0
      return FALSE;
793
0
  }
794
795
0
  return TRUE;
796
0
}
797
798
BOOL drive_file_query_directory(DRIVE_FILE* file, UINT32 FsInformationClass, BYTE InitialQuery,
799
                                const WCHAR* path, UINT32 PathWCharLength, wStream* output)
800
0
{
801
0
  size_t length = 0;
802
0
  WCHAR* ent_path = NULL;
803
804
0
  if (!file || !path || !output)
805
0
    return FALSE;
806
807
0
  if (InitialQuery != 0)
808
0
  {
809
    /* release search handle */
810
0
    if (file->find_handle != INVALID_HANDLE_VALUE)
811
0
      FindClose(file->find_handle);
812
813
0
    ent_path = drive_file_combine_fullpath(file->basepath, path, PathWCharLength);
814
    /* open new search handle and retrieve the first entry */
815
0
    file->find_handle = FindFirstFileW(ent_path, &file->find_data);
816
0
    free(ent_path);
817
818
0
    if (file->find_handle == INVALID_HANDLE_VALUE)
819
0
      goto out_fail;
820
0
  }
821
0
  else if (!FindNextFileW(file->find_handle, &file->find_data))
822
0
    goto out_fail;
823
824
0
  length = _wcslen(file->find_data.cFileName) * 2;
825
826
0
  switch (FsInformationClass)
827
0
  {
828
0
    case FileDirectoryInformation:
829
830
      /* http://msdn.microsoft.com/en-us/library/cc232097.aspx */
831
0
      if (!Stream_EnsureRemainingCapacity(output, 4 + 64 + length))
832
0
        goto out_fail;
833
834
0
      if (length > UINT32_MAX - 64)
835
0
        goto out_fail;
836
837
0
      Stream_Write_UINT32(output, (UINT32)(64 + length)); /* Length */
838
0
      Stream_Write_UINT32(output, 0);                     /* NextEntryOffset */
839
0
      Stream_Write_UINT32(output, 0);                     /* FileIndex */
840
0
      Stream_Write_UINT32(output,
841
0
                          file->find_data.ftCreationTime.dwLowDateTime); /* CreationTime */
842
0
      Stream_Write_UINT32(output,
843
0
                          file->find_data.ftCreationTime.dwHighDateTime); /* CreationTime */
844
0
      Stream_Write_UINT32(
845
0
          output, file->find_data.ftLastAccessTime.dwLowDateTime); /* LastAccessTime */
846
0
      Stream_Write_UINT32(
847
0
          output, file->find_data.ftLastAccessTime.dwHighDateTime); /* LastAccessTime */
848
0
      Stream_Write_UINT32(output,
849
0
                          file->find_data.ftLastWriteTime.dwLowDateTime); /* LastWriteTime */
850
0
      Stream_Write_UINT32(output,
851
0
                          file->find_data.ftLastWriteTime.dwHighDateTime); /* LastWriteTime */
852
0
      Stream_Write_UINT32(output,
853
0
                          file->find_data.ftLastWriteTime.dwLowDateTime); /* ChangeTime */
854
0
      Stream_Write_UINT32(output,
855
0
                          file->find_data.ftLastWriteTime.dwHighDateTime); /* ChangeTime */
856
0
      Stream_Write_UINT32(output, file->find_data.nFileSizeLow);           /* EndOfFile */
857
0
      Stream_Write_UINT32(output, file->find_data.nFileSizeHigh);          /* EndOfFile */
858
0
      Stream_Write_UINT32(output, file->find_data.nFileSizeLow);     /* AllocationSize */
859
0
      Stream_Write_UINT32(output, file->find_data.nFileSizeHigh);    /* AllocationSize */
860
0
      Stream_Write_UINT32(output, file->find_data.dwFileAttributes); /* FileAttributes */
861
0
      Stream_Write_UINT32(output, (UINT32)length);                   /* FileNameLength */
862
0
      Stream_Write(output, file->find_data.cFileName, length);
863
0
      break;
864
865
0
    case FileFullDirectoryInformation:
866
867
      /* http://msdn.microsoft.com/en-us/library/cc232068.aspx */
868
0
      if (!Stream_EnsureRemainingCapacity(output, 4 + 68 + length))
869
0
        goto out_fail;
870
871
0
      if (length > UINT32_MAX - 68)
872
0
        goto out_fail;
873
874
0
      Stream_Write_UINT32(output, (UINT32)(68 + length)); /* Length */
875
0
      Stream_Write_UINT32(output, 0);                     /* NextEntryOffset */
876
0
      Stream_Write_UINT32(output, 0);                     /* FileIndex */
877
0
      Stream_Write_UINT32(output,
878
0
                          file->find_data.ftCreationTime.dwLowDateTime); /* CreationTime */
879
0
      Stream_Write_UINT32(output,
880
0
                          file->find_data.ftCreationTime.dwHighDateTime); /* CreationTime */
881
0
      Stream_Write_UINT32(
882
0
          output, file->find_data.ftLastAccessTime.dwLowDateTime); /* LastAccessTime */
883
0
      Stream_Write_UINT32(
884
0
          output, file->find_data.ftLastAccessTime.dwHighDateTime); /* LastAccessTime */
885
0
      Stream_Write_UINT32(output,
886
0
                          file->find_data.ftLastWriteTime.dwLowDateTime); /* LastWriteTime */
887
0
      Stream_Write_UINT32(output,
888
0
                          file->find_data.ftLastWriteTime.dwHighDateTime); /* LastWriteTime */
889
0
      Stream_Write_UINT32(output,
890
0
                          file->find_data.ftLastWriteTime.dwLowDateTime); /* ChangeTime */
891
0
      Stream_Write_UINT32(output,
892
0
                          file->find_data.ftLastWriteTime.dwHighDateTime); /* ChangeTime */
893
0
      Stream_Write_UINT32(output, file->find_data.nFileSizeLow);           /* EndOfFile */
894
0
      Stream_Write_UINT32(output, file->find_data.nFileSizeHigh);          /* EndOfFile */
895
0
      Stream_Write_UINT32(output, file->find_data.nFileSizeLow);     /* AllocationSize */
896
0
      Stream_Write_UINT32(output, file->find_data.nFileSizeHigh);    /* AllocationSize */
897
0
      Stream_Write_UINT32(output, file->find_data.dwFileAttributes); /* FileAttributes */
898
0
      Stream_Write_UINT32(output, (UINT32)length);                   /* FileNameLength */
899
0
      Stream_Write_UINT32(output, 0);                                /* EaSize */
900
0
      Stream_Write(output, file->find_data.cFileName, length);
901
0
      break;
902
903
0
    case FileBothDirectoryInformation:
904
905
      /* http://msdn.microsoft.com/en-us/library/cc232095.aspx */
906
0
      if (!Stream_EnsureRemainingCapacity(output, 4 + 93 + length))
907
0
        goto out_fail;
908
909
0
      if (length > UINT32_MAX - 93)
910
0
        goto out_fail;
911
912
0
      Stream_Write_UINT32(output, (UINT32)(93 + length)); /* Length */
913
0
      Stream_Write_UINT32(output, 0);                     /* NextEntryOffset */
914
0
      Stream_Write_UINT32(output, 0);                     /* FileIndex */
915
0
      Stream_Write_UINT32(output,
916
0
                          file->find_data.ftCreationTime.dwLowDateTime); /* CreationTime */
917
0
      Stream_Write_UINT32(output,
918
0
                          file->find_data.ftCreationTime.dwHighDateTime); /* CreationTime */
919
0
      Stream_Write_UINT32(
920
0
          output, file->find_data.ftLastAccessTime.dwLowDateTime); /* LastAccessTime */
921
0
      Stream_Write_UINT32(
922
0
          output, file->find_data.ftLastAccessTime.dwHighDateTime); /* LastAccessTime */
923
0
      Stream_Write_UINT32(output,
924
0
                          file->find_data.ftLastWriteTime.dwLowDateTime); /* LastWriteTime */
925
0
      Stream_Write_UINT32(output,
926
0
                          file->find_data.ftLastWriteTime.dwHighDateTime); /* LastWriteTime */
927
0
      Stream_Write_UINT32(output,
928
0
                          file->find_data.ftLastWriteTime.dwLowDateTime); /* ChangeTime */
929
0
      Stream_Write_UINT32(output,
930
0
                          file->find_data.ftLastWriteTime.dwHighDateTime); /* ChangeTime */
931
0
      Stream_Write_UINT32(output, file->find_data.nFileSizeLow);           /* EndOfFile */
932
0
      Stream_Write_UINT32(output, file->find_data.nFileSizeHigh);          /* EndOfFile */
933
0
      Stream_Write_UINT32(output, file->find_data.nFileSizeLow);     /* AllocationSize */
934
0
      Stream_Write_UINT32(output, file->find_data.nFileSizeHigh);    /* AllocationSize */
935
0
      Stream_Write_UINT32(output, file->find_data.dwFileAttributes); /* FileAttributes */
936
0
      Stream_Write_UINT32(output, (UINT32)length);                   /* FileNameLength */
937
0
      Stream_Write_UINT32(output, 0);                                /* EaSize */
938
0
      Stream_Write_UINT8(output, 0);                                 /* ShortNameLength */
939
      /* Reserved(1), MUST NOT be added! */
940
0
      Stream_Zero(output, 24); /* ShortName */
941
0
      Stream_Write(output, file->find_data.cFileName, length);
942
0
      break;
943
944
0
    case FileNamesInformation:
945
946
      /* http://msdn.microsoft.com/en-us/library/cc232077.aspx */
947
0
      if (!Stream_EnsureRemainingCapacity(output, 4 + 12 + length))
948
0
        goto out_fail;
949
950
0
      if (length > UINT32_MAX - 12)
951
0
        goto out_fail;
952
953
0
      Stream_Write_UINT32(output, (UINT32)(12 + length)); /* Length */
954
0
      Stream_Write_UINT32(output, 0);                     /* NextEntryOffset */
955
0
      Stream_Write_UINT32(output, 0);                     /* FileIndex */
956
0
      Stream_Write_UINT32(output, (UINT32)length);        /* FileNameLength */
957
0
      Stream_Write(output, file->find_data.cFileName, length);
958
0
      break;
959
960
0
    default:
961
0
      WLog_ERR(TAG, "unhandled FsInformationClass %" PRIu32, FsInformationClass);
962
      /* Unhandled FsInformationClass */
963
0
      goto out_fail;
964
0
  }
965
966
0
  return TRUE;
967
0
out_fail:
968
0
  Stream_Write_UINT32(output, 0); /* Length */
969
0
  Stream_Write_UINT8(output, 0);  /* Padding */
970
0
  return FALSE;
971
0
}