VirtualBox

source: vbox/trunk/src/VBox/RDP/client-1.8.3/disk.c@ 67954

Last change on this file since 67954 was 55123, checked in by vboxsync, 10 years ago

rdesktop 1.8.3 modified for VBox

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