/[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 573 - (hide annotations)
Wed Jan 21 22:13:20 2004 UTC (20 years, 4 months ago) by stargo
File MIME type: text/plain
File size: 16230 byte(s)
OpenBSD support

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     #define FILE_ATTRIBUTE_READONLY 0x00000001
22     #define FILE_ATTRIBUTE_HIDDEN 0x00000002
23     #define FILE_ATTRIBUTE_SYSTEM 0x00000004
24     #define FILE_ATTRIBUTE_DIRECTORY 0x00000010
25     #define FILE_ATTRIBUTE_ARCHIVE 0x00000020
26     #define FILE_ATTRIBUTE_DEVICE 0x00000040
27     #define FILE_ATTRIBUTE_NORMAL 0x00000080
28     #define FILE_ATTRIBUTE_TEMPORARY 0x00000100
29     #define FILE_ATTRIBUTE_SPARSE_FILE 0x00000200
30     #define FILE_ATTRIBUTE_REPARSE_POINT 0x00000400
31     #define FILE_ATTRIBUTE_COMPRESSED 0x00000800
32     #define FILE_ATTRIBUTE_OFFLINE 0x00001000
33     #define FILE_ATTRIBUTE_NOT_CONTENT_INDEXED 0x00002000
34     #define FILE_ATTRIBUTE_ENCRYPTED 0x00004000
35    
36     #define FILE_BASIC_INFORMATION 0x04
37     #define FILE_STANDARD_INFORMATION 0x05
38    
39     #define FS_CASE_SENSITIVE 0x00000001
40     #define FS_CASE_IS_PRESERVED 0x00000002
41     #define FS_UNICODE_STORED_ON_DISK 0x00000004
42     #define FS_PERSISTENT_ACLS 0x00000008
43     #define FS_FILE_COMPRESSION 0x00000010
44     #define FS_VOLUME_QUOTAS 0x00000020
45     #define FS_SUPPORTS_SPARSE_FILES 0x00000040
46     #define FS_SUPPORTS_REPARSE_POINTS 0x00000080
47     #define FS_SUPPORTS_REMOTE_STORAGE 0X00000100
48     #define FS_VOL_IS_COMPRESSED 0x00008000
49     #define FILE_READ_ONLY_VOLUME 0x00080000
50    
51     #define OPEN_EXISTING 1
52     #define CREATE_NEW 2
53     #define OPEN_ALWAYS 3
54     #define TRUNCATE_EXISTING 4
55     #define CREATE_ALWAYS 5
56    
57     #define GENERIC_READ 0x80000000
58     #define GENERIC_WRITE 0x40000000
59     #define GENERIC_EXECUTE 0x20000000
60     #define GENERIC_ALL 0x10000000
61    
62     #define ERROR_FILE_NOT_FOUND 2L
63     #define ERROR_ALREADY_EXISTS 183L
64    
65     #define MAX_OPEN_FILES 0x100
66    
67 stargo 572 #if (defined(sun) && (defined(__svr4__) || defined(__SVR4)))
68     #define SOLARIS
69     #endif
70    
71     #ifdef SOLARIS
72     #define DIRFD(a) ((a)->dd_fd)
73     #else
74     #define DIRFD(a) (dirfd(a))
75     #endif
76    
77 n-ki 569 #include <sys/types.h>
78     #include <sys/stat.h>
79     #include <unistd.h>
80     #include <fcntl.h> /* open, close */
81     #include <dirent.h> /* opendir, closedir, readdir */
82     #include <fnmatch.h>
83     #include <errno.h> /* errno */
84 stargo 572
85 stargo 573 #if defined(SOLARIS)
86 stargo 572 #include <sys/statvfs.h> /* solaris statvfs */
87     #define HAVE_STATVFS
88 stargo 573 #define F_NAMELEN(buf) ((buf).f_namemax)
89    
90     #elif defined(__OpenBSD__)
91     #include <sys/param.h>
92     #include <sys/mount.h>
93     #define HAVE_STATFS
94     #define F_NAMELEN(buf) (NAME_MAX)
95    
96 stargo 572 #else
97     #include <sys/vfs.h> /* linux statfs */
98     #define HAVE_STATFS
99 stargo 573 #define F_NAMELEN(buf) ((buf).f_namelen)
100 stargo 572 #endif
101    
102 n-ki 569 #include "rdesktop.h"
103    
104     extern RDPDR_DEVICE g_rdpdr_device[];
105    
106     struct fileinfo
107     {
108     uint32 device_id, flags_and_attributes;
109     char path[256];
110     DIR *pdir;
111     struct dirent *pdirent;
112     char pattern[64];
113     BOOL delete_on_close;
114     }
115     g_fileinfo[MAX_OPEN_FILES];
116    
117 stargo 572 struct fsinfo
118     {
119     uint32 f_blocks, f_bfree, f_bsize, f_namelen;
120     };
121    
122 n-ki 569 /* Convert seconds since 1970 to a filetime */
123     void
124     seconds_since_1970_to_filetime(time_t seconds, uint32 * high, uint32 * low)
125     {
126     unsigned long long ticks;
127    
128     ticks = (seconds + 11644473600LL) * 10000000;
129     *low = (uint32) ticks;
130     *high = (uint32) (ticks >> 32);
131     }
132    
133     /* Enumeration of devices from rdesktop.c */
134     /* returns numer of units found and initialized. */
135     /* optarg looks like ':h:=/mnt/floppy,b:=/mnt/usbdevice1' */
136     /* when it arrives to this function. */
137     int
138     disk_enum_devices(int *id, char *optarg)
139     {
140     char *pos = optarg;
141     char *pos2;
142     int count = 0;
143    
144     // skip the first colon
145     optarg++;
146     while ((pos = next_arg(optarg, ',')) && *id < RDPDR_MAX_DEVICES)
147     {
148     pos2 = next_arg(optarg, '=');
149     strcpy(g_rdpdr_device[*id].name, optarg);
150    
151 stargo 570 toupper_str(g_rdpdr_device[*id].name);
152 n-ki 569
153     /* add trailing colon to name. */
154     strcat(g_rdpdr_device[*id].name, ":");
155    
156     g_rdpdr_device[*id].local_path = xmalloc(strlen(pos2) + 1);
157     strcpy(g_rdpdr_device[*id].local_path, pos2);
158     printf("DISK %s to %s\n", g_rdpdr_device[*id].name, g_rdpdr_device[*id].local_path);
159     g_rdpdr_device[*id].device_type = DEVICE_TYPE_DISK;
160     count++;
161     (*id)++;
162    
163     optarg = pos;
164     }
165     return count;
166     }
167    
168     /* Opens of creates a file or directory */
169     NTSTATUS
170     disk_create(uint32 device_id, uint32 accessmask, uint32 sharemode, uint32 create_disposition,
171     uint32 flags_and_attributes, char *filename, HANDLE * phandle)
172     {
173     HANDLE handle;
174     DIR *dirp;
175     int flags, mode;
176     char path[256];
177    
178     handle = 0;
179     dirp = NULL;
180     flags = 0;
181     mode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
182    
183     if (filename[strlen(filename) - 1] == '/')
184     filename[strlen(filename) - 1] = 0;
185     sprintf(path, "%s%s", g_rdpdr_device[device_id].local_path, filename);
186     //printf("Open: %s\n", path);
187    
188     switch (create_disposition)
189     {
190     case CREATE_ALWAYS:
191    
192     // Delete existing file/link.
193     unlink(path);
194     flags |= O_CREAT;
195     break;
196    
197     case CREATE_NEW:
198    
199     // If the file already exists, then fail.
200     flags |= O_CREAT | O_EXCL;
201     break;
202    
203     case OPEN_ALWAYS:
204    
205     // Create if not already exists.
206     flags |= O_CREAT;
207     break;
208    
209     case OPEN_EXISTING:
210    
211     // Default behaviour
212     break;
213    
214     case TRUNCATE_EXISTING:
215    
216     // If the file does not exist, then fail.
217     flags |= O_TRUNC;
218     break;
219     }
220    
221     if (flags_and_attributes & FILE_DIRECTORY_FILE)
222     {
223     if (flags & O_CREAT)
224     {
225     mkdir(path, mode);
226     }
227    
228     dirp = opendir(path);
229     if (!dirp)
230     {
231     switch (errno)
232     {
233     case EACCES:
234    
235     return STATUS_ACCESS_DENIED;
236    
237     case ENOENT:
238    
239     return STATUS_NO_SUCH_FILE;
240    
241     default:
242    
243     perror("opendir");
244     return STATUS_NO_SUCH_FILE;
245     }
246     }
247 stargo 572 handle = DIRFD(dirp);
248 n-ki 569 }
249     else
250     {
251     if (accessmask & GENERIC_ALL
252     || (accessmask & GENERIC_READ && accessmask & GENERIC_WRITE))
253     {
254     flags |= O_RDWR;
255     }
256     else if ((accessmask & GENERIC_WRITE) && !(accessmask & GENERIC_READ))
257     {
258     flags |= O_WRONLY;
259     }
260     else
261     {
262     flags |= O_RDONLY;
263     }
264    
265     handle = open(path, flags, mode);
266     if (handle == -1)
267     {
268     switch (errno)
269     {
270     case EACCES:
271    
272     return STATUS_ACCESS_DENIED;
273    
274     case ENOENT:
275    
276     return STATUS_NO_SUCH_FILE;
277    
278     default:
279    
280     perror("open");
281     return STATUS_NO_SUCH_FILE;
282     }
283     }
284     }
285    
286     if (handle >= MAX_OPEN_FILES)
287     {
288     error("Maximum number of open files (%s) reached. Increase MAX_OPEN_FILES!\n",
289     handle);
290     exit(1);
291     }
292    
293     if (dirp)
294     g_fileinfo[handle].pdir = dirp;
295     g_fileinfo[handle].device_id = device_id;
296     g_fileinfo[handle].flags_and_attributes = flags_and_attributes;
297     strncpy(g_fileinfo[handle].path, path, 255);
298    
299     *phandle = handle;
300     return STATUS_SUCCESS;
301     }
302    
303     NTSTATUS
304     disk_close(HANDLE handle)
305     {
306     struct fileinfo *pfinfo;
307    
308     pfinfo = &(g_fileinfo[handle]);
309    
310     if (pfinfo->flags_and_attributes & FILE_DIRECTORY_FILE)
311     {
312     closedir(pfinfo->pdir);
313     //FIXME: Should check exit code
314     }
315     else
316     {
317     close(handle);
318     }
319    
320     return STATUS_SUCCESS;
321     }
322    
323     NTSTATUS
324     disk_read(HANDLE handle, uint8 * data, uint32 length, uint32 offset, uint32 * result)
325     {
326     int n;
327    
328     if (offset)
329     lseek(handle, offset, SEEK_SET);
330     n = read(handle, data, length);
331    
332     if (n < 0)
333     {
334     perror("read");
335     *result = 0;
336     return STATUS_INVALID_PARAMETER;
337     }
338    
339     *result = n;
340    
341     return STATUS_SUCCESS;
342     }
343    
344     NTSTATUS
345     disk_write(HANDLE handle, uint8 * data, uint32 length, uint32 offset, uint32 * result)
346     {
347     int n;
348    
349     if (offset)
350     lseek(handle, offset, SEEK_SET);
351    
352     n = write(handle, data, length);
353    
354     if (n < 0)
355     {
356     perror("write");
357     *result = 0;
358     return STATUS_ACCESS_DENIED;
359     }
360    
361     *result = n;
362    
363     return STATUS_SUCCESS;
364     }
365    
366     NTSTATUS
367     disk_query_information(HANDLE handle, uint32 info_class, STREAM out)
368     {
369     uint32 file_attributes, ft_high, ft_low;
370     struct stat filestat;
371     char *path, *filename;
372    
373     path = g_fileinfo[handle].path;
374    
375     // Get information about file
376     if (fstat(handle, &filestat) != 0)
377     {
378     perror("stat");
379     out_uint8(out, 0);
380     return STATUS_ACCESS_DENIED;
381     }
382    
383     // Set file attributes
384     file_attributes = 0;
385     if (S_ISDIR(filestat.st_mode))
386     {
387     file_attributes |= FILE_ATTRIBUTE_DIRECTORY;
388     }
389     filename = 1 + strrchr(path, '/');
390     if (filename && filename[0] == '.')
391     {
392     file_attributes |= FILE_ATTRIBUTE_HIDDEN;
393     }
394    
395     // Return requested data
396     switch (info_class)
397     {
398     case 4: /* FileBasicInformation */
399    
400     out_uint8s(out, 8); //create_time not available;
401    
402     seconds_since_1970_to_filetime(filestat.st_atime, &ft_high, &ft_low);
403     out_uint32_le(out, ft_low); //last_access_time
404     out_uint32_le(out, ft_high);
405    
406     seconds_since_1970_to_filetime(filestat.st_mtime, &ft_high, &ft_low);
407     out_uint32_le(out, ft_low); //last_write_time
408     out_uint32_le(out, ft_high);
409    
410     out_uint8s(out, 8); //unknown zero
411     out_uint32_le(out, file_attributes);
412     break;
413    
414     case 5: /* FileStandardInformation */
415    
416     out_uint32_le(out, filestat.st_size); //Allocation size
417     out_uint32_le(out, 0);
418     out_uint32_le(out, filestat.st_size); //End of file
419     out_uint32_le(out, 0);
420     out_uint32_le(out, filestat.st_nlink); //Number of links
421     out_uint8(out, 0); //Delete pending
422     out_uint8(out, S_ISDIR(filestat.st_mode) ? 1 : 0); //Directory
423     break;
424    
425     case 35: /* FileObjectIdInformation */
426    
427     out_uint32_le(out, file_attributes); /* File Attributes */
428     out_uint32_le(out, 0); /* Reparse Tag */
429     break;
430    
431     default:
432    
433     unimpl("IRP Query (File) Information class: 0x%x\n", info_class);
434     return STATUS_INVALID_PARAMETER;
435     }
436     return STATUS_SUCCESS;
437     }
438    
439     NTSTATUS
440     disk_set_information(HANDLE handle, uint32 info_class, STREAM in, STREAM out)
441     {
442     uint32 device_id, length, file_attributes, ft_high, ft_low;
443     char newname[256], fullpath[256];
444     struct fileinfo *pfinfo;
445    
446     pfinfo = &(g_fileinfo[handle]);
447    
448     switch (info_class)
449     {
450     case 4: /* FileBasicInformation */
451    
452     // Probably safe to ignore
453     break;
454    
455     case 10: /* FileRenameInformation */
456    
457     in_uint8s(in, 4); /* Handle of root dir? */
458     in_uint8s(in, 0x1a); /* unknown */
459     in_uint32_le(in, length);
460    
461     if (length && (length / 2) < 256)
462     {
463     rdp_in_unistr(in, newname, length);
464     convert_to_unix_filename(newname);
465     }
466     else
467     {
468     return STATUS_INVALID_PARAMETER;
469     }
470    
471     sprintf(fullpath, "%s%s", g_rdpdr_device[pfinfo->device_id].local_path,
472     newname);
473    
474     if (rename(pfinfo->path, fullpath) != 0)
475     {
476     perror("rename");
477     return STATUS_ACCESS_DENIED;
478     }
479     break;
480    
481     case 13: /* FileDispositionInformation */
482    
483     //unimpl("IRP Set File Information class: FileDispositionInformation\n");
484     // in_uint32_le(in, delete_on_close);
485     // disk_close(handle);
486     unlink(pfinfo->path);
487     break;
488    
489     case 19: /* FileAllocationInformation */
490    
491     unimpl("IRP Set File Information class: FileAllocationInformation\n");
492     break;
493    
494     case 20: /* FileEndOfFileInformation */
495    
496     unimpl("IRP Set File Information class: FileEndOfFileInformation\n");
497     break;
498    
499     default:
500    
501     unimpl("IRP Set File Information class: 0x%x\n", info_class);
502     return STATUS_INVALID_PARAMETER;
503     }
504     return STATUS_SUCCESS;
505     }
506    
507 stargo 572 int fsstat(const char *path, struct fsinfo *buf)
508     {
509     int ret;
510     #if defined(HAVE_STATFS)
511     struct statfs statbuf;
512     #elif defined(HAVE_STATVFS)
513     struct statvfs statbuf;
514     #endif
515    
516     #if defined(HAVE_STATFS)
517     ret = statfs(path, &statbuf);
518     #elif defined(HAVE_STATVFS)
519     ret = statvfs(path, &statbuf);
520     #else
521     ret=-1;
522     #endif
523    
524     buf->f_blocks = statbuf.f_blocks;
525     buf->f_bfree = statbuf.f_bfree;
526     buf->f_bsize = statbuf.f_bsize;
527 stargo 573 buf->f_namelen = F_NAMELEN(statbuf);
528 stargo 572
529     return ret;
530     }
531    
532 n-ki 569 NTSTATUS
533     disk_query_volume_information(HANDLE handle, uint32 info_class, STREAM out)
534     {
535     char *volume, *fs_type;
536 stargo 572 struct fsinfo stat_fs;
537 n-ki 569 struct fileinfo *pfinfo;
538    
539     pfinfo = &(g_fileinfo[handle]);
540     volume = "RDESKTOP";
541     fs_type = "RDPFS";
542    
543 stargo 572 if (fsstat(pfinfo->path, &stat_fs) != 0) /* FIXME: statfs is not portable */
544 n-ki 569 {
545     perror("statfs");
546     return STATUS_ACCESS_DENIED;
547     }
548    
549     switch (info_class)
550     {
551     case 1: /* FileFsVolumeInformation */
552    
553     out_uint32_le(out, 0); /* volume creation time low */
554     out_uint32_le(out, 0); /* volume creation time high */
555     out_uint32_le(out, 0); /* serial */
556     out_uint32_le(out, 2 * strlen(volume)); /* length of string */
557     out_uint8(out, 0); /* support objects? */
558     rdp_out_unistr(out, volume, 2 * strlen(volume) - 2);
559     break;
560    
561     case 3: /* FileFsSizeInformation */
562    
563     out_uint32_le(out, stat_fs.f_blocks); /* Total allocation units low */
564     out_uint32_le(out, 0); /* Total allocation high units */
565     out_uint32_le(out, stat_fs.f_bfree); /* Available allocation units */
566     out_uint32_le(out, 0); /* Available allowcation units */
567     out_uint32_le(out, stat_fs.f_bsize / 0x200); /* Sectors per allocation unit */
568     out_uint32_le(out, 0x200); /* Bytes per sector */
569     break;
570    
571     case 5: /* FileFsAttributeInformation */
572    
573     out_uint32_le(out, FS_CASE_SENSITIVE | FS_CASE_IS_PRESERVED); /* fs attributes */
574     out_uint32_le(out, stat_fs.f_namelen); /* max length of filename */
575     out_uint32_le(out, 2 * strlen(fs_type)); /* length of fs_type */
576     rdp_out_unistr(out, fs_type, 2 * strlen(fs_type) - 2);
577     break;
578    
579     case 2: /* FileFsLabelInformation */
580     case 4: /* FileFsDeviceInformation */
581     case 6: /* FileFsControlInformation */
582     case 7: /* FileFsFullSizeInformation */
583     case 8: /* FileFsObjectIdInformation */
584     case 9: /* FileFsMaximumInformation */
585     default:
586    
587     unimpl("IRP Query Volume Information class: 0x%x\n", info_class);
588     return STATUS_INVALID_PARAMETER;
589     }
590     return STATUS_SUCCESS;
591     }
592    
593     NTSTATUS
594     disk_query_directory(HANDLE handle, uint32 info_class, char *pattern, STREAM out)
595     {
596     uint32 file_attributes, ft_low, ft_high;
597     char *dirname, fullpath[256];
598     DIR *pdir;
599     struct dirent *pdirent;
600     struct stat fstat;
601     struct fileinfo *pfinfo;
602    
603     pfinfo = &(g_fileinfo[handle]);
604     pdir = pfinfo->pdir;
605     dirname = pfinfo->path;
606     file_attributes = 0;
607    
608     switch (info_class)
609     {
610     case 3: //FIXME: Why 3?
611    
612     // If a search pattern is received, remember this pattern, and restart search
613     if (pattern[0] != 0)
614     {
615     strncpy(pfinfo->pattern, 1 + strrchr(pattern, '/'), 64);
616     rewinddir(pdir);
617     }
618    
619     // find next dirent matching pattern
620     pdirent = readdir(pdir);
621     while (pdirent && fnmatch(pfinfo->pattern, pdirent->d_name, 0) != 0)
622     {
623     pdirent = readdir(pdir);
624     }
625    
626     if (pdirent == NULL)
627     {
628     return STATUS_NO_MORE_FILES;
629     }
630    
631     // Get information for directory entry
632     sprintf(fullpath, "%s/%s", dirname, pdirent->d_name);
633     /* JIF
634     printf("Stat: %s\n", fullpath); */
635     if (stat(fullpath, &fstat))
636     {
637     perror("stat");
638     out_uint8(out, 0);
639     return STATUS_ACCESS_DENIED;
640     }
641    
642     if (S_ISDIR(fstat.st_mode))
643     file_attributes |= FILE_ATTRIBUTE_DIRECTORY;
644     if (pdirent->d_name[0] == '.')
645     file_attributes |= FILE_ATTRIBUTE_HIDDEN;
646    
647     // Return requested information
648     out_uint8s(out, 8); //unknown zero
649     out_uint8s(out, 8); //create_time not available in posix;
650    
651     seconds_since_1970_to_filetime(fstat.st_atime, &ft_high, &ft_low);
652     out_uint32_le(out, ft_low); //last_access_time
653     out_uint32_le(out, ft_high);
654    
655     seconds_since_1970_to_filetime(fstat.st_mtime, &ft_high, &ft_low);
656     out_uint32_le(out, ft_low); //last_write_time
657     out_uint32_le(out, ft_high);
658    
659     out_uint8s(out, 8); //unknown zero
660     out_uint32_le(out, fstat.st_size); //filesize low
661     out_uint32_le(out, 0); //filesize high
662     out_uint32_le(out, fstat.st_size); //filesize low
663     out_uint32_le(out, 0); //filesize high
664     out_uint32_le(out, file_attributes);
665     out_uint8(out, 2 * strlen(pdirent->d_name) + 2); //unicode length
666     out_uint8s(out, 7); //pad?
667     out_uint8(out, 0); //8.3 file length
668     out_uint8s(out, 2 * 12); //8.3 unicode length
669     rdp_out_unistr(out, pdirent->d_name, 2 * strlen(pdirent->d_name));
670     break;
671    
672     default:
673    
674     unimpl("IRP Query Directory sub: 0x%x\n", info_class);
675     return STATUS_INVALID_PARAMETER;
676     }
677    
678     return STATUS_SUCCESS;
679     }
680    
681     DEVICE_FNS disk_fns = {
682     disk_create,
683     disk_close,
684     disk_read,
685     disk_write,
686     NULL /* device_control */
687     };

  ViewVC Help
Powered by ViewVC 1.1.26