/[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 978 - (show annotations)
Mon Aug 15 11:44:35 2005 UTC (18 years, 8 months ago) by stargo
File MIME type: text/plain
File size: 28461 byte(s)
Slightly modified long filenames-patch from Alex Miller <asm at asm.kiev.ua>

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

  ViewVC Help
Powered by ViewVC 1.1.26