VirtualBox

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

Last change on this file since 35532 was 33977, checked in by vboxsync, 14 years ago

*: replaced a bunch of sprintf() by snprintf()

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 29.1 KB
Line 
1/* -*- c-basic-offset: 8 -*-
2 rdesktop: A Remote Desktop Protocol client.
3 Disk Redirection
4 Copyright (C) Jeroen Meijer 2003-2007
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
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 switch (create_disposition)
373 {
374 case CREATE_ALWAYS:
375
376 /* Delete existing file/link. */
377 unlink(path);
378 flags |= O_CREAT;
379 break;
380
381 case CREATE_NEW:
382
383 /* If the file already exists, then fail. */
384 flags |= O_CREAT | O_EXCL;
385 break;
386
387 case OPEN_ALWAYS:
388
389 /* Create if not already exists. */
390 flags |= O_CREAT;
391 break;
392
393 case OPEN_EXISTING:
394
395 /* Default behaviour */
396 break;
397
398 case TRUNCATE_EXISTING:
399
400 /* If the file does not exist, then fail. */
401 flags |= O_TRUNC;
402 break;
403 }
404
405 /*printf("Open: \"%s\" flags: %X, accessmask: %X sharemode: %X create disp: %X\n", path, flags_and_attributes, accessmask, sharemode, create_disposition); */
406
407 /* Get information about file and set that flag ourselfs */
408 if ((stat(path, &filestat) == 0) && (S_ISDIR(filestat.st_mode)))
409 {
410 if (flags_and_attributes & FILE_NON_DIRECTORY_FILE)
411 return RD_STATUS_FILE_IS_A_DIRECTORY;
412 else
413 flags_and_attributes |= FILE_DIRECTORY_FILE;
414 }
415
416 if (flags_and_attributes & FILE_DIRECTORY_FILE)
417 {
418 if (flags & O_CREAT)
419 {
420 mkdir(path, mode);
421 }
422
423 dirp = opendir(path);
424 if (!dirp)
425 {
426 switch (errno)
427 {
428 case EACCES:
429
430 return RD_STATUS_ACCESS_DENIED;
431
432 case ENOENT:
433
434 return RD_STATUS_NO_SUCH_FILE;
435
436 default:
437
438 perror("opendir");
439 return RD_STATUS_NO_SUCH_FILE;
440 }
441 }
442 handle = DIRFD(dirp);
443 }
444 else
445 {
446
447 if (accessmask & GENERIC_ALL
448 || (accessmask & GENERIC_READ && accessmask & GENERIC_WRITE))
449 {
450 flags |= O_RDWR;
451 }
452 else if ((accessmask & GENERIC_WRITE) && !(accessmask & GENERIC_READ))
453 {
454 flags |= O_WRONLY;
455 }
456 else
457 {
458 flags |= O_RDONLY;
459 }
460
461 handle = open_weak_exclusive(path, flags, mode);
462 if (handle == -1)
463 {
464 switch (errno)
465 {
466 case EISDIR:
467
468 return RD_STATUS_FILE_IS_A_DIRECTORY;
469
470 case EACCES:
471
472 return RD_STATUS_ACCESS_DENIED;
473
474 case ENOENT:
475
476 return RD_STATUS_NO_SUCH_FILE;
477 case EEXIST:
478
479 return RD_STATUS_OBJECT_NAME_COLLISION;
480 default:
481
482 perror("open");
483 return RD_STATUS_NO_SUCH_FILE;
484 }
485 }
486
487 /* all read and writes of files should be non blocking */
488 if (fcntl(handle, F_SETFL, O_NONBLOCK) == -1)
489 perror("fcntl");
490 }
491
492 if (handle >= MAX_OPEN_FILES)
493 {
494 error("Maximum number of open files (%s) reached. Increase MAX_OPEN_FILES!\n",
495 handle);
496 exit(1);
497 }
498
499 if (dirp)
500 g_fileinfo[handle].pdir = dirp;
501 else
502 g_fileinfo[handle].pdir = NULL;
503
504 g_fileinfo[handle].device_id = device_id;
505 g_fileinfo[handle].flags_and_attributes = flags_and_attributes;
506 g_fileinfo[handle].accessmask = accessmask;
507 strncpy(g_fileinfo[handle].path, path, PATH_MAX - 1);
508 g_fileinfo[handle].delete_on_close = False;
509
510 if (accessmask & GENERIC_ALL || accessmask & GENERIC_WRITE)
511 g_notify_stamp = True;
512
513 *phandle = handle;
514 return RD_STATUS_SUCCESS;
515}
516
517static RD_NTSTATUS
518disk_close(RD_NTHANDLE handle)
519{
520 struct fileinfo *pfinfo;
521
522 pfinfo = &(g_fileinfo[handle]);
523
524 if (pfinfo->accessmask & GENERIC_ALL || pfinfo->accessmask & GENERIC_WRITE)
525 g_notify_stamp = True;
526
527 rdpdr_abort_io(handle, 0, RD_STATUS_CANCELLED);
528
529 if (pfinfo->pdir)
530 {
531 if (closedir(pfinfo->pdir) < 0)
532 {
533 perror("closedir");
534 return RD_STATUS_INVALID_HANDLE;
535 }
536
537 if (pfinfo->delete_on_close)
538 if (rmdir(pfinfo->path) < 0)
539 {
540 perror(pfinfo->path);
541 return RD_STATUS_ACCESS_DENIED;
542 }
543 pfinfo->delete_on_close = False;
544 }
545 else
546 {
547 if (close(handle) < 0)
548 {
549 perror("close");
550 return RD_STATUS_INVALID_HANDLE;
551 }
552 if (pfinfo->delete_on_close)
553 if (unlink(pfinfo->path) < 0)
554 {
555 perror(pfinfo->path);
556 return RD_STATUS_ACCESS_DENIED;
557 }
558
559 pfinfo->delete_on_close = False;
560 }
561
562 return RD_STATUS_SUCCESS;
563}
564
565static RD_NTSTATUS
566disk_read(RD_NTHANDLE handle, uint8 * data, uint32 length, uint32 offset, uint32 * result)
567{
568 int n;
569
570#if 0
571 /* browsing dir ???? */
572 /* each request is 24 bytes */
573 if (g_fileinfo[handle].flags_and_attributes & FILE_DIRECTORY_FILE)
574 {
575 *result = 0;
576 return STATUS_SUCCESS;
577 }
578#endif
579
580 lseek(handle, offset, SEEK_SET);
581
582 n = read(handle, data, length);
583
584 if (n < 0)
585 {
586 *result = 0;
587 switch (errno)
588 {
589 case EISDIR:
590 /* Implement 24 Byte directory read ??
591 with STATUS_NOT_IMPLEMENTED server doesn't read again */
592 /* return STATUS_FILE_IS_A_DIRECTORY; */
593 return RD_STATUS_NOT_IMPLEMENTED;
594 default:
595 perror("read");
596 return RD_STATUS_INVALID_PARAMETER;
597 }
598 }
599
600 *result = n;
601
602 return RD_STATUS_SUCCESS;
603}
604
605static RD_NTSTATUS
606disk_write(RD_NTHANDLE handle, uint8 * data, uint32 length, uint32 offset, uint32 * result)
607{
608 int n;
609
610 lseek(handle, offset, SEEK_SET);
611
612 n = write(handle, data, length);
613
614 if (n < 0)
615 {
616 perror("write");
617 *result = 0;
618 switch (errno)
619 {
620 case ENOSPC:
621 return RD_STATUS_DISK_FULL;
622 default:
623 return RD_STATUS_ACCESS_DENIED;
624 }
625 }
626
627 *result = n;
628
629 return RD_STATUS_SUCCESS;
630}
631
632RD_NTSTATUS
633disk_query_information(RD_NTHANDLE handle, uint32 info_class, STREAM out)
634{
635 uint32 file_attributes, ft_high, ft_low;
636 struct stat filestat;
637 char *path, *filename;
638
639 path = g_fileinfo[handle].path;
640
641 /* Get information about file */
642 if (fstat(handle, &filestat) != 0)
643 {
644 perror("stat");
645 out_uint8(out, 0);
646 return RD_STATUS_ACCESS_DENIED;
647 }
648
649 /* Set file attributes */
650 file_attributes = 0;
651 if (S_ISDIR(filestat.st_mode))
652 file_attributes |= FILE_ATTRIBUTE_DIRECTORY;
653
654 filename = 1 + strrchr(path, '/');
655 if (filename && filename[0] == '.')
656 file_attributes |= FILE_ATTRIBUTE_HIDDEN;
657
658 if (!file_attributes)
659 file_attributes |= FILE_ATTRIBUTE_NORMAL;
660
661 if (!(filestat.st_mode & S_IWUSR))
662 file_attributes |= FILE_ATTRIBUTE_READONLY;
663
664 /* Return requested data */
665 switch (info_class)
666 {
667 case FileBasicInformation:
668 seconds_since_1970_to_filetime(get_create_time(&filestat), &ft_high,
669 &ft_low);
670 out_uint32_le(out, ft_low); /* create_access_time */
671 out_uint32_le(out, ft_high);
672
673 seconds_since_1970_to_filetime(filestat.st_atime, &ft_high, &ft_low);
674 out_uint32_le(out, ft_low); /* last_access_time */
675 out_uint32_le(out, ft_high);
676
677 seconds_since_1970_to_filetime(filestat.st_mtime, &ft_high, &ft_low);
678 out_uint32_le(out, ft_low); /* last_write_time */
679 out_uint32_le(out, ft_high);
680
681 seconds_since_1970_to_filetime(filestat.st_ctime, &ft_high, &ft_low);
682 out_uint32_le(out, ft_low); /* last_change_time */
683 out_uint32_le(out, ft_high);
684
685 out_uint32_le(out, file_attributes);
686 break;
687
688 case FileStandardInformation:
689
690 out_uint32_le(out, filestat.st_size); /* Allocation size */
691 out_uint32_le(out, 0);
692 out_uint32_le(out, filestat.st_size); /* End of file */
693 out_uint32_le(out, 0);
694 out_uint32_le(out, filestat.st_nlink); /* Number of links */
695 out_uint8(out, 0); /* Delete pending */
696 out_uint8(out, S_ISDIR(filestat.st_mode) ? 1 : 0); /* Directory */
697 break;
698
699 case FileObjectIdInformation:
700
701 out_uint32_le(out, file_attributes); /* File Attributes */
702 out_uint32_le(out, 0); /* Reparse Tag */
703 break;
704
705 default:
706
707 unimpl("IRP Query (File) Information class: 0x%x\n", info_class);
708 return RD_STATUS_INVALID_PARAMETER;
709 }
710 return RD_STATUS_SUCCESS;
711}
712
713RD_NTSTATUS
714disk_set_information(RD_NTHANDLE handle, uint32 info_class, STREAM in, STREAM out)
715{
716 uint32 length, file_attributes, ft_high, ft_low, delete_on_close;
717 char newname[PATH_MAX], fullpath[PATH_MAX];
718 struct fileinfo *pfinfo;
719 int mode;
720 struct stat filestat;
721 time_t write_time, change_time, access_time, mod_time;
722 struct utimbuf tvs;
723 struct STATFS_T stat_fs;
724
725 pfinfo = &(g_fileinfo[handle]);
726 g_notify_stamp = True;
727
728 switch (info_class)
729 {
730 case FileBasicInformation:
731 write_time = change_time = access_time = 0;
732
733 in_uint8s(in, 4); /* Handle of root dir? */
734 in_uint8s(in, 24); /* unknown */
735
736 /* CreationTime */
737 in_uint32_le(in, ft_low);
738 in_uint32_le(in, ft_high);
739
740 /* AccessTime */
741 in_uint32_le(in, ft_low);
742 in_uint32_le(in, ft_high);
743 if (ft_low || ft_high)
744 access_time = convert_1970_to_filetime(ft_high, ft_low);
745
746 /* WriteTime */
747 in_uint32_le(in, ft_low);
748 in_uint32_le(in, ft_high);
749 if (ft_low || ft_high)
750 write_time = convert_1970_to_filetime(ft_high, ft_low);
751
752 /* ChangeTime */
753 in_uint32_le(in, ft_low);
754 in_uint32_le(in, ft_high);
755 if (ft_low || ft_high)
756 change_time = convert_1970_to_filetime(ft_high, ft_low);
757
758 in_uint32_le(in, file_attributes);
759
760 if (fstat(handle, &filestat))
761 return RD_STATUS_ACCESS_DENIED;
762
763 tvs.modtime = filestat.st_mtime;
764 tvs.actime = filestat.st_atime;
765 if (access_time)
766 tvs.actime = access_time;
767
768
769 if (write_time || change_time)
770 mod_time = MIN(write_time, change_time);
771 else
772 mod_time = write_time ? write_time : change_time;
773
774 if (mod_time)
775 tvs.modtime = mod_time;
776
777
778 if (access_time || write_time || change_time)
779 {
780#if WITH_DEBUG_RDP5
781 printf("FileBasicInformation access time %s",
782 ctime(&tvs.actime));
783 printf("FileBasicInformation modification time %s",
784 ctime(&tvs.modtime));
785#endif
786 if (utime(pfinfo->path, &tvs) && errno != EPERM)
787 return RD_STATUS_ACCESS_DENIED;
788 }
789
790 if (!file_attributes)
791 break; /* not valid */
792
793 mode = filestat.st_mode;
794
795 if (file_attributes & FILE_ATTRIBUTE_READONLY)
796 mode &= ~(S_IWUSR | S_IWGRP | S_IWOTH);
797 else
798 mode |= S_IWUSR;
799
800 mode &= 0777;
801#if WITH_DEBUG_RDP5
802 printf("FileBasicInformation set access mode 0%o", mode);
803#endif
804
805 if (fchmod(handle, mode))
806 return RD_STATUS_ACCESS_DENIED;
807
808 break;
809
810 case FileRenameInformation:
811
812 in_uint8s(in, 4); /* Handle of root dir? */
813 in_uint8s(in, 0x1a); /* unknown */
814 in_uint32_le(in, length);
815
816 if (length && (length / 2) < 256)
817 {
818 rdp_in_unistr(in, newname, sizeof(newname), length);
819 convert_to_unix_filename(newname);
820 }
821 else
822 {
823 return RD_STATUS_INVALID_PARAMETER;
824 }
825
826#ifdef VBOX
827 snprintf(fullpath, sizeof(fullpath), "%s%s", g_rdpdr_device[pfinfo->device_id].local_path,
828 newname);
829#else
830 sprintf(fullpath, "%s%s", g_rdpdr_device[pfinfo->device_id].local_path,
831 newname);
832#endif
833
834 if (rename(pfinfo->path, fullpath) != 0)
835 {
836 perror("rename");
837 return RD_STATUS_ACCESS_DENIED;
838 }
839 break;
840
841 case FileDispositionInformation:
842 /* As far as I understand it, the correct
843 thing to do here is to *schedule* a delete,
844 so it will be deleted when the file is
845 closed. Subsequent
846 FileDispositionInformation requests with
847 DeleteFile set to FALSE should unschedule
848 the delete. See
849 http://www.osronline.com/article.cfm?article=245. */
850
851 in_uint32_le(in, delete_on_close);
852
853 if (delete_on_close ||
854 (pfinfo->
855 accessmask & (FILE_DELETE_ON_CLOSE | FILE_COMPLETE_IF_OPLOCKED)))
856 {
857 pfinfo->delete_on_close = True;
858 }
859
860 break;
861
862 case FileAllocationInformation:
863 /* Fall through to FileEndOfFileInformation,
864 which uses ftrunc. This is like Samba with
865 "strict allocation = false", and means that
866 we won't detect out-of-quota errors, for
867 example. */
868
869 case FileEndOfFileInformation:
870 in_uint8s(in, 28); /* unknown */
871 in_uint32_le(in, length); /* file size */
872
873 /* prevents start of writing if not enough space left on device */
874 if (STATFS_FN(pfinfo->path, &stat_fs) == 0)
875 if (stat_fs.f_bfree * stat_fs.f_bsize < length)
876 return RD_STATUS_DISK_FULL;
877
878 if (ftruncate_growable(handle, length) != 0)
879 {
880 return RD_STATUS_DISK_FULL;
881 }
882
883 break;
884 default:
885
886 unimpl("IRP Set File Information class: 0x%x\n", info_class);
887 return RD_STATUS_INVALID_PARAMETER;
888 }
889 return RD_STATUS_SUCCESS;
890}
891
892RD_NTSTATUS
893disk_check_notify(RD_NTHANDLE handle)
894{
895 struct fileinfo *pfinfo;
896 RD_NTSTATUS status = RD_STATUS_PENDING;
897
898 NOTIFY notify;
899
900 pfinfo = &(g_fileinfo[handle]);
901 if (!pfinfo->pdir)
902 return RD_STATUS_INVALID_DEVICE_REQUEST;
903
904
905
906 status = NotifyInfo(handle, pfinfo->info_class, &notify);
907
908 if (status != RD_STATUS_PENDING)
909 return status;
910
911 if (memcmp(&pfinfo->notify, &notify, sizeof(NOTIFY)))
912 {
913 /*printf("disk_check_notify found changed event\n"); */
914 memcpy(&pfinfo->notify, &notify, sizeof(NOTIFY));
915 status = RD_STATUS_NOTIFY_ENUM_DIR;
916 }
917
918 return status;
919
920
921}
922
923RD_NTSTATUS
924disk_create_notify(RD_NTHANDLE handle, uint32 info_class)
925{
926
927 struct fileinfo *pfinfo;
928 RD_NTSTATUS ret = RD_STATUS_PENDING;
929
930 /* printf("start disk_create_notify info_class %X\n", info_class); */
931
932 pfinfo = &(g_fileinfo[handle]);
933 pfinfo->info_class = info_class;
934
935 ret = NotifyInfo(handle, info_class, &pfinfo->notify);
936
937 if (info_class & 0x1000)
938 { /* ???? */
939 if (ret == RD_STATUS_PENDING)
940 return RD_STATUS_SUCCESS;
941 }
942
943 /* printf("disk_create_notify: num_entries %d\n", pfinfo->notify.num_entries); */
944
945
946 return ret;
947
948}
949
950static RD_NTSTATUS
951NotifyInfo(RD_NTHANDLE handle, uint32 info_class, NOTIFY * p)
952{
953 struct fileinfo *pfinfo;
954 struct stat filestat;
955 struct dirent *dp;
956 char *fullname;
957 DIR *dpr;
958
959 pfinfo = &(g_fileinfo[handle]);
960 if (fstat(handle, &filestat) < 0)
961 {
962 perror("NotifyInfo");
963 return RD_STATUS_ACCESS_DENIED;
964 }
965 p->modify_time = filestat.st_mtime;
966 p->status_time = filestat.st_ctime;
967 p->num_entries = 0;
968 p->total_time = 0;
969
970
971 dpr = opendir(pfinfo->path);
972 if (!dpr)
973 {
974 perror("NotifyInfo");
975 return RD_STATUS_ACCESS_DENIED;
976 }
977
978
979 while ((dp = readdir(dpr)))
980 {
981 if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, ".."))
982 continue;
983 p->num_entries++;
984 fullname = (char *) xmalloc(strlen(pfinfo->path) + strlen(dp->d_name) + 2);
985 sprintf(fullname, "%s/%s", pfinfo->path, dp->d_name);
986
987 if (!stat(fullname, &filestat))
988 {
989 p->total_time += (filestat.st_mtime + filestat.st_ctime);
990 }
991
992 xfree(fullname);
993 }
994 closedir(dpr);
995
996 return RD_STATUS_PENDING;
997}
998
999static FsInfoType *
1000FsVolumeInfo(char *fpath)
1001{
1002
1003 static FsInfoType info;
1004#ifdef USE_SETMNTENT
1005 FILE *fdfs;
1006 struct mntent *e;
1007#endif
1008
1009 /* initialize */
1010 memset(&info, 0, sizeof(info));
1011 strcpy(info.label, "RDESKTOP");
1012 strcpy(info.type, "RDPFS");
1013
1014#ifdef USE_SETMNTENT
1015 fdfs = setmntent(MNTENT_PATH, "r");
1016 if (!fdfs)
1017 return &info;
1018
1019 while ((e = getmntent(fdfs)))
1020 {
1021 if (str_startswith(e->mnt_dir, fpath))
1022 {
1023 strcpy(info.type, e->mnt_type);
1024 strcpy(info.name, e->mnt_fsname);
1025 if (strstr(e->mnt_opts, "vfat") || strstr(e->mnt_opts, "iso9660"))
1026 {
1027 int fd = open(e->mnt_fsname, O_RDONLY);
1028 if (fd >= 0)
1029 {
1030 unsigned char buf[512];
1031 memset(buf, 0, sizeof(buf));
1032 if (strstr(e->mnt_opts, "vfat"))
1033 /*FAT*/
1034 {
1035 strcpy(info.type, "vfat");
1036 read(fd, buf, sizeof(buf));
1037 info.serial =
1038 (buf[42] << 24) + (buf[41] << 16) +
1039 (buf[40] << 8) + buf[39];
1040 strncpy(info.label, (char *) buf + 43, 10);
1041 info.label[10] = '\0';
1042 }
1043 else if (lseek(fd, 32767, SEEK_SET) >= 0) /* ISO9660 */
1044 {
1045 read(fd, buf, sizeof(buf));
1046 strncpy(info.label, (char *) buf + 41, 32);
1047 info.label[32] = '\0';
1048 /* info.Serial = (buf[128]<<24)+(buf[127]<<16)+(buf[126]<<8)+buf[125]; */
1049 }
1050 close(fd);
1051 }
1052 }
1053 }
1054 }
1055 endmntent(fdfs);
1056#else
1057 /* initialize */
1058 memset(&info, 0, sizeof(info));
1059 strcpy(info.label, "RDESKTOP");
1060 strcpy(info.type, "RDPFS");
1061
1062#endif
1063 return &info;
1064}
1065
1066
1067RD_NTSTATUS
1068disk_query_volume_information(RD_NTHANDLE handle, uint32 info_class, STREAM out)
1069{
1070 struct STATFS_T stat_fs;
1071 struct fileinfo *pfinfo;
1072 FsInfoType *fsinfo;
1073
1074 pfinfo = &(g_fileinfo[handle]);
1075
1076 if (STATFS_FN(pfinfo->path, &stat_fs) != 0)
1077 {
1078 perror("statfs");
1079 return RD_STATUS_ACCESS_DENIED;
1080 }
1081
1082 fsinfo = FsVolumeInfo(pfinfo->path);
1083
1084 switch (info_class)
1085 {
1086 case FileFsVolumeInformation:
1087
1088 out_uint32_le(out, 0); /* volume creation time low */
1089 out_uint32_le(out, 0); /* volume creation time high */
1090 out_uint32_le(out, fsinfo->serial); /* serial */
1091
1092 out_uint32_le(out, 2 * strlen(fsinfo->label)); /* length of string */
1093
1094 out_uint8(out, 0); /* support objects? */
1095 rdp_out_unistr(out, fsinfo->label, 2 * strlen(fsinfo->label) - 2);
1096 break;
1097
1098 case FileFsSizeInformation:
1099
1100 out_uint32_le(out, stat_fs.f_blocks); /* Total allocation units low */
1101 out_uint32_le(out, 0); /* Total allocation high units */
1102 out_uint32_le(out, stat_fs.f_bfree); /* Available allocation units */
1103 out_uint32_le(out, 0); /* Available allowcation units */
1104 out_uint32_le(out, stat_fs.f_bsize / 0x200); /* Sectors per allocation unit */
1105 out_uint32_le(out, 0x200); /* Bytes per sector */
1106 break;
1107
1108 case FileFsAttributeInformation:
1109
1110 out_uint32_le(out, FS_CASE_SENSITIVE | FS_CASE_IS_PRESERVED); /* fs attributes */
1111 out_uint32_le(out, F_NAMELEN(stat_fs)); /* max length of filename */
1112
1113 out_uint32_le(out, 2 * strlen(fsinfo->type)); /* length of fs_type */
1114 rdp_out_unistr(out, fsinfo->type, 2 * strlen(fsinfo->type) - 2);
1115 break;
1116
1117 case FileFsLabelInformation:
1118 case FileFsDeviceInformation:
1119 case FileFsControlInformation:
1120 case FileFsFullSizeInformation:
1121 case FileFsObjectIdInformation:
1122 case FileFsMaximumInformation:
1123
1124 default:
1125
1126 unimpl("IRP Query Volume Information class: 0x%x\n", info_class);
1127 return RD_STATUS_INVALID_PARAMETER;
1128 }
1129 return RD_STATUS_SUCCESS;
1130}
1131
1132RD_NTSTATUS
1133disk_query_directory(RD_NTHANDLE handle, uint32 info_class, char *pattern, STREAM out)
1134{
1135 uint32 file_attributes, ft_low, ft_high;
1136 char *dirname, fullpath[PATH_MAX];
1137 DIR *pdir;
1138 struct dirent *pdirent;
1139 struct stat filestat;
1140 struct fileinfo *pfinfo;
1141
1142 pfinfo = &(g_fileinfo[handle]);
1143 pdir = pfinfo->pdir;
1144 dirname = pfinfo->path;
1145 file_attributes = 0;
1146
1147 switch (info_class)
1148 {
1149 case FileBothDirectoryInformation:
1150
1151 /* If a search pattern is received, remember this pattern, and restart search */
1152 if (pattern[0] != 0)
1153 {
1154 strncpy(pfinfo->pattern, 1 + strrchr(pattern, '/'), PATH_MAX - 1);
1155 rewinddir(pdir);
1156 }
1157
1158 /* find next dirent matching pattern */
1159 pdirent = readdir(pdir);
1160 while (pdirent && fnmatch(pfinfo->pattern, pdirent->d_name, 0) != 0)
1161 pdirent = readdir(pdir);
1162
1163 if (pdirent == NULL)
1164 return RD_STATUS_NO_MORE_FILES;
1165
1166 /* Get information for directory entry */
1167#ifdef VBOX
1168 snprintf(fullpath, sizeof(fullpath), "%s/%s", dirname, pdirent->d_name);
1169#else
1170 sprintf(fullpath, "%s/%s", dirname, pdirent->d_name);
1171#endif
1172
1173 if (stat(fullpath, &filestat))
1174 {
1175 switch (errno)
1176 {
1177 case ENOENT:
1178 case ELOOP:
1179 case EACCES:
1180 /* These are non-fatal errors. */
1181 memset(&filestat, 0, sizeof(filestat));
1182 break;
1183 default:
1184 /* Fatal error. By returning STATUS_NO_SUCH_FILE,
1185 the directory list operation will be aborted */
1186 perror(fullpath);
1187 out_uint8(out, 0);
1188 return RD_STATUS_NO_SUCH_FILE;
1189 }
1190 }
1191
1192 if (S_ISDIR(filestat.st_mode))
1193 file_attributes |= FILE_ATTRIBUTE_DIRECTORY;
1194 if (pdirent->d_name[0] == '.')
1195 file_attributes |= FILE_ATTRIBUTE_HIDDEN;
1196 if (!file_attributes)
1197 file_attributes |= FILE_ATTRIBUTE_NORMAL;
1198 if (!(filestat.st_mode & S_IWUSR))
1199 file_attributes |= FILE_ATTRIBUTE_READONLY;
1200
1201 /* Return requested information */
1202 out_uint8s(out, 8); /* unknown zero */
1203
1204 seconds_since_1970_to_filetime(get_create_time(&filestat), &ft_high,
1205 &ft_low);
1206 out_uint32_le(out, ft_low); /* create time */
1207 out_uint32_le(out, ft_high);
1208
1209 seconds_since_1970_to_filetime(filestat.st_atime, &ft_high, &ft_low);
1210 out_uint32_le(out, ft_low); /* last_access_time */
1211 out_uint32_le(out, ft_high);
1212
1213 seconds_since_1970_to_filetime(filestat.st_mtime, &ft_high, &ft_low);
1214 out_uint32_le(out, ft_low); /* last_write_time */
1215 out_uint32_le(out, ft_high);
1216
1217 seconds_since_1970_to_filetime(filestat.st_ctime, &ft_high, &ft_low);
1218 out_uint32_le(out, ft_low); /* change_write_time */
1219 out_uint32_le(out, ft_high);
1220
1221 out_uint32_le(out, filestat.st_size); /* filesize low */
1222 out_uint32_le(out, 0); /* filesize high */
1223 out_uint32_le(out, filestat.st_size); /* filesize low */
1224 out_uint32_le(out, 0); /* filesize high */
1225 out_uint32_le(out, file_attributes);
1226 out_uint8(out, 2 * strlen(pdirent->d_name) + 2); /* unicode length */
1227 out_uint8s(out, 7); /* pad? */
1228 out_uint8(out, 0); /* 8.3 file length */
1229 out_uint8s(out, 2 * 12); /* 8.3 unicode length */
1230 rdp_out_unistr(out, pdirent->d_name, 2 * strlen(pdirent->d_name));
1231 break;
1232
1233 default:
1234 /* FIXME: Support FileDirectoryInformation,
1235 FileFullDirectoryInformation, and
1236 FileNamesInformation */
1237
1238 unimpl("IRP Query Directory sub: 0x%x\n", info_class);
1239 return RD_STATUS_INVALID_PARAMETER;
1240 }
1241
1242 return RD_STATUS_SUCCESS;
1243}
1244
1245
1246
1247static RD_NTSTATUS
1248disk_device_control(RD_NTHANDLE handle, uint32 request, STREAM in, STREAM out)
1249{
1250 if (((request >> 16) != 20) || ((request >> 16) != 9))
1251 return RD_STATUS_INVALID_PARAMETER;
1252
1253 /* extract operation */
1254 request >>= 2;
1255 request &= 0xfff;
1256
1257 printf("DISK IOCTL %d\n", request);
1258
1259 switch (request)
1260 {
1261 case 25: /* ? */
1262 case 42: /* ? */
1263 default:
1264 unimpl("DISK IOCTL %d\n", request);
1265 return RD_STATUS_INVALID_PARAMETER;
1266 }
1267
1268 return RD_STATUS_SUCCESS;
1269}
1270
1271DEVICE_FNS disk_fns = {
1272 disk_create,
1273 disk_close,
1274 disk_read,
1275 disk_write,
1276 disk_device_control /* device_control */
1277};
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