Coverage Report

Created: 2026-01-09 06:49

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/FreeRDP/channels/drive/client/drive_file.c
Line
Count
Source
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
    (void)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 BOOL contains_dotdot(const WCHAR* path, size_t base_length, size_t path_length)
94
0
{
95
0
  WCHAR dotdotbuffer[6] = { 0 };
96
0
  const WCHAR* dotdot = InitializeConstWCharFromUtf8("..", dotdotbuffer, ARRAYSIZE(dotdotbuffer));
97
0
  const WCHAR* tst = path;
98
99
0
  if (path_length < 2)
100
0
    return FALSE;
101
102
0
  do
103
0
  {
104
0
    tst = _wcsstr(tst, dotdot);
105
0
    if (!tst)
106
0
      return FALSE;
107
108
    /* Filter .. sequences in file or directory names */
109
0
    if ((base_length == 0) || (*(tst - 1) == L'/') || (*(tst - 1) == L'\\'))
110
0
    {
111
0
      if (tst + 2 < path + path_length)
112
0
      {
113
0
        if ((tst[2] == '/') || (tst[2] == '\\'))
114
0
          return TRUE;
115
0
      }
116
0
    }
117
0
    tst += 2;
118
0
  } while (TRUE);
119
120
0
  return FALSE;
121
0
}
122
123
static WCHAR* drive_file_combine_fullpath(const WCHAR* base_path, const WCHAR* path,
124
                                          size_t PathWCharLength)
125
0
{
126
0
  BOOL ok = FALSE;
127
0
  WCHAR* fullpath = NULL;
128
129
0
  if (!base_path || (!path && (PathWCharLength > 0)))
130
0
    goto fail;
131
132
0
  {
133
0
    const size_t base_path_length = _wcsnlen(base_path, MAX_PATH);
134
0
    const size_t length = base_path_length + PathWCharLength + 1;
135
0
    fullpath = (WCHAR*)calloc(length, sizeof(WCHAR));
136
137
0
    if (!fullpath)
138
0
      goto fail;
139
140
0
    CopyMemory(fullpath, base_path, base_path_length * sizeof(WCHAR));
141
0
    if (path)
142
0
      CopyMemory(&fullpath[base_path_length], path, PathWCharLength * sizeof(WCHAR));
143
144
0
    if (!drive_file_fix_path(fullpath, length))
145
0
      goto fail;
146
147
    /* Ensure the path does not contain sequences like '..' */
148
0
    if (contains_dotdot(&fullpath[base_path_length], base_path_length, PathWCharLength))
149
0
    {
150
0
      char abuffer[MAX_PATH] = { 0 };
151
0
      (void)ConvertWCharToUtf8(&fullpath[base_path_length], abuffer, ARRAYSIZE(abuffer));
152
153
0
      WLog_WARN(TAG, "[rdpdr] received invalid file path '%s' from server, aborting!",
154
0
                &abuffer[base_path_length]);
155
0
      goto fail;
156
0
    }
157
0
  }
158
159
0
  ok = TRUE;
160
0
fail:
161
0
  if (!ok)
162
0
  {
163
0
    free(fullpath);
164
0
    fullpath = NULL;
165
0
  }
166
0
  return fullpath;
167
0
}
168
169
static BOOL drive_file_set_fullpath(DRIVE_FILE* file, const WCHAR* fullpath)
170
0
{
171
0
  if (!file || !fullpath)
172
0
    return FALSE;
173
174
0
  const size_t len = _wcslen(fullpath);
175
0
  free(file->fullpath);
176
0
  file->fullpath = NULL;
177
178
0
  if (len == 0)
179
0
    return TRUE;
180
181
0
  file->fullpath = _wcsdup(fullpath);
182
0
  if (!file->fullpath)
183
0
    return FALSE;
184
185
0
  const WCHAR sep[] = { PathGetSeparatorW(PATH_STYLE_NATIVE), '\0' };
186
0
  WCHAR* filename = _wcsrchr(file->fullpath, *sep);
187
0
  if (filename && _wcsncmp(filename, sep, ARRAYSIZE(sep)) == 0)
188
0
    *filename = '\0';
189
190
0
  return TRUE;
191
0
}
192
193
static BOOL drive_file_init(DRIVE_FILE* file)
194
0
{
195
0
  UINT CreateDisposition = 0;
196
0
  DWORD dwAttr = GetFileAttributesW(file->fullpath);
197
198
0
  if (dwAttr != INVALID_FILE_ATTRIBUTES)
199
0
  {
200
    /* The file exists */
201
0
    file->is_dir = (dwAttr & FILE_ATTRIBUTE_DIRECTORY) != 0;
202
203
0
    if (file->is_dir)
204
0
    {
205
0
      if (file->CreateDisposition == FILE_CREATE)
206
0
      {
207
0
        SetLastError(ERROR_ALREADY_EXISTS);
208
0
        return FALSE;
209
0
      }
210
211
0
      if (file->CreateOptions & FILE_NON_DIRECTORY_FILE)
212
0
      {
213
0
        SetLastError(ERROR_ACCESS_DENIED);
214
0
        return FALSE;
215
0
      }
216
217
0
      return TRUE;
218
0
    }
219
0
    else
220
0
    {
221
0
      if (file->CreateOptions & FILE_DIRECTORY_FILE)
222
0
      {
223
0
        SetLastError(ERROR_DIRECTORY);
224
0
        return FALSE;
225
0
      }
226
0
    }
227
0
  }
228
0
  else
229
0
  {
230
0
    file->is_dir = ((file->CreateOptions & FILE_DIRECTORY_FILE) ? TRUE : FALSE);
231
232
0
    if (file->is_dir)
233
0
    {
234
      /* Should only create the directory if the disposition allows for it */
235
0
      if ((file->CreateDisposition == FILE_OPEN_IF) ||
236
0
          (file->CreateDisposition == FILE_CREATE))
237
0
      {
238
0
        if (CreateDirectoryW(file->fullpath, NULL) != 0)
239
0
        {
240
0
          return TRUE;
241
0
        }
242
0
      }
243
244
0
      SetLastError(ERROR_FILE_NOT_FOUND);
245
0
      return FALSE;
246
0
    }
247
0
  }
248
249
0
  if (file->file_handle == INVALID_HANDLE_VALUE)
250
0
  {
251
0
    switch (file->CreateDisposition)
252
0
    {
253
0
      case FILE_SUPERSEDE: /* If the file already exists, replace it with the given file. If
254
                              it does not, create the given file. */
255
0
        CreateDisposition = CREATE_ALWAYS;
256
0
        break;
257
258
0
      case FILE_OPEN: /* If the file already exists, open it instead of creating a new file.
259
                         If it does not, fail the request and do not create a new file. */
260
0
        CreateDisposition = OPEN_EXISTING;
261
0
        break;
262
263
0
      case FILE_CREATE: /* If the file already exists, fail the request and do not create or
264
                           open the given file. If it does not, create the given file. */
265
0
        CreateDisposition = CREATE_NEW;
266
0
        break;
267
268
0
      case FILE_OPEN_IF: /* If the file already exists, open it. If it does not, create the
269
                            given file. */
270
0
        CreateDisposition = OPEN_ALWAYS;
271
0
        break;
272
273
0
      case FILE_OVERWRITE: /* If the file already exists, open it and overwrite it. If it does
274
                              not, fail the request. */
275
0
        CreateDisposition = TRUNCATE_EXISTING;
276
0
        break;
277
278
0
      case FILE_OVERWRITE_IF: /* If the file already exists, open it and overwrite it. If it
279
                                 does not, create the given file. */
280
0
        CreateDisposition = CREATE_ALWAYS;
281
0
        break;
282
283
0
      default:
284
0
        break;
285
0
    }
286
287
0
#ifndef WIN32
288
0
    file->SharedAccess = 0;
289
0
#endif
290
0
    file->file_handle = CreateFileW(file->fullpath, file->DesiredAccess, file->SharedAccess,
291
0
                                    NULL, CreateDisposition, file->FileAttributes, NULL);
292
0
  }
293
294
#ifdef WIN32
295
  if (file->file_handle == INVALID_HANDLE_VALUE)
296
  {
297
    /* Get the error message, if any. */
298
    DWORD errorMessageID = GetLastError();
299
300
    if (errorMessageID != 0)
301
    {
302
      LPSTR messageBuffer = NULL;
303
      size_t size =
304
          FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
305
                             FORMAT_MESSAGE_IGNORE_INSERTS,
306
                         NULL, errorMessageID, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
307
                         (LPSTR)&messageBuffer, 0, NULL);
308
      char fullpath[MAX_PATH] = { 0 };
309
      (void)ConvertWCharToUtf8(file->fullpath, fullpath, sizeof(fullpath));
310
      WLog_ERR(TAG, "Error in drive_file_init: %s %s", messageBuffer, fullpath);
311
      /* Free the buffer. */
312
      LocalFree(messageBuffer);
313
      /* restore original error code */
314
      SetLastError(errorMessageID);
315
    }
316
  }
