1 /* -*- c-basic-offset: 8 -*-
2 rdesktop: A Remote Desktop Protocol client.
3 Disk Redirection
4 Copyright (C) Jeroen Meijer <jeroen@oldambt7.com> 2003-2008
5 Copyright 2003-2011 Peter Astrand <astrand@cendio.se> for Cendio AB
6 Copyright 2017 Henrik Andersson <hean01@cendio.se> for Cendio AB
7 Copyright 2017 Karl Mikaelsson <derfian@cendio.se> for Cendio AB
8 Copyright 2017 Alexander Zakharov <uglym8@gmail.com>
9
10 This program is free software: you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation, either version 3 of the License, or
13 (at your option) any later version.
14
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with this program. If not, see <http://www.gnu.org/licenses/>.
22 */
23
24 #include "disk.h"
25
26 #include <sys/types.h>
27 #include <sys/stat.h>
28 #include <unistd.h>
29 #include <fcntl.h> /* open, close */
30 #include <dirent.h> /* opendir, closedir, readdir */
31 #include <fnmatch.h>
32 #include <errno.h> /* errno */
33 #include <stdio.h>
34
35 #include <utime.h>
36 #include <time.h> /* ctime */
37
38 #if (defined(HAVE_DIRFD) || (HAVE_DECL_DIRFD == 1))
39 #define DIRFD(a) (dirfd(a))
40 #else
41 #define DIRFD(a) ((a)->DIR_FD_MEMBER_NAME)
42 #endif
43
44 /* TODO: Fix mntent-handling for solaris
45 * #include <sys/mntent.h> */
46 #if (defined(HAVE_MNTENT_H) && defined(HAVE_SETMNTENT))
47 #include <mntent.h>
48 #define MNTENT_PATH "/etc/mtab"
49 #define USE_SETMNTENT
50 #endif
51
52 #ifdef HAVE_SYS_VFS_H
53 #include <sys/vfs.h>
54 #endif
55
56 #ifdef HAVE_SYS_STATVFS_H
57 #include <sys/statvfs.h>
58 #endif
59
60 #ifdef HAVE_SYS_STATFS_H
61 #include <sys/statfs.h>
62 #endif
63
64 #ifdef HAVE_SYS_PARAM_H
65 #include <sys/param.h>
66 #endif
67
68 #ifdef HAVE_SYS_MOUNT_H
69 #include <sys/mount.h>
70 #endif
71
72 #include "rdesktop.h"
73
74 #ifdef STAT_STATFS3_OSF1
75 #define STATFS_FN(path, buf) (statfs(path,buf,sizeof(buf)))
76 #define STATFS_T statfs
77 #define USE_STATFS
78 #endif
79
80 #ifdef STAT_STATVFS
81 #define STATFS_FN(path, buf) (statvfs(path,buf))
82 #define STATFS_T statvfs
83 #define USE_STATVFS
84 #endif
85
86 #ifdef STAT_STATVFS64
87 #define STATFS_FN(path, buf) (statvfs64(path,buf))
88 #define STATFS_T statvfs64
89 #define USE_STATVFS
90 #endif
91
92 #if (defined(STAT_STATFS2_FS_DATA) || defined(STAT_STATFS2_BSIZE) || defined(STAT_STATFS2_FSIZE))
93 #define STATFS_FN(path, buf) (statfs(path,buf))
94 #define STATFS_T statfs
95 #define USE_STATFS
96 #endif
97
98 #ifdef STAT_STATFS4
99 #define STATFS_FN(path, buf) (statfs(path,buf,sizeof(buf),0))
100 #define STATFS_T statfs
101 #define USE_STATFS
102 #endif
103
104 #if ((defined(USE_STATFS) && defined(HAVE_STRUCT_STATFS_F_NAMEMAX)) || (defined(USE_STATVFS) && defined(HAVE_STRUCT_STATVFS_F_NAMEMAX)))
105 #define F_NAMELEN(buf) ((buf).f_namemax)
106 #endif
107
108 #if ((defined(USE_STATFS) && defined(HAVE_STRUCT_STATFS_F_NAMELEN)) || (defined(USE_STATVFS) && defined(HAVE_STRUCT_STATVFS_F_NAMELEN)))
109 #define F_NAMELEN(buf) ((buf).f_namelen)
110 #endif
111
112 #ifndef F_NAMELEN
113 #define F_NAMELEN(buf) (255)
114 #endif
115
116 /* Dummy statfs fallback */
117 #ifndef STATFS_T
118 struct dummy_statfs_t
119 {
120 long f_bfree;
121 long f_bsize;
122 long f_bavail;
123 long f_blocks;
124 int f_namelen;
125 int f_namemax;
126 };
127
128 static int
dummy_statfs(struct dummy_statfs_t * buf)129 dummy_statfs(struct dummy_statfs_t *buf)
130 {
131 buf->f_blocks = 262144;
132 buf->f_bfree = 131072;
133 buf->f_bavail = 131072;
134 buf->f_bsize = 512;
135 buf->f_namelen = 255;
136 buf->f_namemax = 255;
137
138 return 0;
139 }
140
141 #define STATFS_T dummy_statfs_t
142 #define STATFS_FN(path,buf) (dummy_statfs(buf))
143 #endif
144
145 extern RDPDR_DEVICE g_rdpdr_device[];
146
147 FILEINFO g_fileinfo[MAX_OPEN_FILES];
148 RD_BOOL g_notify_stamp = False;
149
150 typedef struct
151 {
152 char name[PATH_MAX];
153 char label[PATH_MAX];
154 unsigned long serial;
155 char type[PATH_MAX];
156 } FsInfoType;
157
158 static RD_NTSTATUS NotifyInfo(RD_NTHANDLE handle, uint32 info_class, NOTIFY * p);
159
160 static time_t
get_create_time(struct stat * filestat)161 get_create_time(struct stat *filestat)
162 {
163 time_t ret, ret1;
164
165 ret = MIN(filestat->st_ctime, filestat->st_mtime);
166 ret1 = MIN(ret, filestat->st_atime);
167
168 if (ret1 != (time_t) 0)
169 return ret1;
170
171 return ret;
172 }
173
174 /* Convert seconds since 1970 to a filetime */
175 static void
seconds_since_1970_to_filetime(time_t seconds,uint32 * high,uint32 * low)176 seconds_since_1970_to_filetime(time_t seconds, uint32 * high, uint32 * low)
177 {
178 unsigned long long ticks;
179
180 ticks = (seconds + 11644473600LL) * 10000000;
181 *low = (uint32) ticks;
182 *high = (uint32) (ticks >> 32);
183 }
184
185 /* Convert seconds since 1970 back to filetime */
186 static time_t
convert_1970_to_filetime(uint32 high,uint32 low)187 convert_1970_to_filetime(uint32 high, uint32 low)
188 {
189 unsigned long long ticks;
190 time_t val;
191
192 ticks = low + (((unsigned long long) high) << 32);
193 ticks /= 10000000;
194 ticks -= 11644473600LL;
195
196 val = (time_t) ticks;
197 return (val);
198
199 }
200
201 /* A wrapper for ftruncate which supports growing files, even if the
202 native ftruncate doesn't. This is needed on Linux FAT filesystems,
203 for example. */
204 static int
ftruncate_growable(int fd,off_t length)205 ftruncate_growable(int fd, off_t length)
206 {
207 int ret;
208 off_t pos;
209 static const char zero = 0;
210
211 /* Try the simple method first */
212 if ((ret = ftruncate(fd, length)) != -1)
213 {
214 return ret;
215 }
216
217 /*
218 * Some kind of error. Perhaps we were trying to grow. Retry
219 * in a safe way.
220 */
221
222 /* Get current position */
223 if ((pos = lseek(fd, 0, SEEK_CUR)) == -1)
224 {
225 logger(Disk, Error, "ftruncate_growable(), lseek() failed: %s", strerror(errno));
226 return -1;
227 }
228
229 /* Seek to new size */
230 if (lseek(fd, length, SEEK_SET) == -1)
231 {
232 logger(Disk, Error, "ftruncate_growable(), lseek() failed: %s", strerror(errno));
233 return -1;
234 }
235
236 /* Write a zero */
237 if (write(fd, &zero, 1) == -1)
238 {
239 logger(Disk, Error, "ftruncate_growable(), write() failed: %s", strerror(errno));
240 return -1;
241 }
242
243 /* Truncate. This shouldn't fail. */
244 if (ftruncate(fd, length) == -1)
245 {
246 logger(Disk, Error, "ftruncate_growable(), ftruncate() failed: %s",
247 strerror(errno));
248 return -1;
249 }
250
251 /* Restore position */
252 if (lseek(fd, pos, SEEK_SET) == -1)
253 {
254 logger(Disk, Error, "ftruncate_growable(), lseek() failed: %s", strerror(errno));
255 return -1;
256 }
257
258 return 0;
259 }
260
261 /* Just like open(2), but if a open with O_EXCL fails, retry with
262 GUARDED semantics. This might be necessary because some filesystems
263 (such as NFS filesystems mounted from a unfsd server) doesn't
264 support O_EXCL. GUARDED semantics are subject to race conditions,
265 but we can live with that.
266 */
267 static int
open_weak_exclusive(const char * pathname,int flags,mode_t mode)268 open_weak_exclusive(const char *pathname, int flags, mode_t mode)
269 {
270 int ret;
271 struct stat filestat;
272
273 ret = open(pathname, flags, mode);
274 if (ret != -1 || !(flags & O_EXCL))
275 {
276 /* Success, or not using O_EXCL */
277 return ret;
278 }
279
280 /* An error occurred, and we are using O_EXCL. In case the FS
281 doesn't support O_EXCL, some kind of error will be
282 returned. Unfortunately, we don't know which one. Linux
283 2.6.8 seems to return 524, but I cannot find a documented
284 #define for this case. So, we'll return only on errors that
285 we know aren't related to O_EXCL. */
286 switch (errno)
287 {
288 case EACCES:
289 case EEXIST:
290 case EINTR:
291 case EISDIR:
292 case ELOOP:
293 case ENAMETOOLONG:
294 case ENOENT:
295 case ENOTDIR:
296 return ret;
297 }
298
299 /* Retry with GUARDED semantics */
300 if (stat(pathname, &filestat) != -1)
301 {
302 /* File exists */
303 errno = EEXIST;
304 return -1;
305 }
306 else
307 {
308 return open(pathname, flags & ~O_EXCL, mode);
309 }
310 }
311
312 /* Enumeration of devices from rdesktop.c */
313 /* returns number of units found and initialized. */
314 /* optarg looks like ':h=/mnt/floppy,b=/mnt/usbdevice1' */
315 /* when it arrives to this function. */
316 int
disk_enum_devices(uint32 * id,char * optarg)317 disk_enum_devices(uint32 * id, char *optarg)
318 {
319 char *pos = optarg;
320 char *pos2;
321 int count = 0;
322 DISK_DEVICE *pdisk_data;
323
324 /* skip the first colon */
325 optarg++;
326 while ((pos = next_arg(optarg, ',')) && *id < RDPDR_MAX_DEVICES)
327 {
328 pos2 = next_arg(optarg, '=');
329
330 pdisk_data = (DISK_DEVICE *) xmalloc(sizeof(DISK_DEVICE));
331 memset(pdisk_data, 0, sizeof(DISK_DEVICE));
332 strncpy(pdisk_data->name, optarg, sizeof(pdisk_data->name) - 1);
333 strncpy(g_rdpdr_device[*id].name, optarg, sizeof(g_rdpdr_device[*id].name) - 1);
334
335 g_rdpdr_device[*id].local_path = (char *) xmalloc(strlen(pos2) + 1);
336 strcpy(g_rdpdr_device[*id].local_path, pos2);
337 g_rdpdr_device[*id].device_type = DEVICE_TYPE_DISK;
338 g_rdpdr_device[*id].pdevice_data = (void *) pdisk_data;
339
340 count++;
341 (*id)++;
342
343 optarg = pos;
344 }
345 return count;
346 }
347
348 /* Opens or creates a file or directory */
349 static RD_NTSTATUS
disk_create(uint32 device_id,uint32 accessmask,uint32 sharemode,uint32 create_disposition,uint32 flags_and_attributes,char * filename,RD_NTHANDLE * phandle)350 disk_create(uint32 device_id, uint32 accessmask, uint32 sharemode, uint32 create_disposition,
351 uint32 flags_and_attributes, char *filename, RD_NTHANDLE * phandle)
352 {
353 int handle;
354 DIR *dirp;
355 int flags, mode;
356 char path[PATH_MAX];
357 struct stat filestat;
358
359 logger(Disk, Debug, "disk_create(device_id=0x%x, accessmask=0x%x, sharemode=0x%x, "
360 "create_disp=%d, flags=0x%x, fname=%s, ...)", device_id, accessmask,
361 sharemode, create_disposition, flags_and_attributes, filename);
362 handle = 0;
363 dirp = NULL;
364 flags = 0;
365 mode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
366
367 if (filename && *filename && filename[strlen(filename) - 1] == '/')
368 filename[strlen(filename) - 1] = 0;
369
370 sprintf(path, "%s%s", g_rdpdr_device[device_id].local_path, filename ? filename : "");
371
372 /* Protect against malicious servers:
373 somelongpath/.. not allowed
374 somelongpath/../b not allowed
375 somelongpath/..b in principle ok, but currently not allowed
376 somelongpath/b.. ok
377 somelongpath/b..b ok
378 somelongpath/b../c ok
379 */
380 if (strstr(path, "/.."))
381 {
382 return RD_STATUS_ACCESS_DENIED;
383 }
384
385 switch (create_disposition)
386 {
387 case CREATE_ALWAYS:
388
389 /* Delete existing file/link. */
390 unlink(path);
391 flags |= O_CREAT;
392 break;
393
394 case CREATE_NEW:
395
396 /* If the file already exists, then fail. */
397 flags |= O_CREAT | O_EXCL;
398 break;
399
400 case OPEN_ALWAYS:
401
402 /* Create if not already exists. */
403 flags |= O_CREAT;
404 break;
405
406 case OPEN_EXISTING:
407
408 /* Default behaviour */
409 break;
410
411 case TRUNCATE_EXISTING:
412
413 /* If the file does not exist, then fail. */
414 flags |= O_TRUNC;
415 break;
416 }
417
418 /*printf("Open: \"%s\" flags: %X, accessmask: %X sharemode: %X create disp: %X\n", path, flags_and_attributes, accessmask, sharemode, create_disposition); */
419
420 /* Get information about file and set that flag ourselves */
421 if ((stat(path, &filestat) == 0) && (S_ISDIR(filestat.st_mode)))
422 {
423 if (flags_and_attributes & FILE_NON_DIRECTORY_FILE)
424 return RD_STATUS_FILE_IS_A_DIRECTORY;
425 else
426 flags_and_attributes |= FILE_DIRECTORY_FILE;
427 }
428
429 if (flags_and_attributes & FILE_DIRECTORY_FILE)
430 {
431 if (flags & O_CREAT)
432 {
433 mkdir(path, mode);
434 }
435
436 dirp = opendir(path);
437 if (!dirp)
438 {
439 switch (errno)
440 {
441 case EACCES:
442
443 return RD_STATUS_ACCESS_DENIED;
444
445 case ENOENT:
446
447 return RD_STATUS_NO_SUCH_FILE;
448
449 default:
450 logger(Disk, Error, "disk_create(), opendir() failed: %s",
451 strerror(errno));
452 return RD_STATUS_NO_SUCH_FILE;
453 }
454 }
455 handle = DIRFD(dirp);
456 }
457 else
458 {
459
460 if (accessmask & GENERIC_ALL
461 || (accessmask & GENERIC_READ && accessmask & GENERIC_WRITE))
462 {
463 flags |= O_RDWR;
464 }
465 else if ((accessmask & GENERIC_WRITE) && !(accessmask & GENERIC_READ))
466 {
467 flags |= O_WRONLY;
468 }
469 else
470 {
471 flags |= O_RDONLY;
472 }
473
474 handle = open_weak_exclusive(path, flags, mode);
475 if (handle == -1)
476 {
477 switch (errno)
478 {
479 case EISDIR:
480
481 return RD_STATUS_FILE_IS_A_DIRECTORY;
482
483 case EACCES:
484
485 return RD_STATUS_ACCESS_DENIED;
486
487 case ENOENT:
488
489 return RD_STATUS_NO_SUCH_FILE;
490 case EEXIST:
491
492 return RD_STATUS_OBJECT_NAME_COLLISION;
493 default:
494 logger(Disk, Error, "disk_create(), open() failed: %s",
495 strerror(errno));
496 return RD_STATUS_NO_SUCH_FILE;
497 }
498 }
499
500 /* all read and writes of files should be non blocking */
501 if (fcntl(handle, F_SETFL, O_NONBLOCK) == -1)
502 logger(Disk, Error, "disk_create(), fcntl() failed: %s", strerror(errno));
503
504 }
505
506 if (handle >= MAX_OPEN_FILES)
507 {
508 logger(Disk, Error,
509 "disk_create(), handle (%d) is greater than or equal to MAX_OPEN_FILES (%d)!",
510 handle, MAX_OPEN_FILES);
511 exit(EX_SOFTWARE);
512 }
513
514 if (dirp)
515 g_fileinfo[handle].pdir = dirp;
516 else
517 g_fileinfo[handle].pdir = NULL;
518
519 g_fileinfo[handle].device_id = device_id;
520 g_fileinfo[handle].flags_and_attributes = flags_and_attributes;
521 g_fileinfo[handle].accessmask = accessmask;
522 strncpy(g_fileinfo[handle].path, path, PATH_MAX - 1);
523 g_fileinfo[handle].delete_on_close = False;
524
525 if (accessmask & GENERIC_ALL || accessmask & GENERIC_WRITE)
526 g_notify_stamp = True;
527
528 *phandle = handle;
529 return RD_STATUS_SUCCESS;
530 }
531
532 static RD_NTSTATUS
disk_close(RD_NTHANDLE handle)533 disk_close(RD_NTHANDLE handle)
534 {
535 struct fileinfo *pfinfo;
536
537 logger(Disk, Debug, "disk_close(handle=0x%x)", handle);
538
539 pfinfo = &(g_fileinfo[handle]);
540
541 if (pfinfo->accessmask & GENERIC_ALL || pfinfo->accessmask & GENERIC_WRITE)
542 g_notify_stamp = True;
543
544 rdpdr_abort_io(handle, 0, RD_STATUS_CANCELLED);
545
546 if (pfinfo->pdir)
547 {
548 if (closedir(pfinfo->pdir) < 0)
549 {
550 logger(Disk, Error, "disk_close(), closedir() failed: %s", strerror(errno));
551 return RD_STATUS_INVALID_HANDLE;
552 }
553
554 if (pfinfo->delete_on_close)
555 if (rmdir(pfinfo->path) < 0)
556 {
557 logger(Disk, Error, "disk_close(), rmdir() failed: %s",
558 strerror(errno));
559 return RD_STATUS_ACCESS_DENIED;
560 }
561 pfinfo->delete_on_close = False;
562 }
563 else
564 {
565 if (close(handle) < 0)
566 {
567 logger(Disk, Error, "disk_close(), close() failed: %s", strerror(errno));
568 return RD_STATUS_INVALID_HANDLE;
569 }
570 if (pfinfo->delete_on_close)
571 if (unlink(pfinfo->path) < 0)
572 {
573 logger(Disk, Error, "disk_close(), unlink() failed: %s",
574 strerror(errno));
575 return RD_STATUS_ACCESS_DENIED;
576 }
577
578 pfinfo->delete_on_close = False;
579 }
580
581 return RD_STATUS_SUCCESS;
582 }
583
584 static RD_NTSTATUS
disk_read(RD_NTHANDLE handle,uint8 * data,uint32 length,uint64 offset,uint32 * result)585 disk_read(RD_NTHANDLE handle, uint8 * data, uint32 length, uint64 offset, uint32 * result)
586 {
587 int n;
588
589 #if 0
590 /* browsing dir ???? */
591 /* each request is 24 bytes */
592 if (g_fileinfo[handle].flags_and_attributes & FILE_DIRECTORY_FILE)
593 {
594 *result = 0;
595 return STATUS_SUCCESS;
596 }
597 #endif
598
599 lseek(handle, offset, SEEK_SET);
600
601 n = read(handle, data, length);
602
603 if (n < 0)
604 {
605 *result = 0;
606 switch (errno)
607 {
608 case EISDIR:
609 /* Implement 24 Byte directory read ??
610 with STATUS_NOT_IMPLEMENTED server doesn't read again */
611 /* return STATUS_FILE_IS_A_DIRECTORY; */
612 return RD_STATUS_NOT_IMPLEMENTED;
613 default:
614 logger(Disk, Error, "disk_read(), read failed: %s",
615 strerror(errno));
616 return RD_STATUS_INVALID_PARAMETER;
617 }
618 }
619
620 *result = n;
621
622 return RD_STATUS_SUCCESS;
623 }
624
625 static RD_NTSTATUS
disk_write(RD_NTHANDLE handle,uint8 * data,uint32 length,uint64 offset,uint32 * result)626 disk_write(RD_NTHANDLE handle, uint8 * data, uint32 length, uint64 offset, uint32 * result)
627 {
628 int n;
629
630 lseek(handle, offset, SEEK_SET);
631
632 n = write(handle, data, length);
633
634 if (n < 0)
635 {
636 logger(Disk, Error, "disk_write(), write() failed: %s", strerror(errno));
637 *result = 0;
638 switch (errno)
639 {
640 case ENOSPC:
641 return RD_STATUS_DISK_FULL;
642 default:
643 return RD_STATUS_ACCESS_DENIED;
644 }
645 }
646
647 *result = n;
648
649 return RD_STATUS_SUCCESS;
650 }
651
652 /* Btw, all used Flie* structures are described in [MS-FSCC] */
653 RD_NTSTATUS
disk_query_information(RD_NTHANDLE handle,uint32 info_class,STREAM out)654 disk_query_information(RD_NTHANDLE handle, uint32 info_class, STREAM out)
655 {
656 uint32 file_attributes, ft_high, ft_low;
657 struct stat filestat;
658 char *path, *filename;
659
660 logger(Disk, Debug, "disk_query_information(handle=0x%x, info_class=0x%x)", handle,
661 info_class);
662
663 path = g_fileinfo[handle].path;
664
665 /* Get information about file */
666 if (fstat(handle, &filestat) != 0)
667 {
668 logger(Disk, Error, "disk_query_information(), stat() failed: %s", strerror(errno));
669 out_uint8(out, 0);
670 return RD_STATUS_ACCESS_DENIED;
671 }
672
673 /* Set file attributes */
674 file_attributes = 0;
675 if (S_ISDIR(filestat.st_mode))
676 file_attributes |= FILE_ATTRIBUTE_DIRECTORY;
677
678 filename = strrchr(path, '/');
679 if (filename)
680 filename += 1;
681
682 if (filename && filename[0] == '.')
683 file_attributes |= FILE_ATTRIBUTE_HIDDEN;
684
685 if (!file_attributes)
686 file_attributes |= FILE_ATTRIBUTE_NORMAL;
687
688 if (!(filestat.st_mode & S_IWUSR))
689 file_attributes |= FILE_ATTRIBUTE_READONLY;
690
691 /* Return requested data */
692 switch (info_class)
693 {
694 case FileBasicInformation:
695 seconds_since_1970_to_filetime(get_create_time(&filestat), &ft_high,
696 &ft_low);
697 out_uint32_le(out, ft_low); /* create_access_time */
698 out_uint32_le(out, ft_high);
699
700 seconds_since_1970_to_filetime(filestat.st_atime, &ft_high, &ft_low);
701 out_uint32_le(out, ft_low); /* last_access_time */
702 out_uint32_le(out, ft_high);
703
704 seconds_since_1970_to_filetime(filestat.st_mtime, &ft_high, &ft_low);
705 out_uint32_le(out, ft_low); /* last_write_time */
706 out_uint32_le(out, ft_high);
707
708 seconds_since_1970_to_filetime(filestat.st_ctime, &ft_high, &ft_low);
709 out_uint32_le(out, ft_low); /* last_change_time */
710 out_uint32_le(out, ft_high);
711
712 out_uint32_le(out, file_attributes);
713 break;
714
715 case FileStandardInformation:
716
717 out_uint64_le(out, filestat.st_size); /* Allocation size */
718 out_uint64_le(out, filestat.st_size); /* End of file */
719
720 out_uint32_le(out, filestat.st_nlink); /* Number of links */
721 out_uint8(out, 0); /* Delete pending */
722 out_uint8(out, S_ISDIR(filestat.st_mode) ? 1 : 0); /* Directory */
723 break;
724
725 case FileObjectIdInformation:
726
727 out_uint32_le(out, file_attributes); /* File Attributes */
728 out_uint32_le(out, 0); /* Reparse Tag */
729 break;
730
731 default:
732 logger(Disk, Warning,
733 "disk_query_information(), unhandled query information class 0x%x",
734 info_class);
735 return RD_STATUS_INVALID_PARAMETER;
736 }
737 return RD_STATUS_SUCCESS;
738 }
739
740 /* 2.2.3.3.9 [MS-RDPEFS] */
741 RD_NTSTATUS
disk_set_information(RD_NTHANDLE handle,uint32 info_class,STREAM in,STREAM out)742 disk_set_information(RD_NTHANDLE handle, uint32 info_class, STREAM in, STREAM out)
743 {
744 UNUSED(out);
745 uint32 length, file_attributes, ft_high, ft_low;
746 char *newname, fullpath[PATH_MAX];
747 struct fileinfo *pfinfo;
748 int mode;
749 struct stat filestat;
750 time_t write_time, change_time, access_time, mod_time;
751 struct utimbuf tvs;
752 struct STATFS_T stat_fs;
753
754 logger(Disk, Debug, "disk_set_information(handle=0x%x, info_class=0x%x, ...)", handle,
755 info_class);
756
757 pfinfo = &(g_fileinfo[handle]);
758 g_notify_stamp = True;
759 newname = NULL;
760
761 switch (info_class)
762 {
763 case FileBasicInformation:
764 write_time = change_time = access_time = 0;
765
766 in_uint8s(in, 4); /* length of SetBuffer */
767 in_uint8s(in, 24); /* padding */
768
769 /* CreationTime */
770 in_uint32_le(in, ft_low);
771 in_uint32_le(in, ft_high);
772
773 /* AccessTime */
774 in_uint32_le(in, ft_low);
775 in_uint32_le(in, ft_high);
776 if (ft_low || ft_high)
777 access_time = convert_1970_to_filetime(ft_high, ft_low);
778
779 /* WriteTime */
780 in_uint32_le(in, ft_low);
781 in_uint32_le(in, ft_high);
782 if (ft_low || ft_high)
783 write_time = convert_1970_to_filetime(ft_high, ft_low);
784
785 /* ChangeTime */
786 in_uint32_le(in, ft_low);
787 in_uint32_le(in, ft_high);
788 if (ft_low || ft_high)
789 change_time = convert_1970_to_filetime(ft_high, ft_low);
790
791 in_uint32_le(in, file_attributes);
792
793 if (fstat(handle, &filestat))
794 return RD_STATUS_ACCESS_DENIED;
795
796 tvs.modtime = filestat.st_mtime;
797 tvs.actime = filestat.st_atime;
798 if (access_time)
799 tvs.actime = access_time;
800
801
802 if (write_time || change_time)
803 mod_time = MIN(write_time, change_time);
804 else
805 mod_time = write_time ? write_time : change_time;
806
807 if (mod_time)
808 tvs.modtime = mod_time;
809
810
811 if (access_time || write_time || change_time)
812 {
813 logger(Disk, Debug,
814 "disk_set_information(), access time='%s', modify time='%s'",
815 ctime(&tvs.actime), ctime(&tvs.modtime));
816 if (utime(pfinfo->path, &tvs) && errno != EPERM)
817 return RD_STATUS_ACCESS_DENIED;
818 }
819
820 if (!file_attributes)
821 break; /* not valid */
822
823 mode = filestat.st_mode;
824
825 if (file_attributes & FILE_ATTRIBUTE_READONLY)
826 mode &= ~(S_IWUSR | S_IWGRP | S_IWOTH);
827 else
828 mode |= S_IWUSR;
829
830 mode &= 0777;
831
832 logger(Disk, Debug, "disk_set_information(), access mode 0%o", mode);
833
834 if (fchmod(handle, mode))
835 return RD_STATUS_ACCESS_DENIED;
836
837 break;
838
839 case FileRenameInformation:
840
841 in_uint8s(in, 4); /* Handle of root dir? */
842 in_uint8s(in, 0x1a); /* unknown */
843 in_uint32_le(in, length);
844
845 if (length && (length / 2) >= 256)
846 return RD_STATUS_INVALID_PARAMETER;
847
848 rdp_in_unistr(in, length, &newname, &length);
849 if (newname == NULL)
850 return RD_STATUS_INVALID_PARAMETER;
851
852 convert_to_unix_filename(newname);
853
854 sprintf(fullpath, "%s%s", g_rdpdr_device[pfinfo->device_id].local_path,
855 newname);
856
857 free(newname);
858
859 if (rename(pfinfo->path, fullpath) != 0)
860 {
861 logger(Disk, Error, "disk_set_information(), rename() failed: %s",
862 strerror(errno));
863 return RD_STATUS_ACCESS_DENIED;
864 }
865 break;
866
867 case FileDispositionInformation:
868 /* As far as I understand it, the correct
869 thing to do here is to *schedule* a delete,
870 so it will be deleted when the file is
871 closed. Subsequent
872 FileDispositionInformation requests with
873 DeleteFile set to FALSE should unschedule
874 the delete. See
875 http://www.osronline.com/article.cfm?article=245. */
876
877 /* FileDispositionInformation always sets delete_on_close to true.
878 "STREAM in" includes Length(4bytes) , Padding(24bytes) and SetBuffer(zero byte).
879 Length is always set to zero.
880 [MS-RDPEFS] http://msdn.microsoft.com/en-us/library/cc241305%28PROT.10%29.aspx
881 - 2.2.3.3.9 Server Drive Set Information Request
882 */
883 in_uint8s(in, 4); /* length of SetBuffer */
884 in_uint8s(in, 24); /* padding */
885
886
887 if ((pfinfo->accessmask &
888 (FILE_DELETE_ON_CLOSE | FILE_COMPLETE_IF_OPLOCKED)))
889 {
890 /* if file exists in directory , necessary to return RD_STATUS_DIRECTORY_NOT_EMPTY with win2008
891 [MS-RDPEFS] http://msdn.microsoft.com/en-us/library/cc241305%28PROT.10%29.aspx
892 - 2.2.3.3.9 Server Drive Set Information Request
893 - 2.2.3.4.9 Client Drive Set Information Response
894 [MS-FSCC] http://msdn.microsoft.com/en-us/library/cc231987%28PROT.10%29.aspx
895 - 2.4.11 FileDispositionInformation
896 [FSBO] http://msdn.microsoft.com/en-us/library/cc246487%28PROT.13%29.aspx
897 - 4.3.2 Set Delete-on-close using FileDispositionInformation Information Class (IRP_MJ_SET_INFORMATION)
898 */
899 if (pfinfo->pdir)
900 {
901 DIR *dp = opendir(pfinfo->path);
902 struct dirent *dir;
903
904 while ((dir = readdir(dp)) != NULL)
905 {
906 if (strcmp(dir->d_name, ".") != 0
907 && strcmp(dir->d_name, "..") != 0)
908 {
909 closedir(dp);
910 return RD_STATUS_DIRECTORY_NOT_EMPTY;
911 }
912 }
913 closedir(dp);
914 }
915
916 pfinfo->delete_on_close = True;
917 }
918
919 break;
920
921 case FileAllocationInformation:
922 /* Fall through to FileEndOfFileInformation,
923 which uses ftrunc. This is like Samba with
924 "strict allocation = false", and means that
925 we won't detect out-of-quota errors, for
926 example. */
927
928 case FileEndOfFileInformation:
929 in_uint8s(in, 28); /* unknown */
930 in_uint32_le(in, length); /* file size */
931
932 /* prevents start of writing if not enough space left on device */
933 if (STATFS_FN(pfinfo->path, &stat_fs) == 0)
934 if (stat_fs.f_bfree * stat_fs.f_bsize < length)
935 return RD_STATUS_DISK_FULL;
936
937 if (ftruncate_growable(handle, length) != 0)
938 {
939 return RD_STATUS_DISK_FULL;
940 }
941
942 break;
943 default:
944 logger(Disk, Warning,
945 "disk_set_information(), unhandled information class 0x%x",
946 info_class);
947 return RD_STATUS_INVALID_PARAMETER;
948 }
949 return RD_STATUS_SUCCESS;
950 }
951
952 RD_NTSTATUS
disk_check_notify(RD_NTHANDLE handle)953 disk_check_notify(RD_NTHANDLE handle)
954 {
955 struct fileinfo *pfinfo;
956 RD_NTSTATUS status = RD_STATUS_PENDING;
957 NOTIFY notify;
958
959 logger(Disk, Debug, "disk_check_notify(handle=0x%x)", handle);
960
961 pfinfo = &(g_fileinfo[handle]);
962 if (!pfinfo->pdir)
963 return RD_STATUS_INVALID_DEVICE_REQUEST;
964
965
966
967 status = NotifyInfo(handle, pfinfo->info_class, ¬ify);
968
969 if (status != RD_STATUS_PENDING)
970 return status;
971
972 if (memcmp(&pfinfo->notify, ¬ify, sizeof(NOTIFY)))
973 {
974 /*printf("disk_check_notify found changed event\n"); */
975 memcpy(&pfinfo->notify, ¬ify, sizeof(NOTIFY));
976 status = RD_STATUS_NOTIFY_ENUM_DIR;
977 }
978
979 return status;
980
981
982 }
983
984 RD_NTSTATUS
disk_create_notify(RD_NTHANDLE handle,uint32 info_class)985 disk_create_notify(RD_NTHANDLE handle, uint32 info_class)
986 {
987 struct fileinfo *pfinfo;
988 RD_NTSTATUS ret = RD_STATUS_PENDING;
989
990 logger(Disk, Debug, "disk_create_notify(handle=0x%x, info_class=0x%x)", handle, info_class);
991
992 pfinfo = &(g_fileinfo[handle]);
993 pfinfo->info_class = info_class;
994
995 ret = NotifyInfo(handle, info_class, &pfinfo->notify);
996
997 if (info_class & 0x1000)
998 { /* ???? */
999 if (ret == RD_STATUS_PENDING)
1000 return RD_STATUS_SUCCESS;
1001 }
1002
1003 /* printf("disk_create_notify: num_entries %d\n", pfinfo->notify.num_entries); */
1004
1005
1006 return ret;
1007
1008 }
1009
1010 static RD_NTSTATUS
NotifyInfo(RD_NTHANDLE handle,uint32 info_class,NOTIFY * p)1011 NotifyInfo(RD_NTHANDLE handle, uint32 info_class, NOTIFY * p)
1012 {
1013 UNUSED(info_class);
1014 struct fileinfo *pfinfo;
1015 struct stat filestat;
1016 struct dirent *dp;
1017 char *fullname;
1018 DIR *dpr;
1019
1020 pfinfo = &(g_fileinfo[handle]);
1021 if (fstat(handle, &filestat) < 0)
1022 {
1023 logger(Disk, Error, "NotifyInfo(), fstat failed: %s", strerror(errno));
1024 return RD_STATUS_ACCESS_DENIED;
1025 }
1026 p->modify_time = filestat.st_mtime;
1027 p->status_time = filestat.st_ctime;
1028 p->num_entries = 0;
1029 p->total_time = 0;
1030
1031
1032 dpr = opendir(pfinfo->path);
1033 if (!dpr)
1034 {
1035 logger(Disk, Error, "NotifyInfo(), opendir failed: %s", strerror(errno));
1036 return RD_STATUS_ACCESS_DENIED;
1037 }
1038
1039
1040 while ((dp = readdir(dpr)))
1041 {
1042 if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, ".."))
1043 continue;
1044 p->num_entries++;
1045 fullname = (char *) xmalloc(strlen(pfinfo->path) + strlen(dp->d_name) + 2);
1046 sprintf(fullname, "%s/%s", pfinfo->path, dp->d_name);
1047
1048 if (!stat(fullname, &filestat))
1049 {
1050 p->total_time += (filestat.st_mtime + filestat.st_ctime);
1051 }
1052
1053 xfree(fullname);
1054 }
1055 closedir(dpr);
1056
1057 return RD_STATUS_PENDING;
1058 }
1059
1060 static FsInfoType *
FsVolumeInfo(char * fpath)1061 FsVolumeInfo(char *fpath)
1062 {
1063
1064 static FsInfoType info;
1065 #ifdef USE_SETMNTENT
1066 FILE *fdfs;
1067 struct mntent *e;
1068 #endif
1069
1070 /* initialize */
1071 memset(&info, 0, sizeof(info));
1072 strcpy(info.label, "RDESKTOP");
1073 strcpy(info.type, "RDPFS");
1074
1075 #ifdef USE_SETMNTENT
1076 fdfs = setmntent(MNTENT_PATH, "r");
1077 if (!fdfs)
1078 return &info;
1079
1080 while ((e = getmntent(fdfs)))
1081 {
1082 if (str_startswith(e->mnt_dir, fpath))
1083 {
1084 strcpy(info.type, e->mnt_type);
1085 strcpy(info.name, e->mnt_fsname);
1086 if (strstr(e->mnt_opts, "vfat") || strstr(e->mnt_opts, "iso9660"))
1087 {
1088 int fd = open(e->mnt_fsname, O_RDONLY);
1089 if (fd >= 0)
1090 {
1091 unsigned char buf[512];
1092 memset(buf, 0, sizeof(buf));
1093 if (strstr(e->mnt_opts, "vfat"))
1094 /*FAT*/
1095 {
1096 strcpy(info.type, "vfat");
1097 read(fd, buf, sizeof(buf));
1098 info.serial =
1099 (buf[42] << 24) + (buf[41] << 16) +
1100 (buf[40] << 8) + buf[39];
1101 strncpy(info.label, (char *) buf + 43, 10);
1102 info.label[10] = '\0';
1103 }
1104 else if (lseek(fd, 32767, SEEK_SET) >= 0) /* ISO9660 */
1105 {
1106 read(fd, buf, sizeof(buf));
1107 strncpy(info.label, (char *) buf + 41, 32);
1108 info.label[32] = '\0';
1109 /* info.Serial = (buf[128]<<24)+(buf[127]<<16)+(buf[126]<<8)+buf[125]; */
1110 }
1111 close(fd);
1112 }
1113 }
1114 }
1115 }
1116 endmntent(fdfs);
1117 #else
1118 /* initialize */
1119 memset(&info, 0, sizeof(info));
1120 strcpy(info.label, "RDESKTOP");
1121 strcpy(info.type, "RDPFS");
1122
1123 #endif
1124 return &info;
1125 }
1126
1127
1128 RD_NTSTATUS
disk_query_volume_information(RD_NTHANDLE handle,uint32 info_class,STREAM out)1129 disk_query_volume_information(RD_NTHANDLE handle, uint32 info_class, STREAM out)
1130 {
1131 struct STATFS_T stat_fs;
1132 struct fileinfo *pfinfo;
1133 FsInfoType *fsinfo;
1134 STREAM stmp;
1135
1136 logger(Disk, Debug, "disk_query_volume_information(handle=0x%x, info_class=0x%x)", handle,
1137 info_class);
1138
1139 pfinfo = &(g_fileinfo[handle]);
1140
1141 if (STATFS_FN(pfinfo->path, &stat_fs) != 0)
1142 {
1143 logger(Disk, Error, "disk_query_volume_information(), statfs() failed: %s",
1144 strerror(errno));
1145 return RD_STATUS_ACCESS_DENIED;
1146 }
1147
1148 fsinfo = FsVolumeInfo(pfinfo->path);
1149
1150 switch (info_class)
1151 {
1152 case FileFsVolumeInformation:
1153 stmp = s_alloc(PATH_MAX * 4);
1154 out_utf16s(stmp, fsinfo->label);
1155 s_mark_end(stmp);
1156
1157 out_uint32_le(out, 0); /* volume creation time low */
1158 out_uint32_le(out, 0); /* volume creation time high */
1159 out_uint32_le(out, fsinfo->serial); /* serial */
1160 out_uint32_le(out, s_length(stmp)); /* length of string */
1161 out_uint8(out, 0); /* support objects? */
1162 out_stream(out, stmp); /* fsinfo->label string */
1163 s_free(stmp);
1164 break;
1165
1166 case FileFsSizeInformation:
1167
1168 out_uint64_le(out, stat_fs.f_blocks); /* Total allocation units */
1169 out_uint64_le(out, stat_fs.f_bfree); /* Available allocation units */
1170 out_uint32_le(out, stat_fs.f_bsize / 0x200); /* Sectors per allocation unit */
1171 out_uint32_le(out, 0x200); /* Bytes per sector */
1172 break;
1173
1174 case FileFsFullSizeInformation:
1175
1176 out_uint64_le(out, stat_fs.f_blocks); /* Total allocation units */
1177 out_uint64_le(out, stat_fs.f_bavail); /* Caller allocation units */
1178 out_uint64_le(out, stat_fs.f_bfree); /* Available allocation units */
1179 out_uint32_le(out, stat_fs.f_bsize / 0x200); /* Sectors per allocation unit */
1180 out_uint32_le(out, 0x200); /* Bytes per sector */
1181 break;
1182
1183 case FileFsAttributeInformation:
1184 stmp = s_alloc(PATH_MAX * 4);
1185 out_utf16s_no_eos(stmp, fsinfo->type);
1186 s_mark_end(stmp);
1187
1188 out_uint32_le(out, FS_CASE_SENSITIVE | FS_CASE_IS_PRESERVED); /* fs attributes */
1189 out_uint32_le(out, F_NAMELEN(stat_fs)); /* max length of filename */
1190
1191 out_uint32_le(out, s_length(stmp)); /* length of fsinfo->type string */
1192 out_stream(out, stmp); /* fsinfo->typ string */
1193 s_free(stmp);
1194 break;
1195
1196 case FileFsLabelInformation:
1197 case FileFsDeviceInformation:
1198 case FileFsControlInformation:
1199 case FileFsObjectIdInformation:
1200 case FileFsMaximumInformation:
1201
1202 default:
1203 logger(Disk, Warning,
1204 "disk_query_volume_information(), unhandled volume info class 0x%x",
1205 info_class);
1206 return RD_STATUS_INVALID_PARAMETER;
1207 }
1208 return RD_STATUS_SUCCESS;
1209 }
1210
1211 RD_NTSTATUS
disk_query_directory(RD_NTHANDLE handle,uint32 info_class,char * pattern,STREAM out)1212 disk_query_directory(RD_NTHANDLE handle, uint32 info_class, char *pattern, STREAM out)
1213 {
1214 uint32 file_attributes, ft_low, ft_high;
1215 char *dirname, fullpath[PATH_MAX];
1216 DIR *pdir;
1217 struct dirent *pdirent;
1218 struct stat filestat;
1219 struct fileinfo *pfinfo;
1220 STREAM stmp;
1221
1222 logger(Disk, Debug, "disk_query_directory(handle=0x%x, info_class=0x%x, pattern=%s, ...)",
1223 handle, info_class, pattern);
1224
1225 pfinfo = &(g_fileinfo[handle]);
1226 pdir = pfinfo->pdir;
1227 dirname = pfinfo->path;
1228 file_attributes = 0;
1229
1230 switch (info_class)
1231 {
1232 case FileBothDirectoryInformation:
1233 case FileDirectoryInformation:
1234 case FileFullDirectoryInformation:
1235 case FileNamesInformation:
1236
1237 /* If a search pattern is received, remember this pattern, and restart search */
1238 if (pattern != NULL && pattern[0] != 0)
1239 {
1240 strncpy(pfinfo->pattern, 1 + strrchr(pattern, '/'), PATH_MAX - 1);
1241 rewinddir(pdir);
1242 }
1243
1244 /* find next dirent matching pattern */
1245 pdirent = readdir(pdir);
1246 while (pdirent && fnmatch(pfinfo->pattern, pdirent->d_name, 0) != 0)
1247 pdirent = readdir(pdir);
1248
1249 if (pdirent == NULL)
1250 return RD_STATUS_NO_MORE_FILES;
1251
1252 /* Get information for directory entry */
1253 sprintf(fullpath, "%s/%s", dirname, pdirent->d_name);
1254
1255 if (stat(fullpath, &filestat))
1256 {
1257 switch (errno)
1258 {
1259 case ENOENT:
1260 case ELOOP:
1261 case EACCES:
1262 /* These are non-fatal errors. */
1263 memset(&filestat, 0, sizeof(filestat));
1264 break;
1265 default:
1266 /* Fatal error. By returning STATUS_NO_SUCH_FILE,
1267 the directory list operation will be aborted */
1268 logger(Disk, Error,
1269 "disk_query_directory(), stat() failed: %s",
1270 strerror(errno));
1271 out_uint8(out, 0);
1272 return RD_STATUS_NO_SUCH_FILE;
1273 }
1274 }
1275
1276 if (S_ISDIR(filestat.st_mode))
1277 file_attributes |= FILE_ATTRIBUTE_DIRECTORY;
1278 if (pdirent->d_name[0] == '.')
1279 file_attributes |= FILE_ATTRIBUTE_HIDDEN;
1280 if (!file_attributes)
1281 file_attributes |= FILE_ATTRIBUTE_NORMAL;
1282 if (!(filestat.st_mode & S_IWUSR))
1283 file_attributes |= FILE_ATTRIBUTE_READONLY;
1284
1285 /* Return requested information */
1286 out_uint32_le(out, 0); /* NextEntryOffset */
1287 out_uint32_le(out, 0); /* FileIndex zero */
1288 break;
1289
1290 default:
1291 logger(Disk, Warning,
1292 "disk_query_directory(), unhandled directory info class 0x%x",
1293 info_class);
1294 return RD_STATUS_INVALID_PARAMETER;
1295 }
1296
1297 // Write entry name as utf16 into stmp
1298 stmp = s_alloc(PATH_MAX * 4);
1299 out_utf16s_no_eos(stmp, pdirent->d_name);
1300 s_mark_end(stmp);
1301
1302 switch (info_class)
1303 {
1304 case FileBothDirectoryInformation:
1305
1306 seconds_since_1970_to_filetime(get_create_time(&filestat), &ft_high,
1307 &ft_low);
1308 out_uint32_le(out, ft_low); /* create time */
1309 out_uint32_le(out, ft_high);
1310
1311 seconds_since_1970_to_filetime(filestat.st_atime, &ft_high, &ft_low);
1312 out_uint32_le(out, ft_low); /* last_access_time */
1313 out_uint32_le(out, ft_high);
1314
1315 seconds_since_1970_to_filetime(filestat.st_mtime, &ft_high, &ft_low);
1316 out_uint32_le(out, ft_low); /* last_write_time */
1317 out_uint32_le(out, ft_high);
1318
1319 seconds_since_1970_to_filetime(filestat.st_ctime, &ft_high, &ft_low);
1320 out_uint32_le(out, ft_low); /* change_write_time */
1321 out_uint32_le(out, ft_high);
1322
1323 out_uint64_le(out, filestat.st_size); /* filesize */
1324 out_uint64_le(out, filestat.st_size); /* filesize */
1325 out_uint32_le(out, file_attributes); /* FileAttributes */
1326 out_uint32_le(out, s_length(stmp)); /* length of dir entry name string */
1327 out_uint32_le(out, 0); /* EaSize */
1328 out_uint8(out, 0); /* ShortNameLength */
1329 out_uint8s(out, 24); /* ShortName (8.3 name) */
1330 out_stream(out, stmp); /* dir entry name string */
1331 break;
1332
1333
1334 case FileDirectoryInformation:
1335
1336 seconds_since_1970_to_filetime(get_create_time(&filestat), &ft_high,
1337 &ft_low);
1338 out_uint32_le(out, ft_low); /* create time */
1339 out_uint32_le(out, ft_high);
1340
1341 seconds_since_1970_to_filetime(filestat.st_atime, &ft_high, &ft_low);
1342 out_uint32_le(out, ft_low); /* last_access_time */
1343 out_uint32_le(out, ft_high);
1344
1345 seconds_since_1970_to_filetime(filestat.st_mtime, &ft_high, &ft_low);
1346 out_uint32_le(out, ft_low); /* last_write_time */
1347 out_uint32_le(out, ft_high);
1348
1349 seconds_since_1970_to_filetime(filestat.st_ctime, &ft_high, &ft_low);
1350 out_uint32_le(out, ft_low); /* change_write_time */
1351 out_uint32_le(out, ft_high);
1352
1353 out_uint64_le(out, filestat.st_size); /* filesize */
1354 out_uint64_le(out, filestat.st_size); /* filesize */
1355 out_uint32_le(out, file_attributes);
1356 out_uint32_le(out, s_length(stmp)); /* dir entry name string length */
1357 out_stream(out, stmp); /* dir entry name */
1358 break;
1359
1360
1361 case FileFullDirectoryInformation:
1362
1363 seconds_since_1970_to_filetime(get_create_time(&filestat), &ft_high,
1364 &ft_low);
1365 out_uint32_le(out, ft_low); /* create time */
1366 out_uint32_le(out, ft_high);
1367
1368 seconds_since_1970_to_filetime(filestat.st_atime, &ft_high, &ft_low);
1369 out_uint32_le(out, ft_low); /* last_access_time */
1370 out_uint32_le(out, ft_high);
1371
1372 seconds_since_1970_to_filetime(filestat.st_mtime, &ft_high, &ft_low);
1373 out_uint32_le(out, ft_low); /* last_write_time */
1374 out_uint32_le(out, ft_high);
1375
1376 seconds_since_1970_to_filetime(filestat.st_ctime, &ft_high, &ft_low);
1377 out_uint32_le(out, ft_low); /* change_write_time */
1378 out_uint32_le(out, ft_high);
1379
1380 out_uint64_le(out, filestat.st_size); /* filesize */
1381 out_uint64_le(out, filestat.st_size); /* filesize */
1382 out_uint32_le(out, file_attributes);
1383 out_uint32_le(out, s_length(stmp)); /* dir entry name string length */
1384 out_uint32_le(out, 0); /* EaSize */
1385 out_stream(out, stmp); /* dir entry name */
1386 break;
1387
1388
1389 case FileNamesInformation:
1390
1391 out_uint32_le(out, s_length(stmp)); /* dir entry name string length */
1392 out_stream(out, stmp); /* dir entry name */
1393 break;
1394
1395
1396 default:
1397 logger(Disk, Warning,
1398 "disk_query_directory(), unhandled directory info class 0x%x",
1399 info_class);
1400 s_free(stmp);
1401 return RD_STATUS_INVALID_PARAMETER;
1402 }
1403
1404 s_free(stmp);
1405
1406 return RD_STATUS_SUCCESS;
1407 }
1408
1409
1410
1411 static RD_NTSTATUS
disk_device_control(RD_NTHANDLE handle,uint32 request,STREAM in,STREAM out)1412 disk_device_control(RD_NTHANDLE handle, uint32 request, STREAM in, STREAM out)
1413 {
1414 UNUSED(in);
1415 UNUSED(out);
1416
1417 logger(Disk, Debug, "disk_device_control(handle=0x%x, request=0x%x, ...)", handle, request);
1418 if (((request >> 16) != 20) || ((request >> 16) != 9))
1419 return RD_STATUS_INVALID_PARAMETER;
1420
1421 /* extract operation */
1422 request >>= 2;
1423 request &= 0xfff;
1424
1425 switch (request)
1426 {
1427 case 25: /* ? */
1428 case 42: /* ? */
1429 default:
1430 logger(Disk, Warning, "disk_device_control(), unhandled disk ioctl %d",
1431 request);
1432 return RD_STATUS_INVALID_PARAMETER;
1433 }
1434
1435 return RD_STATUS_SUCCESS;
1436 }
1437
1438 DEVICE_FNS disk_fns = {
1439 disk_create,
1440 disk_close,
1441 disk_read,
1442 disk_write,
1443 disk_device_control /* device_control */
1444 };
1445