/[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 783 - (show annotations)
Fri Oct 15 18:02:45 2004 UTC (19 years, 6 months ago) by stargo
File MIME type: text/plain
File size: 22628 byte(s)
Add support for Mac OSX from Steven Palm <n9yty@n9yty.com>

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

  ViewVC Help
Powered by ViewVC 1.1.26