317
#endif
318
319
0
  return file->file_handle != INVALID_HANDLE_VALUE;
320
0
}
321
322
DRIVE_FILE* drive_file_new(const WCHAR* base_path, const WCHAR* path, UINT32 PathWCharLength,
323
                           UINT32 id, UINT32 DesiredAccess, UINT32 CreateDisposition,
324
                           UINT32 CreateOptions, UINT32 FileAttributes, UINT32 SharedAccess)
325
0
{
326
0
  if (!base_path || (!path && (PathWCharLength > 0)))
327
0
    return NULL;
328
329
0
  DRIVE_FILE* file = (DRIVE_FILE*)calloc(1, sizeof(DRIVE_FILE));
330
331
0
  if (!file)
332
0
  {
333
0
    WLog_ERR(TAG, "calloc failed!");
334
0
    return NULL;
335
0
  }
336
337
0
  file->file_handle = INVALID_HANDLE_VALUE;
338
0
  file->find_handle = INVALID_HANDLE_VALUE;
339
0
  file->id = id;
340
0
  file->basepath = base_path;
341
0
  file->FileAttributes = FileAttributes;
342
0
  file->DesiredAccess = DesiredAccess;
343
0
  file->CreateDisposition = CreateDisposition;
344
0
  file->CreateOptions = CreateOptions;
345
0
  file->SharedAccess = SharedAccess;
346
347
0
  WCHAR* p = drive_file_combine_fullpath(base_path, path, PathWCharLength);
348
0
  (void)drive_file_set_fullpath(file, p);
349
0
  free(p);
350
351
0
  if (!drive_file_init(file))
352
0
  {
353
0
    DWORD lastError = GetLastError();
354
0
    drive_file_free(file);
355
0
    SetLastError(lastError);
356
0
    return NULL;
357
0
  }
358
359
0
  return file;
360
0
}
361
362
BOOL drive_file_free(DRIVE_FILE* file)
363
0
{
364
0
  BOOL rc = FALSE;
365
366
0
  if (!file)
367
0
    return FALSE;
368
369
0
  if (file->file_handle != INVALID_HANDLE_VALUE)
370
0
  {
371
0
    (void)CloseHandle(file->file_handle);
372
0
    file->file_handle = INVALID_HANDLE_VALUE;
373
0
  }
374
375
0
  if (file->find_handle != INVALID_HANDLE_VALUE)
376
0
  {
377
0
    FindClose(file->find_handle);
378
0
    file->find_handle = INVALID_HANDLE_VALUE;
379
0
  }
380
381
0
  if (file->CreateOptions & FILE_DELETE_ON_CLOSE)
382
0
    file->delete_pending = TRUE;
383
384
0
  if (file->delete_pending)
385
0
  {
386
0
    if (file->is_dir)
387
0
    {
388
0
      if (!winpr_RemoveDirectory_RecursiveW(file->fullpath))
389
0
        goto fail;
390
0
    }
391
0
    else if (!DeleteFileW(file->fullpath))
392
0
      goto fail;
393
0
  }
394
395
0
  rc = TRUE;
396
0
fail:
397
0
  DEBUG_WSTR("Free %s", file->fullpath);
398
0
  free(file->fullpath);
399
0
  free(file);
400
0
  return rc;
401
0
}
402
403
BOOL drive_file_seek(DRIVE_FILE* file, UINT64 Offset)
404
0
{
405
0
  LARGE_INTEGER loffset = { 0 };
406
407
0
  if (!file)
408
0
    return FALSE;
409
410
0
  if (Offset > INT64_MAX)
411
0
    return FALSE;
412
413
0
  loffset.QuadPart = (LONGLONG)Offset;
414
0
  return SetFilePointerEx(file->file_handle, loffset, NULL, FILE_BEGIN);
415
0
}
416
417
BOOL drive_file_read(DRIVE_FILE* file, BYTE* buffer, UINT32* Length)
418
0
{
419
0
  DWORD read = 0;
420
421
0
  if (!file || !buffer || !Length)
422
0
    return FALSE;
423
424
0
  DEBUG_WSTR("Read file %s", file->fullpath);
425
426
0
  if (ReadFile(file->file_handle, buffer, *Length, &read, NULL))
427
0
  {
428
0
    *Length = read;
429
0
    return TRUE;
430
0
  }
431
432
0
  return FALSE;
433
0
}
434
435
BOOL drive_file_write(DRIVE_FILE* file, const BYTE* buffer, UINT32 Length)
436
0
{
437
0
  DWORD written = 0;
438
439
0
  if (!file || !buffer)
440
0
    return FALSE;
441
442
0
  DEBUG_WSTR("Write file %s", file->fullpath);
443
444
0
  while (Length > 0)
445
0
  {
446
0
    if (!WriteFile(file->file_handle, buffer, Length, &written, NULL))
447
0
      return FALSE;
448
449
0
    Length -= written;
450
0
    buffer += written;
451
0
  }
452
453
0
  return TRUE;
454
0
}
455
456
static BOOL drive_file_query_from_handle_information(const DRIVE_FILE* file,
457
                                                     const BY_HANDLE_FILE_INFORMATION* info,
458
                                                     UINT32 FsInformationClass, wStream* output)
