/[rdesktop]/jpeg/rdesktop/trunk/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 /jpeg/rdesktop/trunk/disk.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 596 - (show annotations)
Tue Feb 3 14:03:42 2004 UTC (20 years, 4 months ago) by n-ki
Original Path: sourceforge.net/trunk/rdesktop/disk.c
File MIME type: text/plain
File size: 16881 byte(s)
enable aio of read/write files. workaround server bug where directory flag is not set on create

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

  ViewVC Help
Powered by ViewVC 1.1.26