1 /* -*- c-basic-offset: 8 -*-
2 rdesktop: A Remote Desktop Protocol client.
4 Copyright (C) Jeroen Meijer 2003
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.
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.
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.
23 #include <sys/types.h>
26 #include <fcntl.h> /* open, close */
27 #include <dirent.h> /* opendir, closedir, readdir */
29 #include <errno.h> /* errno */
33 #include <time.h> /* ctime */
35 #if (defined(HAVE_DIRFD) || (HAVE_DECL_DIRFD == 1))
36 #define DIRFD(a) (dirfd(a))
38 #define DIRFD(a) ((a)->DIR_FD_MEMBER_NAME)
41 /* TODO: Fix mntent-handling for solaris
42 * #include <sys/mntent.h> */
43 #if (defined(HAVE_MNTENT_H) && defined(HAVE_SETMNTENT))
45 #define MNTENT_PATH "/etc/mtab"
53 #ifdef HAVE_SYS_STATVFS_H
54 #include <sys/statvfs.h>
57 #ifdef HAVE_SYS_STATFS_H
58 #include <sys/statfs.h>
61 #ifdef HAVE_SYS_PARAM_H
62 #include <sys/param.h>
65 #ifdef HAVE_SYS_MOUNT_H
66 #include <sys/mount.h>
71 #ifdef STAT_STATFS3_OSF1
72 #define STATFS_FN(path, buf) (statfs(path,buf,sizeof(buf)))
73 #define STATFS_T statfs
78 #define STATFS_FN(path, buf) (statvfs(path,buf))
79 #define STATFS_T statvfs
84 #define STATFS_FN(path, buf) (statvfs64(path,buf))
85 #define STATFS_T statvfs64
89 #if (defined(STAT_STATFS2_FS_DATA) || defined(STAT_STATFS2_BSIZE) || defined(STAT_STATFS2_FSIZE))
90 #define STATFS_FN(path, buf) (statfs(path,buf))
91 #define STATFS_T statfs
96 #define STATFS_FN(path, buf) (statfs(path,buf,sizeof(buf),0))
97 #define STATFS_T statfs
101 #if ((defined(USE_STATFS) && defined(HAVE_STRUCT_STATFS_F_NAMEMAX)) || (defined(USE_STATVFS) && defined(HAVE_STRUCT_STATVFS_F_NAMEMAX)))
102 #define F_NAMELEN(buf) ((buf).f_namemax)
105 #if ((defined(USE_STATFS) && defined(HAVE_STRUCT_STATFS_F_NAMELEN)) || (defined(USE_STATVFS) && defined(HAVE_STRUCT_STATVFS_F_NAMELEN)))
106 #define F_NAMELEN(buf) ((buf).f_namelen)
110 #define F_NAMELEN(buf) (255)
113 /* Dummy statfs fallback */
115 struct dummy_statfs_t
125 dummy_statfs(struct dummy_statfs_t
*buf
)
127 buf
->f_blocks
= 262144;
128 buf
->f_bfree
= 131072;
130 buf
->f_namelen
= 255;
131 buf
->f_namemax
= 255;
136 #define STATFS_T dummy_statfs_t
137 #define STATFS_FN(path,buf) (dummy_statfs(buf))
143 char label
[PATH_MAX
];
144 unsigned long serial
;
148 static NTSTATUS
NotifyInfo(RDPCLIENT
* This
, NTHANDLE handle
, uint32 info_class
, NOTIFY
* p
);
151 get_create_time(struct stat
*st
)
155 ret
= MIN(st
->st_ctime
, st
->st_mtime
);
156 ret1
= MIN(ret
, st
->st_atime
);
158 if (ret1
!= (time_t) 0)
164 /* Convert seconds since 1970 to a filetime */
166 seconds_since_1970_to_filetime(time_t seconds
, uint32
* high
, uint32
* low
)
168 unsigned long long ticks
;
170 ticks
= (seconds
+ 11644473600LL) * 10000000;
171 *low
= (uint32
) ticks
;
172 *high
= (uint32
) (ticks
>> 32);
175 /* Convert seconds since 1970 back to filetime */
177 convert_1970_to_filetime(uint32 high
, uint32 low
)
179 unsigned long long ticks
;
182 ticks
= low
+ (((unsigned long long) high
) << 32);
184 ticks
-= 11644473600LL;
186 val
= (time_t) ticks
;
191 /* A wrapper for ftruncate which supports growing files, even if the
192 native ftruncate doesn't. This is needed on Linux FAT filesystems,
195 ftruncate_growable(int fd
, off_t length
)
199 static const char zero
= 0;
201 /* Try the simple method first */
202 if ((ret
= ftruncate(fd
, length
)) != -1)
208 * Some kind of error. Perhaps we were trying to grow. Retry
212 /* Get current position */
213 if ((pos
= lseek(fd
, 0, SEEK_CUR
)) == -1)
219 /* Seek to new size */
220 if (lseek(fd
, length
, SEEK_SET
) == -1)
227 if (write(fd
, &zero
, 1) == -1)
233 /* Truncate. This shouldn't fail. */
234 if (ftruncate(fd
, length
) == -1)
240 /* Restore position */
241 if (lseek(fd
, pos
, SEEK_SET
) == -1)
250 /* Just like open(2), but if a open with O_EXCL fails, retry with
251 GUARDED semantics. This might be necessary because some filesystems
252 (such as NFS filesystems mounted from a unfsd server) doesn't
253 support O_EXCL. GUARDED semantics are subject to race conditions,
254 but we can live with that.
257 open_weak_exclusive(const char *pathname
, int flags
, mode_t mode
)
262 ret
= open(pathname
, flags
, mode
);
263 if (ret
!= -1 || !(flags
& O_EXCL
))
265 /* Success, or not using O_EXCL */
269 /* An error occured, and we are using O_EXCL. In case the FS
270 doesn't support O_EXCL, some kind of error will be
271 returned. Unfortunately, we don't know which one. Linux
272 2.6.8 seems to return 524, but I cannot find a documented
273 #define for this case. So, we'll return only on errors that
274 we know aren't related to O_EXCL. */
288 /* Retry with GUARDED semantics */
289 if (stat(pathname
, &statbuf
) != -1)
297 return open(pathname
, flags
& ~O_EXCL
, mode
);
301 /* Enumeration of devices from rdesktop.c */
302 /* returns numer of units found and initialized. */
303 /* optarg looks like ':h=/mnt/floppy,b=/mnt/usbdevice1' */
304 /* when it arrives to this function. */
306 disk_enum_devices(RDPCLIENT
* This
, uint32
* id
, char *optarg
)
312 /* skip the first colon */
314 while ((pos
= next_arg(optarg
, ',')) && *id
< RDPDR_MAX_DEVICES
)
316 pos2
= next_arg(optarg
, '=');
318 strncpy(This
->rdpdr_device
[*id
].name
, optarg
, sizeof(This
->rdpdr_device
[*id
].name
) - 1);
319 if (strlen(optarg
) > (sizeof(This
->rdpdr_device
[*id
].name
) - 1))
320 fprintf(stderr
, "share name %s truncated to %s\n", optarg
,
321 This
->rdpdr_device
[*id
].name
);
323 This
->rdpdr_device
[*id
].local_path
= (char *) xmalloc(strlen(pos2
) + 1);
324 strcpy(This
->rdpdr_device
[*id
].local_path
, pos2
);
325 This
->rdpdr_device
[*id
].device_type
= DEVICE_TYPE_DISK
;
334 /* Opens or creates a file or directory */
336 disk_create(RDPCLIENT
* This
, uint32 device_id
, uint32 accessmask
, uint32 sharemode
, uint32 create_disposition
,
337 uint32 flags_and_attributes
, char *filename
, NTHANDLE
* phandle
)
343 struct stat filestat
;
348 mode
= S_IRWXU
| S_IRGRP
| S_IXGRP
| S_IROTH
| S_IXOTH
;
350 if (*filename
&& filename
[strlen(filename
) - 1] == '/')
351 filename
[strlen(filename
) - 1] = 0;
352 sprintf(path
, "%s%s", This
->rdpdr_device
[device_id
].local_path
, filename
);
354 switch (create_disposition
)
358 /* Delete existing file/link. */
365 /* If the file already exists, then fail. */
366 flags
|= O_CREAT
| O_EXCL
;
371 /* Create if not already exists. */
377 /* Default behaviour */
380 case TRUNCATE_EXISTING
:
382 /* If the file does not exist, then fail. */
387 /*printf("Open: \"%s\" flags: %X, accessmask: %X sharemode: %X create disp: %X\n", path, flags_and_attributes, accessmask, sharemode, create_disposition); */
389 /* Get information about file and set that flag ourselfs */
390 if ((stat(path
, &filestat
) == 0) && (S_ISDIR(filestat
.st_mode
)))
392 if (flags_and_attributes
& FILE_NON_DIRECTORY_FILE
)
393 return STATUS_FILE_IS_A_DIRECTORY
;
395 flags_and_attributes
|= FILE_DIRECTORY_FILE
;
398 if (flags_and_attributes
& FILE_DIRECTORY_FILE
)
405 dirp
= opendir(path
);
412 return STATUS_ACCESS_DENIED
;
416 return STATUS_NO_SUCH_FILE
;
421 return STATUS_NO_SUCH_FILE
;
424 handle
= DIRFD(dirp
);
429 if (accessmask
& GENERIC_ALL
430 || (accessmask
& GENERIC_READ
&& accessmask
& GENERIC_WRITE
))
434 else if ((accessmask
& GENERIC_WRITE
) && !(accessmask
& GENERIC_READ
))
443 handle
= open_weak_exclusive(path
, flags
, mode
);
450 return STATUS_FILE_IS_A_DIRECTORY
;
454 return STATUS_ACCESS_DENIED
;
458 return STATUS_NO_SUCH_FILE
;
461 return STATUS_OBJECT_NAME_COLLISION
;
465 return STATUS_NO_SUCH_FILE
;
469 /* all read and writes of files should be non blocking */
470 if (fcntl(handle
, F_SETFL
, O_NONBLOCK
) == -1)
474 if (handle
>= MAX_OPEN_FILES
)
476 error("Maximum number of open files (%s) reached. Increase MAX_OPEN_FILES!\n",
482 This
->fileinfo
[handle
].pdir
= dirp
;
484 This
->fileinfo
[handle
].pdir
= NULL
;
486 This
->fileinfo
[handle
].device_id
= device_id
;
487 This
->fileinfo
[handle
].flags_and_attributes
= flags_and_attributes
;
488 This
->fileinfo
[handle
].accessmask
= accessmask
;
489 strncpy(This
->fileinfo
[handle
].path
, path
, PATH_MAX
- 1);
490 This
->fileinfo
[handle
].delete_on_close
= False
;
491 This
->notify_stamp
= True
;
494 return STATUS_SUCCESS
;
498 disk_close(RDPCLIENT
* This
, NTHANDLE handle
)
500 struct fileinfo
*pfinfo
;
502 pfinfo
= &(This
->fileinfo
[handle
]);
504 This
->notify_stamp
= True
;
506 rdpdr_abort_io(This
, handle
, 0, STATUS_CANCELLED
);
510 if (closedir(pfinfo
->pdir
) < 0)
513 return STATUS_INVALID_HANDLE
;
516 if (pfinfo
->delete_on_close
)
517 if (rmdir(pfinfo
->path
) < 0)
519 perror(pfinfo
->path
);
520 return STATUS_ACCESS_DENIED
;
522 pfinfo
->delete_on_close
= False
;
526 if (close(handle
) < 0)
529 return STATUS_INVALID_HANDLE
;
531 if (pfinfo
->delete_on_close
)
532 if (unlink(pfinfo
->path
) < 0)
534 perror(pfinfo
->path
);
535 return STATUS_ACCESS_DENIED
;
538 pfinfo
->delete_on_close
= False
;
541 return STATUS_SUCCESS
;
545 disk_read(RDPCLIENT
* This
, NTHANDLE handle
, uint8
* data
, uint32 length
, uint32 offset
, uint32
* result
)
550 /* browsing dir ???? */
551 /* each request is 24 bytes */
552 if (This
->fileinfo
[handle
].flags_and_attributes
& FILE_DIRECTORY_FILE
)
555 return STATUS_SUCCESS
;
559 lseek(handle
, offset
, SEEK_SET
);
561 n
= read(handle
, data
, length
);
569 /* Implement 24 Byte directory read ??
570 with STATUS_NOT_IMPLEMENTED server doesn't read again */
571 /* return STATUS_FILE_IS_A_DIRECTORY; */
572 return STATUS_NOT_IMPLEMENTED
;
575 return STATUS_INVALID_PARAMETER
;
581 return STATUS_SUCCESS
;
585 disk_write(RDPCLIENT
* This
, NTHANDLE handle
, uint8
* data
, uint32 length
, uint32 offset
, uint32
* result
)
589 lseek(handle
, offset
, SEEK_SET
);
591 n
= write(handle
, data
, length
);
600 return STATUS_DISK_FULL
;
602 return STATUS_ACCESS_DENIED
;
608 return STATUS_SUCCESS
;
612 disk_query_information(RDPCLIENT
* This
, NTHANDLE handle
, uint32 info_class
, STREAM out
)
614 uint32 file_attributes
, ft_high
, ft_low
;
615 struct stat filestat
;
616 char *path
, *filename
;
618 path
= This
->fileinfo
[handle
].path
;
620 /* Get information about file */
621 if (fstat(handle
, &filestat
) != 0)
625 return STATUS_ACCESS_DENIED
;
628 /* Set file attributes */
630 if (S_ISDIR(filestat
.st_mode
))
631 file_attributes
|= FILE_ATTRIBUTE_DIRECTORY
;
633 filename
= 1 + strrchr(path
, '/');
634 if (filename
&& filename
[0] == '.')
635 file_attributes
|= FILE_ATTRIBUTE_HIDDEN
;
637 if (!file_attributes
)
638 file_attributes
|= FILE_ATTRIBUTE_NORMAL
;
640 if (!(filestat
.st_mode
& S_IWUSR
))
641 file_attributes
|= FILE_ATTRIBUTE_READONLY
;
643 /* Return requested data */
646 case FileBasicInformation
:
647 seconds_since_1970_to_filetime(get_create_time(&filestat
), &ft_high
,
649 out_uint32_le(out
, ft_low
); /* create_access_time */
650 out_uint32_le(out
, ft_high
);
652 seconds_since_1970_to_filetime(filestat
.st_atime
, &ft_high
, &ft_low
);
653 out_uint32_le(out
, ft_low
); /* last_access_time */
654 out_uint32_le(out
, ft_high
);
656 seconds_since_1970_to_filetime(filestat
.st_mtime
, &ft_high
, &ft_low
);
657 out_uint32_le(out
, ft_low
); /* last_write_time */
658 out_uint32_le(out
, ft_high
);
660 seconds_since_1970_to_filetime(filestat
.st_ctime
, &ft_high
, &ft_low
);
661 out_uint32_le(out
, ft_low
); /* last_change_time */
662 out_uint32_le(out
, ft_high
);
664 out_uint32_le(out
, file_attributes
);
667 case FileStandardInformation
:
669 out_uint32_le(out
, filestat
.st_size
); /* Allocation size */
670 out_uint32_le(out
, 0);
671 out_uint32_le(out
, filestat
.st_size
); /* End of file */
672 out_uint32_le(out
, 0);
673 out_uint32_le(out
, filestat
.st_nlink
); /* Number of links */
674 out_uint8(out
, 0); /* Delete pending */
675 out_uint8(out
, S_ISDIR(filestat
.st_mode
) ? 1 : 0); /* Directory */
678 case FileObjectIdInformation
:
680 out_uint32_le(out
, file_attributes
); /* File Attributes */
681 out_uint32_le(out
, 0); /* Reparse Tag */
686 unimpl("IRP Query (File) Information class: 0x%x\n", info_class
);
687 return STATUS_INVALID_PARAMETER
;
689 return STATUS_SUCCESS
;
693 disk_set_information(RDPCLIENT
* This
, NTHANDLE handle
, uint32 info_class
, STREAM in
, STREAM out
)
695 uint32 length
, file_attributes
, ft_high
, ft_low
, delete_on_close
;
696 char newname
[PATH_MAX
], fullpath
[PATH_MAX
];
697 struct fileinfo
*pfinfo
;
699 struct stat filestat
;
700 time_t write_time
, change_time
, access_time
, mod_time
;
702 struct STATFS_T stat_fs
;
704 pfinfo
= &(This
->fileinfo
[handle
]);
705 This
->notify_stamp
= True
;
709 case FileBasicInformation
:
710 write_time
= change_time
= access_time
= 0;
712 in_uint8s(in
, 4); /* Handle of root dir? */
713 in_uint8s(in
, 24); /* unknown */
716 in_uint32_le(in
, ft_low
);
717 in_uint32_le(in
, ft_high
);
720 in_uint32_le(in
, ft_low
);
721 in_uint32_le(in
, ft_high
);
722 if (ft_low
|| ft_high
)
723 access_time
= convert_1970_to_filetime(ft_high
, ft_low
);
726 in_uint32_le(in
, ft_low
);
727 in_uint32_le(in
, ft_high
);
728 if (ft_low
|| ft_high
)
729 write_time
= convert_1970_to_filetime(ft_high
, ft_low
);
732 in_uint32_le(in
, ft_low
);
733 in_uint32_le(in
, ft_high
);
734 if (ft_low
|| ft_high
)
735 change_time
= convert_1970_to_filetime(ft_high
, ft_low
);
737 in_uint32_le(in
, file_attributes
);
739 if (fstat(handle
, &filestat
))
740 return STATUS_ACCESS_DENIED
;
742 tvs
.modtime
= filestat
.st_mtime
;
743 tvs
.actime
= filestat
.st_atime
;
745 tvs
.actime
= access_time
;
748 if (write_time
|| change_time
)
749 mod_time
= MIN(write_time
, change_time
);
751 mod_time
= write_time
? write_time
: change_time
;
754 tvs
.modtime
= mod_time
;
757 if (access_time
|| write_time
|| change_time
)
760 printf("FileBasicInformation access time %s",
762 printf("FileBasicInformation modification time %s",
763 ctime(&tvs
.modtime
));
765 if (utime(pfinfo
->path
, &tvs
) && errno
!= EPERM
)
766 return STATUS_ACCESS_DENIED
;
769 if (!file_attributes
)
770 break; /* not valid */
772 mode
= filestat
.st_mode
;
774 if (file_attributes
& FILE_ATTRIBUTE_READONLY
)
775 mode
&= ~(S_IWUSR
| S_IWGRP
| S_IWOTH
);
781 printf("FileBasicInformation set access mode 0%o", mode
);
784 if (fchmod(handle
, mode
))
785 return STATUS_ACCESS_DENIED
;
789 case FileRenameInformation
:
791 in_uint8s(in
, 4); /* Handle of root dir? */
792 in_uint8s(in
, 0x1a); /* unknown */
793 in_uint32_le(in
, length
);
795 if (length
&& (length
/ 2) < 256)
797 rdp_in_unistr(This
, in
, newname
, length
);
798 convert_to_unix_filename(newname
);
802 return STATUS_INVALID_PARAMETER
;
805 sprintf(fullpath
, "%s%s", This
->rdpdr_device
[pfinfo
->device_id
].local_path
,
808 if (rename(pfinfo
->path
, fullpath
) != 0)
811 return STATUS_ACCESS_DENIED
;
815 case FileDispositionInformation
:
816 /* As far as I understand it, the correct
817 thing to do here is to *schedule* a delete,
818 so it will be deleted when the file is
820 FileDispositionInformation requests with
821 DeleteFile set to FALSE should unschedule
823 http://www.osronline.com/article.cfm?article=245. */
825 in_uint32_le(in
, delete_on_close
);
827 if (delete_on_close
||
829 accessmask
& (FILE_DELETE_ON_CLOSE
| FILE_COMPLETE_IF_OPLOCKED
)))
831 pfinfo
->delete_on_close
= True
;
836 case FileAllocationInformation
:
837 /* Fall through to FileEndOfFileInformation,
838 which uses ftrunc. This is like Samba with
839 "strict allocation = false", and means that
840 we won't detect out-of-quota errors, for
843 case FileEndOfFileInformation
:
844 in_uint8s(in
, 28); /* unknown */
845 in_uint32_le(in
, length
); /* file size */
847 /* prevents start of writing if not enough space left on device */
848 if (STATFS_FN(This
->rdpdr_device
[pfinfo
->device_id
].local_path
, &stat_fs
) == 0)
849 if (stat_fs
.f_bfree
* stat_fs
.f_bsize
< length
)
850 return STATUS_DISK_FULL
;
852 if (ftruncate_growable(handle
, length
) != 0)
854 return STATUS_DISK_FULL
;
860 unimpl("IRP Set File Information class: 0x%x\n", info_class
);
861 return STATUS_INVALID_PARAMETER
;
863 return STATUS_SUCCESS
;
867 disk_check_notify(RDPCLIENT
* This
, NTHANDLE handle
)
869 struct fileinfo
*pfinfo
;
870 NTSTATUS status
= STATUS_PENDING
;
874 pfinfo
= &(This
->fileinfo
[handle
]);
876 return STATUS_INVALID_DEVICE_REQUEST
;
880 status
= NotifyInfo(This
, handle
, pfinfo
->info_class
, ¬ify
);
882 if (status
!= STATUS_PENDING
)
885 if (memcmp(&pfinfo
->notify
, ¬ify
, sizeof(NOTIFY
)))
887 /*printf("disk_check_notify found changed event\n"); */
888 memcpy(&pfinfo
->notify
, ¬ify
, sizeof(NOTIFY
));
889 status
= STATUS_NOTIFY_ENUM_DIR
;
898 disk_create_notify(RDPCLIENT
* This
, NTHANDLE handle
, uint32 info_class
)
901 struct fileinfo
*pfinfo
;
902 NTSTATUS ret
= STATUS_PENDING
;
904 /* printf("start disk_create_notify info_class %X\n", info_class); */
906 pfinfo
= &(This
->fileinfo
[handle
]);
907 pfinfo
->info_class
= info_class
;
909 ret
= NotifyInfo(This
, handle
, info_class
, &pfinfo
->notify
);
911 if (info_class
& 0x1000)
913 if (ret
== STATUS_PENDING
)
914 return STATUS_SUCCESS
;
917 /* printf("disk_create_notify: num_entries %d\n", pfinfo->notify.num_entries); */
925 NotifyInfo(RDPCLIENT
* This
, NTHANDLE handle
, uint32 info_class
, NOTIFY
* p
)
927 struct fileinfo
*pfinfo
;
933 pfinfo
= &(This
->fileinfo
[handle
]);
934 if (fstat(handle
, &buf
) < 0)
936 perror("NotifyInfo");
937 return STATUS_ACCESS_DENIED
;
939 p
->modify_time
= buf
.st_mtime
;
940 p
->status_time
= buf
.st_ctime
;
945 dpr
= opendir(pfinfo
->path
);
948 perror("NotifyInfo");
949 return STATUS_ACCESS_DENIED
;
953 while ((dp
= readdir(dpr
)))
955 if (!strcmp(dp
->d_name
, ".") || !strcmp(dp
->d_name
, ".."))
958 fullname
= (char *) xmalloc(strlen(pfinfo
->path
) + strlen(dp
->d_name
) + 2);
959 sprintf(fullname
, "%s/%s", pfinfo
->path
, dp
->d_name
);
961 if (!stat(fullname
, &buf
))
963 p
->total_time
+= (buf
.st_mtime
+ buf
.st_ctime
);
970 return STATUS_PENDING
;
974 FsVolumeInfo(char *fpath
)
977 static FsInfoType info
;
984 memset(&info
, 0, sizeof(info
));
985 strcpy(info
.label
, "RDESKTOP");
986 strcpy(info
.type
, "RDPFS");
989 fdfs
= setmntent(MNTENT_PATH
, "r");
993 while ((e
= getmntent(fdfs
)))
995 if (str_startswith(e
->mnt_dir
, fpath
))
997 strcpy(info
.type
, e
->mnt_type
);
998 strcpy(info
.name
, e
->mnt_fsname
);
999 if (strstr(e
->mnt_opts
, "vfat") || strstr(e
->mnt_opts
, "iso9660"))
1001 int fd
= open(e
->mnt_fsname
, O_RDONLY
);
1004 unsigned char buf
[512];
1005 memset(buf
, 0, sizeof(buf
));
1006 if (strstr(e
->mnt_opts
, "vfat"))
1009 strcpy(info
.type
, "vfat");
1010 read(fd
, buf
, sizeof(buf
));
1012 (buf
[42] << 24) + (buf
[41] << 16) +
1013 (buf
[40] << 8) + buf
[39];
1014 strncpy(info
.label
, buf
+ 43, 10);
1015 info
.label
[10] = '\0';
1017 else if (lseek(fd
, 32767, SEEK_SET
) >= 0) /* ISO9660 */
1019 read(fd
, buf
, sizeof(buf
));
1020 strncpy(info
.label
, buf
+ 41, 32);
1021 info
.label
[32] = '\0';
1022 /* info.Serial = (buf[128]<<24)+(buf[127]<<16)+(buf[126]<<8)+buf[125]; */
1032 memset(&info
, 0, sizeof(info
));
1033 strcpy(info
.label
, "RDESKTOP");
1034 strcpy(info
.type
, "RDPFS");
1042 disk_query_volume_information(RDPCLIENT
* This
, NTHANDLE handle
, uint32 info_class
, STREAM out
)
1044 struct STATFS_T stat_fs
;
1045 struct fileinfo
*pfinfo
;
1048 pfinfo
= &(This
->fileinfo
[handle
]);
1050 if (STATFS_FN(pfinfo
->path
, &stat_fs
) != 0)
1053 return STATUS_ACCESS_DENIED
;
1056 fsinfo
= FsVolumeInfo(pfinfo
->path
);
1060 case FileFsVolumeInformation
:
1062 out_uint32_le(out
, 0); /* volume creation time low */
1063 out_uint32_le(out
, 0); /* volume creation time high */
1064 out_uint32_le(out
, fsinfo
->serial
); /* serial */
1066 out_uint32_le(out
, 2 * strlen(fsinfo
->label
)); /* length of string */
1068 out_uint8(out
, 0); /* support objects? */
1069 rdp_out_unistr(This
, out
, fsinfo
->label
, 2 * strlen(fsinfo
->label
) - 2);
1072 case FileFsSizeInformation
:
1074 out_uint32_le(out
, stat_fs
.f_blocks
); /* Total allocation units low */
1075 out_uint32_le(out
, 0); /* Total allocation high units */
1076 out_uint32_le(out
, stat_fs
.f_bfree
); /* Available allocation units */
1077 out_uint32_le(out
, 0); /* Available allowcation units */
1078 out_uint32_le(out
, stat_fs
.f_bsize
/ 0x200); /* Sectors per allocation unit */
1079 out_uint32_le(out
, 0x200); /* Bytes per sector */
1082 case FileFsAttributeInformation
:
1084 out_uint32_le(out
, FS_CASE_SENSITIVE
| FS_CASE_IS_PRESERVED
); /* fs attributes */
1085 out_uint32_le(out
, F_NAMELEN(stat_fs
)); /* max length of filename */
1087 out_uint32_le(out
, 2 * strlen(fsinfo
->type
)); /* length of fs_type */
1088 rdp_out_unistr(This
, out
, fsinfo
->type
, 2 * strlen(fsinfo
->type
) - 2);
1091 case FileFsLabelInformation
:
1092 case FileFsDeviceInformation
:
1093 case FileFsControlInformation
:
1094 case FileFsFullSizeInformation
:
1095 case FileFsObjectIdInformation
:
1096 case FileFsMaximumInformation
:
1100 unimpl("IRP Query Volume Information class: 0x%x\n", info_class
);
1101 return STATUS_INVALID_PARAMETER
;
1103 return STATUS_SUCCESS
;
1107 disk_query_directory(RDPCLIENT
* This
, NTHANDLE handle
, uint32 info_class
, char *pattern
, STREAM out
)
1109 uint32 file_attributes
, ft_low
, ft_high
;
1110 char *dirname
, fullpath
[PATH_MAX
];
1112 struct dirent
*pdirent
;
1114 struct fileinfo
*pfinfo
;
1116 pfinfo
= &(This
->fileinfo
[handle
]);
1117 pdir
= pfinfo
->pdir
;
1118 dirname
= pfinfo
->path
;
1119 file_attributes
= 0;
1123 case FileBothDirectoryInformation
:
1125 /* If a search pattern is received, remember this pattern, and restart search */
1126 if (pattern
[0] != 0)
1128 strncpy(pfinfo
->pattern
, 1 + strrchr(pattern
, '/'), PATH_MAX
- 1);
1132 /* find next dirent matching pattern */
1133 pdirent
= readdir(pdir
);
1134 while (pdirent
&& fnmatch(pfinfo
->pattern
, pdirent
->d_name
, 0) != 0)
1135 pdirent
= readdir(pdir
);
1137 if (pdirent
== NULL
)
1138 return STATUS_NO_MORE_FILES
;
1140 /* Get information for directory entry */
1141 sprintf(fullpath
, "%s/%s", dirname
, pdirent
->d_name
);
1143 if (stat(fullpath
, &fstat
))
1150 /* These are non-fatal errors. */
1151 memset(&fstat
, 0, sizeof(fstat
));
1154 /* Fatal error. By returning STATUS_NO_SUCH_FILE,
1155 the directory list operation will be aborted */
1158 return STATUS_NO_SUCH_FILE
;
1162 if (S_ISDIR(fstat
.st_mode
))
1163 file_attributes
|= FILE_ATTRIBUTE_DIRECTORY
;
1164 if (pdirent
->d_name
[0] == '.')
1165 file_attributes
|= FILE_ATTRIBUTE_HIDDEN
;
1166 if (!file_attributes
)
1167 file_attributes
|= FILE_ATTRIBUTE_NORMAL
;
1168 if (!(fstat
.st_mode
& S_IWUSR
))
1169 file_attributes
|= FILE_ATTRIBUTE_READONLY
;
1171 /* Return requested information */
1172 out_uint8s(out
, 8); /* unknown zero */
1174 seconds_since_1970_to_filetime(get_create_time(&fstat
), &ft_high
, &ft_low
);
1175 out_uint32_le(out
, ft_low
); /* create time */
1176 out_uint32_le(out
, ft_high
);
1178 seconds_since_1970_to_filetime(fstat
.st_atime
, &ft_high
, &ft_low
);
1179 out_uint32_le(out
, ft_low
); /* last_access_time */
1180 out_uint32_le(out
, ft_high
);
1182 seconds_since_1970_to_filetime(fstat
.st_mtime
, &ft_high
, &ft_low
);
1183 out_uint32_le(out
, ft_low
); /* last_write_time */
1184 out_uint32_le(out
, ft_high
);
1186 seconds_since_1970_to_filetime(fstat
.st_ctime
, &ft_high
, &ft_low
);
1187 out_uint32_le(out
, ft_low
); /* change_write_time */
1188 out_uint32_le(out
, ft_high
);
1190 out_uint32_le(out
, fstat
.st_size
); /* filesize low */
1191 out_uint32_le(out
, 0); /* filesize high */
1192 out_uint32_le(out
, fstat
.st_size
); /* filesize low */
1193 out_uint32_le(out
, 0); /* filesize high */
1194 out_uint32_le(out
, file_attributes
);
1195 out_uint8(out
, 2 * strlen(pdirent
->d_name
) + 2); /* unicode length */
1196 out_uint8s(out
, 7); /* pad? */
1197 out_uint8(out
, 0); /* 8.3 file length */
1198 out_uint8s(out
, 2 * 12); /* 8.3 unicode length */
1199 rdp_out_unistr(This
, out
, pdirent
->d_name
, 2 * strlen(pdirent
->d_name
));
1203 /* FIXME: Support FileDirectoryInformation,
1204 FileFullDirectoryInformation, and
1205 FileNamesInformation */
1207 unimpl("IRP Query Directory sub: 0x%x\n", info_class
);
1208 return STATUS_INVALID_PARAMETER
;
1211 return STATUS_SUCCESS
;
1217 disk_device_control(RDPCLIENT
* This
, NTHANDLE handle
, uint32 request
, STREAM in
, STREAM out
)
1219 if (((request
>> 16) != 20) || ((request
>> 16) != 9))
1220 return STATUS_INVALID_PARAMETER
;
1222 /* extract operation */
1226 printf("DISK IOCTL %d\n", request
);
1233 unimpl("DISK IOCTL %d\n", request
);
1234 return STATUS_INVALID_PARAMETER
;
1237 return STATUS_SUCCESS
;
1240 DEVICE_FNS disk_fns
= {
1245 disk_device_control
/* device_control */