459
0
{
460
0
  switch (FsInformationClass)
461
0
  {
462
0
    case FileBasicInformation:
463
464
      /* http://msdn.microsoft.com/en-us/library/cc232094.aspx */
465
0
      if (!Stream_EnsureRemainingCapacity(output, 4 + 36))
466
0
        return FALSE;
467
468
0
      Stream_Write_UINT32(output, 36);                                    /* Length */
469
0
      Stream_Write_UINT32(output, info->ftCreationTime.dwLowDateTime);    /* CreationTime */
470
0
      Stream_Write_UINT32(output, info->ftCreationTime.dwHighDateTime);   /* CreationTime */
471
0
      Stream_Write_UINT32(output, info->ftLastAccessTime.dwLowDateTime);  /* LastAccessTime */
472
0
      Stream_Write_UINT32(output, info->ftLastAccessTime.dwHighDateTime); /* LastAccessTime */
473
0
      Stream_Write_UINT32(output, info->ftLastWriteTime.dwLowDateTime);   /* LastWriteTime */
474
0
      Stream_Write_UINT32(output, info->ftLastWriteTime.dwHighDateTime);  /* LastWriteTime */
475
0
      Stream_Write_UINT32(output, info->ftLastWriteTime.dwLowDateTime);   /* ChangeTime */
476
0
      Stream_Write_UINT32(output, info->ftLastWriteTime.dwHighDateTime);  /* ChangeTime */
477
0
      Stream_Write_UINT32(output, info->dwFileAttributes);                /* FileAttributes */
478
      /* Reserved(4), MUST NOT be added! */
479
0
      break;
480
481
0
    case FileStandardInformation:
482
483
      /*  http://msdn.microsoft.com/en-us/library/cc232088.aspx */
484
0
      if (!Stream_EnsureRemainingCapacity(output, 4 + 22))
485
0
        return FALSE;
486
487
0
      Stream_Write_UINT32(output, 22);                          /* Length */
488
0
      Stream_Write_UINT32(output, info->nFileSizeLow);          /* AllocationSize */
489
0
      Stream_Write_UINT32(output, info->nFileSizeHigh);         /* AllocationSize */
490
0
      Stream_Write_UINT32(output, info->nFileSizeLow);          /* EndOfFile */
491
0
      Stream_Write_UINT32(output, info->nFileSizeHigh);         /* EndOfFile */
492
0
      Stream_Write_UINT32(output, info->nNumberOfLinks);        /* NumberOfLinks */
493
0
      Stream_Write_UINT8(output, file->delete_pending ? 1 : 0); /* DeletePending */
494
0
      Stream_Write_UINT8(output, info->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY
495
0
                                     ? TRUE
496
0
                                     : FALSE); /* Directory */
497
      /* Reserved(2), MUST NOT be added! */
498
0
      break;
499
500
0
    case FileAttributeTagInformation:
501
502
      /* http://msdn.microsoft.com/en-us/library/cc232093.aspx */
503
0
      if (!Stream_EnsureRemainingCapacity(output, 4 + 8))
504
0
        return FALSE;
505
506
0
      Stream_Write_UINT32(output, 8);                      /* Length */
507
0
      Stream_Write_UINT32(output, info->dwFileAttributes); /* FileAttributes */
508
0
      Stream_Write_UINT32(output, 0);                      /* ReparseTag */
509
0
      break;
510
511
0
    default:
512
      /* Unhandled FsInformationClass */
513
0
      WLog_WARN(TAG, "Unhandled FSInformationClass %s [0x%08" PRIx32 "]",
514
0
                FSInformationClass2Tag(FsInformationClass), FsInformationClass);
515
0
      return FALSE;
516
0
  }
517
518
0
  return TRUE;
519
0
}
520
521
static BOOL drive_file_query_from_attributes(const DRIVE_FILE* file,
522
                                             const WIN32_FILE_ATTRIBUTE_DATA* attrib,
523
                                             UINT32 FsInformationClass, wStream* output)
