/[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 875 - (show annotations)
Sat Apr 2 17:49:56 2005 UTC (19 years, 2 months ago) by stargo
File MIME type: text/plain
File size: 28375 byte(s)
fix dummy_statfs

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

  ViewVC Help
Powered by ViewVC 1.1.26