/[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 661 - (show annotations)
Fri Apr 16 13:03:13 2004 UTC (20 years, 1 month ago) by astrand
File MIME type: text/plain
File size: 21832 byte(s)
FileEndOfFileInformation actually calls ftrunc().
FileAllocationInformation falls through to FileEndOfFileInformation.

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

  ViewVC Help
Powered by ViewVC 1.1.26