/[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

Contents of /sourceforge.net/trunk/rdesktop/disk.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 573 - (show 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 /* -*- 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 #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 #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
85 #if defined(SOLARIS)
86 #include <sys/statvfs.h> /* solaris statvfs */
87 #define HAVE_STATVFS
88 #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 #else
97 #include <sys/vfs.h> /* linux statfs */
98 #define HAVE_STATFS
99 #define F_NAMELEN(buf) ((buf).f_namelen)
100 #endif
101
102 #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 struct fsinfo
118 {
119 uint32 f_blocks, f_bfree, f_bsize, f_namelen;
120 };
121
122 /* 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 toupper_str(g_rdpdr_device[*id].name);
152
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 handle = DIRFD(dirp);
248 }
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 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 buf->f_namelen = F_NAMELEN(statbuf);
528
529 return ret;
530 }
531
532 NTSTATUS
533 disk_query_volume_information(HANDLE handle, uint32 info_class, STREAM out)
534 {
535 char *volume, *fs_type;
536 struct fsinfo stat_fs;
537 struct fileinfo *pfinfo;
538
539 pfinfo = &(g_fileinfo[handle]);
540 volume = "RDESKTOP";
541 fs_type = "RDPFS";
542
543 if (fsstat(pfinfo->path, &stat_fs) != 0) /* FIXME: statfs is not portable */
544 {
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