/[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 812 - (hide annotations)
Mon Feb 14 00:34:23 2005 UTC (19 years, 4 months ago) by jdmeijer
File MIME type: text/plain
File size: 27523 byte(s)
fix compilation on cygwin

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

  ViewVC Help
Powered by ViewVC 1.1.26