/[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 818 - (show annotations)
Mon Feb 21 12:39:34 2005 UTC (19 years, 3 months ago) by forsberg
File MIME type: text/plain
File size: 27560 byte(s)
Disk unit names seem to be truncated at seven characters on the WTS,
and I can't see any field allowing for longer names. This is not very
surprising, since native clients export drive names ("A", "H" etc.).

Telling the user that the name is truncated at seven, not eight,
characters.

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

  ViewVC Help
Powered by ViewVC 1.1.26