/[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

Annotation of /sourceforge.net/trunk/rdesktop/disk.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 795 - (hide annotations)
Wed Nov 3 13:56:52 2004 UTC (19 years, 7 months ago) by stargo
File MIME type: text/plain
File size: 27324 byte(s)
Big serial- and disk-redirection update from
Andreas Flick <Andreas.Flick@unicon-ka.de>

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

  ViewVC Help
Powered by ViewVC 1.1.26