/[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 596 - (hide annotations)
Tue Feb 3 14:03:42 2004 UTC (20 years, 4 months ago) by n-ki
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 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 stargo 574 #define STATFS_FN(path, buf) (statvfs(path,buf))
88     #define STATFS_T statvfs
89 stargo 573 #define F_NAMELEN(buf) ((buf).f_namemax)
90    
91 stargo 576 #elif (defined(__OpenBSD__) || defined(__NetBSD__) || defined(__FreeBSD__))
92 stargo 573 #include <sys/param.h>
93     #include <sys/mount.h>
94 stargo 574 #define STATFS_FN(path, buf) (statfs(path,buf))
95     #define STATFS_T statfs
96 stargo 573 #define F_NAMELEN(buf) (NAME_MAX)
97    
98 stargo 572 #else
99     #include <sys/vfs.h> /* linux statfs */
100 stargo 574 #define STATFS_FN(path, buf) (statfs(path,buf))
101     #define STATFS_T statfs
102 stargo 573 #define F_NAMELEN(buf) ((buf).f_namelen)
103 stargo 572 #endif
104    
105 n-ki 569 #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 stargo 570 toupper_str(g_rdpdr_device[*id].name);
150 n-ki 569
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 n-ki 596 /* Opens or creates a file or directory */
167 n-ki 569 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 n-ki 596 /* 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 n-ki 569 {
222 n-ki 596 if (accessmask & GENERIC_ALL
223     || (accessmask & GENERIC_READ && accessmask & GENERIC_WRITE))
224 n-ki 569 {
225 n-ki 596 flags |= O_RDWR;
226 n-ki 569 }
227 n-ki 596 else if ((accessmask & GENERIC_WRITE) && !(accessmask & GENERIC_READ))
228     {
229     flags |= O_WRONLY;
230     }
231     else
232     {
233     flags |= O_RDONLY;
234     }
235 n-ki 569
236 n-ki 596 handle = open(path, flags, mode);
237     if (handle == -1)
238 n-ki 569 {
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 n-ki 596 perror("open");
252 n-ki 569 return STATUS_NO_SUCH_FILE;
253     }
254     }
255 n-ki 596
256     /* all read and writes of files should be non blocking */
257     if (fcntl(handle, F_SETFL, O_NONBLOCK) == -1)
258     perror("fcntl");
259 n-ki 569 }
260 n-ki 596
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 n-ki 569 {
265 n-ki 596 /* 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 n-ki 569 {
271 n-ki 596 flags_and_attributes |= FILE_DIRECTORY_FILE;
272     close(handle);
273     handle = 0;
274 n-ki 569 }
275 n-ki 596 }
276    
277    
278     if (flags_and_attributes & FILE_DIRECTORY_FILE)
279     {
280     if (flags & O_CREAT)
281 n-ki 569 {
282 n-ki 596 mkdir(path, mode);
283 n-ki 569 }
284    
285 n-ki 596 dirp = opendir(path);
286     if (!dirp)
287 n-ki 569 {
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 n-ki 596 perror("opendir");
301 n-ki 569 return STATUS_NO_SUCH_FILE;
302     }
303     }
304 n-ki 596 handle = DIRFD(dirp);
305 n-ki 569 }
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 n-ki 596 // printf("create: attrib: %u handle %u\n", g_fileinfo[handle].flags_and_attributes, handle );
319 n-ki 569 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 n-ki 596 /* 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 n-ki 569 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 stargo 574 struct STATFS_T stat_fs;
542 n-ki 569 struct fileinfo *pfinfo;
543    
544     pfinfo = &(g_fileinfo[handle]);
545     volume = "RDESKTOP";
546     fs_type = "RDPFS";
547    
548 stargo 574 if (STATFS_FN(pfinfo->path, &stat_fs) != 0) /* FIXME: statfs is not portable */
549 n-ki 569 {
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 stargo 574 out_uint32_le(out, F_NAMELEN(stat_fs)); /* max length of filename */
580 n-ki 569 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 n-ki 596 /* JIF
639 n-ki 569 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