524
0
{
525
0
  switch (FsInformationClass)
526
0
  {
527
0
    case FileBasicInformation:
528
529
      /* http://msdn.microsoft.com/en-us/library/cc232094.aspx */
530
0
      if (!Stream_EnsureRemainingCapacity(output, 4 + 36))
531
0
        return FALSE;
532
533
0
      Stream_Write_UINT32(output, 36);                                    /* Length */
534
0
      Stream_Write_UINT32(output, attrib->ftCreationTime.dwLowDateTime);  /* CreationTime */
535
0
      Stream_Write_UINT32(output, attrib->ftCreationTime.dwHighDateTime); /* CreationTime */
536
0
      Stream_Write_UINT32(output,
537
0
                          attrib->ftLastAccessTime.dwLowDateTime); /* LastAccessTime */
538
0
      Stream_Write_UINT32(output,
539
0
                          attrib->ftLastAccessTime.dwHighDateTime);       /* LastAccessTime */
540
0
      Stream_Write_UINT32(output, attrib->ftLastWriteTime.dwLowDateTime); /* LastWriteTime */
541
0
      Stream_Write_UINT32(output, attrib->ftLastWriteTime.dwHighDateTime); /* LastWriteTime */
542
0
      Stream_Write_UINT32(output, attrib->ftLastWriteTime.dwLowDateTime);  /* ChangeTime */
543
0
      Stream_Write_UINT32(output, attrib->ftLastWriteTime.dwHighDateTime); /* ChangeTime */
544
0
      Stream_Write_UINT32(output, attrib->dwFileAttributes); /* FileAttributes */
545
      /* Reserved(4), MUST NOT be added! */
546
0
      break;
547
548
0
    case FileStandardInformation:
549
550
      /*  http://msdn.microsoft.com/en-us/library/cc232088.aspx */
551
0
      if (!Stream_EnsureRemainingCapacity(output, 4 + 22))
552
0
        return FALSE;
553
554
0
      Stream_Write_UINT32(output, 22);                          /* Length */
555
0
      Stream_Write_UINT32(output, attrib->nFileSizeLow);        /* AllocationSize */
556
0
      Stream_Write_UINT32(output, attrib->nFileSizeHigh);       /* AllocationSize */
557
0
      Stream_Write_UINT32(output, attrib->nFileSizeLow);        /* EndOfFile */
558
0
      Stream_Write_UINT32(output, attrib->nFileSizeHigh);       /* EndOfFile */
559
0
      Stream_Write_UINT32(output, 0);                           /* NumberOfLinks */
560
0
      Stream_Write_UINT8(output, file->delete_pending ? 1 : 0); /* DeletePending */
561
0
      Stream_Write_UINT8(output, attrib->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY
562
0
                                     ? TRUE
563
0
                                     : FALSE); /* Directory */
564
      /* Reserved(2), MUST NOT be added! */
565
0
      break;
566
567
0
    case FileAttributeTagInformation:
568
569
      /* http://msdn.microsoft.com/en-us/library/cc232093.aspx */
570
0
      if (!Stream_EnsureRemainingCapacity(output, 4 + 8))
571
0
        return FALSE;
572
573
0
      Stream_Write_UINT32(output, 8);                        /* Length */
574
0
      Stream_Write_UINT32(output, attrib->dwFileAttributes); /* FileAttributes */
575
0
      Stream_Write_UINT32(output, 0);                        /* ReparseTag */
576
0
      break;
577
578
0
    default:
579
      /* Unhandled FsInformationClass */
580
0
      WLog_WARN(TAG, "Unhandled FSInformationClass %s [0x%08" PRIx32 "]",
581
0
                FSInformationClass2Tag(FsInformationClass), FsInformationClass);
582
0
      return FALSE;
583
0
  }
584
585
0
  return TRUE;
586
0
}
587
588
BOOL drive_file_query_information(DRIVE_FILE* file, UINT32 FsInformationClass, wStream* output)
589
0
{
590
0
  BY_HANDLE_FILE_INFORMATION fileInformation = { 0 };
591
0
  BOOL status = 0;
592
593
0
  if (!file || !output)
594
0
    return FALSE;
595
596
0
  if ((file->file_handle != INVALID_HANDLE_VALUE) &&
597
0
      GetFileInformationByHandle(file->file_handle, &fileInformation))
598
0
    return drive_file_query_from_handle_information(file, &fileInformation, FsInformationClass,
599
0
                                                    output);
600
601
0
  if (!file->is_dir)
602
0
  {
603
0
    HANDLE hFile = CreateFileW(file->fullpath, 0, FILE_SHARE_DELETE, NULL, OPEN_EXISTING,
604
0
                               FILE_ATTRIBUTE_NORMAL, NULL);
605
0
    if (hFile != INVALID_HANDLE_VALUE)
606
0
    {
607
0
      status = GetFileInformationByHandle(hFile, &fileInformation);
608
0
      (void)CloseHandle(hFile);
609
0
      if (!status)
610
0
        goto out_fail;
611
612
0
      if (!drive_file_query_from_handle_information(file, &fileInformation,
613
0
                                                    FsInformationClass, output))
614
0
        goto out_fail;
615
616
0
      return TRUE;
617
0
    }
618
0
  }
619
620
  /* If we failed before (i.e. if information for a drive is queried) fall back to
621
   * GetFileAttributesExW */
622
0
  {
623
0
    WIN32_FILE_ATTRIBUTE_DATA fileAttributes = { 0 };
624
0
    if (!GetFileAttributesExW(file->fullpath, GetFileExInfoStandard, &fileAttributes))
625
0
      goto out_fail;
626
627
0
    if (!drive_file_query_from_attributes(file, &fileAttributes, FsInformationClass, output))
628
0
      goto out_fail;
629
0
  }
630
631
0
  return TRUE;
632
0
out_fail:
633
0
  Stream_Write_UINT32(output, 0); /* Length */
634
0
  return FALSE;
635
0
}
636
637
static BOOL drive_file_set_basic_information(DRIVE_FILE* file, UINT32 Length, wStream* input)
638
0
{
639
0
  WINPR_ASSERT(file);
640
641
0
  const uint32_t expect = 36;
642
0
  if (Length != expect)
643
0
  {
644
0
    WLog_WARN(TAG, "Unexpected Length=%" PRIu32 ", expected %" PRIu32, Length, expect);
645
0
    return FALSE;
646
0
  }
647
648
  /* http://msdn.microsoft.com/en-us/library/cc232094.aspx */
649
0
  const ULARGE_INTEGER liCreationTime = { .QuadPart = Stream_Get_UINT64(input) };
650
0
  const ULARGE_INTEGER liLastAccessTime = { .QuadPart = Stream_Get_UINT64(input) };
651
0
  const ULARGE_INTEGER liLastWriteTime = { .QuadPart = Stream_Get_UINT64(input) };
652
0
  const ULARGE_INTEGER liChangeTime = { .QuadPart = Stream_Get_UINT64(input) };
653
0
  const uint32_t FileAttributes = Stream_Get_UINT32(input);
654
655
0
  if (!PathFileExistsW(file->fullpath))
656
0
    return FALSE;
657
658
0
  if (file->file_handle == INVALID_HANDLE_VALUE)
659
0
  {
660
0
    char fullpath[MAX_PATH] = { 0 };
661
0
    (void)ConvertWCharToUtf8(file->fullpath, fullpath, sizeof(fullpath) - 1);
662
663
0
    WLog_ERR(TAG, "Unable to set file time %s (%" PRId32 ")", fullpath, GetLastError());
664
0
    return FALSE;
665
0
  }
666
667
0
  FILETIME ftCreationTime = { 0 };
668
0
  FILETIME ftLastAccessTime = { 0 };
669
0
  FILETIME ftLastWriteTime = { 0 };
670
0
  FILETIME* pftCreationTime = NULL;
671
0
  FILETIME* pftLastAccessTime = NULL;
672
0
  FILETIME* pftLastWriteTime = NULL;
673
0
  if (liCreationTime.QuadPart != 0)
674
0
  {
675
0
    ftCreationTime.dwHighDateTime = liCreationTime.u.HighPart;
676
0
    ftCreationTime.dwLowDateTime = liCreationTime.u.LowPart;
677
0
    pftCreationTime = &ftCreationTime;
678
0
  }
679
680
0
  if (liLastAccessTime.QuadPart != 0)
681
0
  {
682
0
    ftLastAccessTime.dwHighDateTime = liLastAccessTime.u.HighPart;
683
0
    ftLastAccessTime.dwLowDateTime = liLastAccessTime.u.LowPart;
684
0
    pftLastAccessTime = &ftLastAccessTime;
685
0
  }
686
687
0
  if (liLastWriteTime.QuadPart != 0)
688
0
  {
689
0
    ftLastWriteTime.dwHighDateTime = liLastWriteTime.u.HighPart;
690
0
    ftLastWriteTime.dwLowDateTime = liLastWriteTime.u.LowPart;
691
0
    pftLastWriteTime = &ftLastWriteTime;
692
0
  }
693
694
0
  if (liChangeTime.QuadPart != 0 && liChangeTime.QuadPart > liLastWriteTime.QuadPart)
695
0
  {
696
0
    ftLastWriteTime.dwHighDateTime = liChangeTime.u.HighPart;
697
0
    ftLastWriteTime.dwLowDateTime = liChangeTime.u.LowPart;
698
0
    pftLastWriteTime = &ftLastWriteTime;
699
0
  }
700
701
0
  DEBUG_WSTR("SetFileTime %s", file->fullpath);
702
703
0
  if (!SetFileAttributesW(file->fullpath, FileAttributes))
704
0
  {
705
0
    char fullpath[MAX_PATH] = { 0 };
706
0
    (void)ConvertWCharToUtf8(file->fullpath, fullpath, sizeof(fullpath));
707
0
    WLog_ERR(TAG, "Unable to set file attributes for %s", fullpath);
708
0
    return FALSE;
709
0
  }
710
711
0
  if (!SetFileTime(file->file_handle, pftCreationTime, pftLastAccessTime, pftLastWriteTime))
712
0
  {
713
0
    char fullpath[MAX_PATH] = { 0 };
714
0
    (void)ConvertWCharToUtf8(file->fullpath, fullpath, sizeof(fullpath));
715
0
    WLog_ERR(TAG, "Unable to set file time for %s", fullpath);
716
0
    return FALSE;
717
0
  }
718
0
  return TRUE;
719
0
}
720
721
static BOOL drive_file_set_alloc_information(DRIVE_FILE* file, UINT32 Length, wStream* input)
722
0
{
723
0
  WINPR_ASSERT(file);
724
0
  const uint32_t expect = 8;
725
0
  if (Length != expect)
726
0
  {
727
0
    WLog_WARN(TAG, "Unexpected Length=%" PRIu32 ", expected %" PRIu32, Length, expect);
728
0
    return FALSE;
729
0
  }
730
731
  /* http://msdn.microsoft.com/en-us/library/cc232076.aspx */
732
0
  const int64_t size = Stream_Get_INT64(input);
733
734
0
  if (file->file_handle == INVALID_HANDLE_VALUE)
735
0
  {
736
0
    char fullpath[MAX_PATH] = { 0 };
737
0
    (void)ConvertWCharToUtf8(file->fullpath, fullpath, sizeof(fullpath));
738
0
    WLog_ERR(TAG, "Unable to truncate %s to %" PRId64 " (%" PRId32 ")", fullpath, size,
739
0
             GetLastError());
740
0
    return FALSE;
741
0
  }
742
743
0
  LARGE_INTEGER liSize = { .QuadPart = size };
744
745
0
  if (!SetFilePointerEx(file->file_handle, liSize, NULL, FILE_BEGIN))
746
0
  {
747
0
    char fullpath[MAX_PATH] = { 0 };
748
0
    (void)ConvertWCharToUtf8(file->fullpath, fullpath, sizeof(fullpath));
749
0
    WLog_ERR(TAG, "Unable to truncate %s to %" PRId64 " (%" PRId32 ")", fullpath, size,
750
0
             GetLastError());
751
0
    return FALSE;
752
0
  }
753
754
0
  DEBUG_WSTR("Truncate %s", file->fullpath);
755
756
0
  if (SetEndOfFile(file->file_handle) == 0)
757
0
  {
758
0
    char fullpath[MAX_PATH] = { 0 };
759
0
    (void)ConvertWCharToUtf8(file->fullpath, fullpath, sizeof(fullpath));
760
0
    WLog_ERR(TAG, "Unable to truncate %s to %" PRId64 " (%" PRId32 ")", fullpath, size,
761
0
             GetLastError());
762
0
    return FALSE;
763
0
  }
764
765
0
  return TRUE;
766
0
}
767
768
static BOOL drive_file_set_disposition_information(DRIVE_FILE* file, UINT32 Length, wStream* input)
769
0
{
770
0
  WINPR_ASSERT(file);
771
0
  uint8_t delete_pending = 0;
772
  /* http://msdn.microsoft.com/en-us/library/cc232098.aspx */
773
  /* http://msdn.microsoft.com/en-us/library/cc241371.aspx */
774
0
  if (file->is_dir && !PathIsDirectoryEmptyW(file->fullpath))
775
0
  {
776
0
    SetLastError(ERROR_DIR_NOT_EMPTY);
777
0
    return FALSE;
778
0
  }
779
780
0
  if (Length)
781
0
  {
782
0
    const uint32_t expect = 1;
783
0
    if (Length != expect)
784
0
      WLog_DBG(TAG, "Unexpected Length=%" PRIu32 ", expected %" PRIu32, Length, expect);
785
786
0
    delete_pending = Stream_Get_UINT8(input);
787
0
  }
788
0
  else
789
0
    delete_pending = 1;
790
791
0
  if (delete_pending)
792
0
  {
793
0
    DEBUG_WSTR("SetDeletePending %s", file->fullpath);
794
0
    const uint32_t attr = GetFileAttributesW(file->fullpath);
795
796
0
    if (attr & FILE_ATTRIBUTE_READONLY)
797
0
    {
798
0
      SetLastError(ERROR_ACCESS_DENIED);
799
0
      return FALSE;
800
0
    }
801
0
  }
802
803
0
  file->delete_pending = delete_pending;
804
0
  return TRUE;
805
0
}
806
807
static BOOL drive_file_set_rename_information(DRIVE_FILE* file, UINT32 Length, wStream* input)
808
0
{
809
0
  WINPR_ASSERT(file);
810
811
0
  const uint32_t expect = 6;
812
0
  if (Length < expect)
813
0
  {
814
0
    WLog_WARN(TAG, "Unexpected Length=%" PRIu32 ", expected at least %" PRIu32, Length, expect);
815
0
    return FALSE;
816
0
  }
817
818
  /* http://msdn.microsoft.com/en-us/library/cc232085.aspx */
819
0
  const uint8_t ReplaceIfExists = Stream_Get_UINT8(input);
820
0
  Stream_Seek_UINT8(input); /* RootDirectory */
821
0
  const uint32_t FileNameLength = Stream_Get_UINT32(input);
822
823
0
  if (Length != expect + FileNameLength)
824
0
  {
825
0
    WLog_WARN(TAG, "Unexpected Length=%" PRIu32 ", expected %" PRIu32, Length,
826
0
              expect + FileNameLength);
827
0
    return FALSE;
828
0
  }
829
830
0
  WCHAR* fullpath = drive_file_combine_fullpath(file->basepath, Stream_ConstPointer(input),
831
0
                                                FileNameLength / sizeof(WCHAR));
832
833
0
  if (!fullpath)
834
0
    return FALSE;
835
836
#ifdef _WIN32
837
838
  if (file->file_handle != INVALID_HANDLE_VALUE)
839
  {
840
    (void)CloseHandle(file->file_handle);
841
    file->file_handle = INVALID_HANDLE_VALUE;
842
  }
843
844
#endif
845
0
  DEBUG_WSTR("MoveFileExW %s", file->fullpath);
846
847
0
  if (MoveFileExW(file->fullpath, fullpath,
848
0
                  MOVEFILE_COPY_ALLOWED | (ReplaceIfExists ? MOVEFILE_REPLACE_EXISTING : 0)))
849
0
  {
850
0
    const BOOL rc = drive_file_set_fullpath(file, fullpath);
851
0
    free(fullpath);
852
0
    if (!rc)
853
0
      return FALSE;
854
0
  }
855
0
  else
856
0
  {
857
0
    free(fullpath);
858
0
    return FALSE;
859
0
  }
860
861
#ifdef _WIN32
862
  drive_file_init(file);
863
#endif
864
0
  return TRUE;
865
0
}
866
867
BOOL drive_file_set_information(DRIVE_FILE* file, UINT32 FsInformationClass, UINT32 Length,
868
                                wStream* input)
