VirtualBox

source: vbox/trunk/src/VBox/RDP/client/disk.c@ 40654

Last change on this file since 40654 was 37224, checked in by vboxsync, 13 years ago

RDP/client: fix OSE

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

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette