VirtualBox

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

最後變更 在這個檔案從55121是 55121,由 vboxsync 提交於 10 年 前

rdesktop 1.8.3 unmodified

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

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