/[rdesktop]/sourceforge.net/trunk/rdesktop/disk.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /sourceforge.net/trunk/rdesktop/disk.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 795 - (show annotations)
Wed Nov 3 13:56:52 2004 UTC (19 years, 6 months ago) by stargo
File MIME type: text/plain
File size: 27324 byte(s)
Big serial- and disk-redirection update from
Andreas Flick <Andreas.Flick@unicon-ka.de>

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

  ViewVC Help
Powered by ViewVC 1.1.26