/[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 790 - (show annotations)
Thu Oct 28 07:46:39 2004 UTC (19 years, 6 months ago) by astrand
File MIME type: text/plain
File size: 24759 byte(s)
Support for file systems that cannot handle O_EXCL.

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

  ViewVC Help
Powered by ViewVC 1.1.26