/[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 807 - (hide annotations)
Thu Dec 23 20:43:47 2004 UTC (19 years, 5 months ago) by stargo
File MIME type: text/plain
File size: 27538 byte(s)
OSF1 fixes from [ 938867 ] Misc porting patches
by Marc W. Mengel

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

  ViewVC Help
Powered by ViewVC 1.1.26