869
0
{
870
0
  if (!file || !input)
871
0
    return FALSE;
872
873
0
  if (!Stream_CheckAndLogRequiredLength(TAG, input, Length))
874
0
    return FALSE;
875
876
0
  switch (FsInformationClass)
877
0
  {
878
0
    case FileBasicInformation:
879
0
      return drive_file_set_basic_information(file, Length, input);
880
881
0
    case FileEndOfFileInformation:
882
    /* http://msdn.microsoft.com/en-us/library/cc232067.aspx */
883
0
    case FileAllocationInformation:
884
0
      return drive_file_set_alloc_information(file, Length, input);
885
886
0
    case FileDispositionInformation:
887
0
      return drive_file_set_disposition_information(file, Length, input);
888
889
0
    case FileRenameInformation:
890
0
      return drive_file_set_rename_information(file, Length, input);
891
892
0
    default:
893
0
      WLog_WARN(TAG, "Unhandled FSInformationClass %s [0x%08" PRIx32 "]",
894
0
                FSInformationClass2Tag(FsInformationClass), FsInformationClass);
895
0
      return FALSE;
896
0
  }
897
898
0
  return TRUE;
899
0
}
900
901
static BOOL drive_file_query_dir_info(DRIVE_FILE* file, wStream* output, size_t length)
902
0
{
903
0
  WINPR_ASSERT(file);
904
0
  WINPR_ASSERT(output);
905
906
  /* http://msdn.microsoft.com/en-us/library/cc232097.aspx */
907
0
  if (!Stream_EnsureRemainingCapacity(output, 4 + 64 + length))
908
0
    return FALSE;
909
910
0
  if (length > UINT32_MAX - 64)
911
0
    return FALSE;
912
913
0
  Stream_Write_UINT32(output, (UINT32)(64 + length));                        /* Length */
914
0
  Stream_Write_UINT32(output, 0);                                            /* NextEntryOffset */
915
0
  Stream_Write_UINT32(output, 0);                                            /* FileIndex */
916
0
  Stream_Write_UINT32(output, file->find_data.ftCreationTime.dwLowDateTime); /* CreationTime */
917
0
  Stream_Write_UINT32(output, file->find_data.ftCreationTime.dwHighDateTime); /* CreationTime */
918
0
  Stream_Write_UINT32(output,
919
0
                      file->find_data.ftLastAccessTime.dwLowDateTime); /* LastAccessTime */
920
0
  Stream_Write_UINT32(output,
921
0
                      file->find_data.ftLastAccessTime.dwHighDateTime);       /* LastAccessTime */
922
0
  Stream_Write_UINT32(output, file->find_data.ftLastWriteTime.dwLowDateTime); /* LastWriteTime */
923
0
  Stream_Write_UINT32(output, file->find_data.ftLastWriteTime.dwHighDateTime); /* LastWriteTime */
924
0
  Stream_Write_UINT32(output, file->find_data.ftLastWriteTime.dwLowDateTime);  /* ChangeTime */
925
0
  Stream_Write_UINT32(output, file->find_data.ftLastWriteTime.dwHighDateTime); /* ChangeTime */
926
0
  Stream_Write_UINT32(output, file->find_data.nFileSizeLow);                   /* EndOfFile */
927
0
  Stream_Write_UINT32(output, file->find_data.nFileSizeHigh);                  /* EndOfFile */
928
0
  Stream_Write_UINT32(output, file->find_data.nFileSizeLow);     /* AllocationSize */
929
0
  Stream_Write_UINT32(output, file->find_data.nFileSizeHigh);    /* AllocationSize */
930
0
  Stream_Write_UINT32(output, file->find_data.dwFileAttributes); /* FileAttributes */
931
0
  Stream_Write_UINT32(output, (UINT32)length);                   /* FileNameLength */
932
0
  Stream_Write(output, file->find_data.cFileName, length);
933
0
  return TRUE;
934
0
}
935
936
static BOOL drive_file_query_full_dir_info(DRIVE_FILE* file, wStream* output, size_t length)
937
0
{
938
0
  WINPR_ASSERT(file);
939
0
  WINPR_ASSERT(output);
940
  /* http://msdn.microsoft.com/en-us/library/cc232068.aspx */
941
0
  if (!Stream_EnsureRemainingCapacity(output, 4 + 68 + length))
942
0
    return FALSE;
943
944
0
  if (length > UINT32_MAX - 68)
945
0
    return FALSE;
946
947
0
  Stream_Write_UINT32(output, (UINT32)(68 + length));                        /* Length */
948
0
  Stream_Write_UINT32(output, 0);                                            /* NextEntryOffset */
949
0
  Stream_Write_UINT32(output, 0);                                            /* FileIndex */
950
0
  Stream_Write_UINT32(output, file->find_data.ftCreationTime.dwLowDateTime); /* CreationTime */
951
0
  Stream_Write_UINT32(output, file->find_data.ftCreationTime.dwHighDateTime); /* CreationTime */
952
0
  Stream_Write_UINT32(output,
953
0
                      file->find_data.ftLastAccessTime.dwLowDateTime); /* LastAccessTime */
954
0
  Stream_Write_UINT32(output,
955
0
                      file->find_data.ftLastAccessTime.dwHighDateTime);       /* LastAccessTime */
956
0
  Stream_Write_UINT32(output, file->find_data.ftLastWriteTime.dwLowDateTime); /* LastWriteTime */
957
0
  Stream_Write_UINT32(output, file->find_data.ftLastWriteTime.dwHighDateTime); /* LastWriteTime */
958
0
  Stream_Write_UINT32(output, file->find_data.ftLastWriteTime.dwLowDateTime);  /* ChangeTime */
959
0
  Stream_Write_UINT32(output, file->find_data.ftLastWriteTime.dwHighDateTime); /* ChangeTime */
960
0
  Stream_Write_UINT32(output, file->find_data.nFileSizeLow);                   /* EndOfFile */
961
0
  Stream_Write_UINT32(output, file->find_data.nFileSizeHigh);                  /* EndOfFile */
962
0
  Stream_Write_UINT32(output, file->find_data.nFileSizeLow);     /* AllocationSize */
963
0
  Stream_Write_UINT32(output, file->find_data.nFileSizeHigh);    /* AllocationSize */
964
0
  Stream_Write_UINT32(output, file->find_data.dwFileAttributes); /* FileAttributes */
965
0
  Stream_Write_UINT32(output, (UINT32)length);                   /* FileNameLength */
966
0
  Stream_Write_UINT32(output, 0);                                /* EaSize */
967
0
  Stream_Write(output, file->find_data.cFileName, length);
968
0
  return TRUE;
969
0
}
970
971
static BOOL drive_file_query_both_dir_info(DRIVE_FILE* file, wStream* output, size_t length)
972
0
{
973
0
  WINPR_ASSERT(file);
974
0
  WINPR_ASSERT(output);
975
  /* http://msdn.microsoft.com/en-us/library/cc232095.aspx */
976
0
  if (!Stream_EnsureRemainingCapacity(output, 4 + 93 + length))
977
0
    return FALSE;
978
979
0
  if (length > UINT32_MAX - 93)
980
0
    return FALSE;
981
982
0
  Stream_Write_UINT32(output, (UINT32)(93 + length));                        /* Length */
983
0
  Stream_Write_UINT32(output, 0);                                            /* NextEntryOffset */
984
0
  Stream_Write_UINT32(output, 0);                                            /* FileIndex */
985
0
  Stream_Write_UINT32(output, file->find_data.ftCreationTime.dwLowDateTime); /* CreationTime */
986
0
  Stream_Write_UINT32(output, file->find_data.ftCreationTime.dwHighDateTime); /* CreationTime */
987
0
  Stream_Write_UINT32(output,
988
0
                      file->find_data.ftLastAccessTime.dwLowDateTime); /* LastAccessTime */
989
0
  Stream_Write_UINT32(output,
990
0
                      file->find_data.ftLastAccessTime.dwHighDateTime);       /* LastAccessTime */
991
0
  Stream_Write_UINT32(output, file->find_data.ftLastWriteTime.dwLowDateTime); /* LastWriteTime */
992
0
  Stream_Write_UINT32(output, file->find_data.ftLastWriteTime.dwHighDateTime); /* LastWriteTime */
993
0
  Stream_Write_UINT32(output, file->find_data.ftLastWriteTime.dwLowDateTime);  /* ChangeTime */
994
0
  Stream_Write_UINT32(output, file->find_data.ftLastWriteTime.dwHighDateTime); /* ChangeTime */
995
0
  Stream_Write_UINT32(output, file->find_data.nFileSizeLow);                   /* EndOfFile */
996
0
  Stream_Write_UINT32(output, file->find_data.nFileSizeHigh);                  /* EndOfFile */
997
0
  Stream_Write_UINT32(output, file->find_data.nFileSizeLow);     /* AllocationSize */
998
0
  Stream_Write_UINT32(output, file->find_data.nFileSizeHigh);    /* AllocationSize */
999
0
  Stream_Write_UINT32(output, file->find_data.dwFileAttributes); /* FileAttributes */
1000
0
  Stream_Write_UINT32(output, (UINT32)length);                   /* FileNameLength */
1001
0
  Stream_Write_UINT32(output, 0);                                /* EaSize */
1002
0
  Stream_Write_UINT8(output, 0);                                 /* ShortNameLength */
1003
  /* Reserved(1), MUST NOT be added! */
1004
0
  Stream_Zero(output, 24); /* ShortName */
1005
0
  Stream_Write(output, file->find_data.cFileName, length);
1006
0
  return TRUE;
1007
0
}
1008
1009
static BOOL drive_file_query_names_info(DRIVE_FILE* file, wStream* output, size_t length)
1010
0
{
1011
0
  WINPR_ASSERT(file);
1012
0
  WINPR_ASSERT(output);
1013
  /* http://msdn.microsoft.com/en-us/library/cc232077.aspx */
1014
0
  if (!Stream_EnsureRemainingCapacity(output, 4 + 12 + length))
1015
0
    return FALSE;
1016
1017
0
  if (length > UINT32_MAX - 12)
1018
0
    return FALSE;
1019
1020
0
  Stream_Write_UINT32(output, (UINT32)(12 + length)); /* Length */
1021
0
  Stream_Write_UINT32(output, 0);                     /* NextEntryOffset */
1022
0
  Stream_Write_UINT32(output, 0);                     /* FileIndex */
1023
0
  Stream_Write_UINT32(output, (UINT32)length);        /* FileNameLength */
1024
0
  Stream_Write(output, file->find_data.cFileName, length);
1025
0
  return TRUE;
1026
0
}
1027
1028
BOOL drive_file_query_directory(DRIVE_FILE* file, UINT32 FsInformationClass, BYTE InitialQuery,
1029
                                const WCHAR* path, UINT32 PathWCharLength, wStream* output)
