/[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 790 - (hide annotations)
Thu Oct 28 07:46:39 2004 UTC (19 years, 8 months ago) by astrand
File MIME type: text/plain
File size: 24759 byte(s)
Support for file systems that cannot handle O_EXCL.

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

  ViewVC Help
Powered by ViewVC 1.1.26