/[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 787 - (hide annotations)
Thu Oct 21 08:28:03 2004 UTC (19 years, 8 months ago) by astrand
File MIME type: text/plain
File size: 23498 byte(s)
disk_create: When filename is zero bytes long, we mustn't reference
filename[strlen(filename)-1].

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

  ViewVC Help
Powered by ViewVC 1.1.26