1030
0
{
1031
0
  BOOL rc = FALSE;
1032
0
  size_t length = 0;
1033
0
  WCHAR* ent_path = NULL;
1034
1035
0
  if (!file || !path || !output)
1036
0
    return FALSE;
1037
1038
0
  if (InitialQuery != 0)
1039
0
  {
1040
    /* release search handle */
1041
0
    if (file->find_handle != INVALID_HANDLE_VALUE)
1042
0
      FindClose(file->find_handle);
1043
1044
0
    ent_path = drive_file_combine_fullpath(file->basepath, path, PathWCharLength);
1045
    /* open new search handle and retrieve the first entry */
1046
0
    file->find_handle = FindFirstFileW(ent_path, &file->find_data);
1047
0
    free(ent_path);
1048
1049
0
    if (file->find_handle == INVALID_HANDLE_VALUE)
1050
0
      goto out_fail;
1051
0
  }
1052
0
  else if (!FindNextFileW(file->find_handle, &file->find_data))
1053
0
    goto out_fail;
1054
1055
0
  length = _wcslen(file->find_data.cFileName) * 2;
1056
1057
0
  switch (FsInformationClass)
1058
0
  {
1059
0
    case FileDirectoryInformation:
1060
0
      rc = drive_file_query_dir_info(file, output, length);
1061
0
      break;
1062
1063
0
    case FileFullDirectoryInformation:
1064
0
      rc = drive_file_query_full_dir_info(file, output, length);
1065
0
      break;
1066
1067
0
    case FileBothDirectoryInformation:
1068
0
      rc = drive_file_query_both_dir_info(file, output, length);
1069
0
      break;
1070
1071
0
    case FileNamesInformation:
1072
0
      rc = drive_file_query_names_info(file, output, length);
1073
0
      break;
1074
1075
0
    default:
1076
0
      WLog_WARN(TAG, "Unhandled FSInformationClass %s [0x%08" PRIx32 "]",
1077
0
                FSInformationClass2Tag(FsInformationClass), FsInformationClass);
1078
      /* Unhandled FsInformationClass */
1079
0
      goto out_fail;
1080
0
  }
1081
1082
0
out_fail:
1083
0
  if (!rc)
1084
0
  {
1085
0
    Stream_Write_UINT32(output, 0); /* Length */
1086
0
    Stream_Write_UINT8(output, 0);  /* Padding */
1087
0
  }
1088
0
  return rc;
1089
0
}