merge andreas flicks work on file timestamps and directory handling, and the beginning of a device control

git-svn-id: svn://svn.code.sf.net/p/rdesktop/code/trunk/rdesktop@599 423420c4-83ab-492f-b58f-81f9feb106b5
This commit is contained in:
Peter Kallden 2004-02-06 10:41:34 +00:00
parent 4991cbccc6
commit 991d0cf8c5

227
disk.c
View File

@ -98,6 +98,10 @@
#include <fnmatch.h> #include <fnmatch.h>
#include <errno.h> /* errno */ #include <errno.h> /* errno */
#include <utime.h>
#include <time.h> /* ctime */
#if defined(SOLARIS) #if defined(SOLARIS)
#include <sys/statvfs.h> /* solaris statvfs */ #include <sys/statvfs.h> /* solaris statvfs */
#define STATFS_FN(path, buf) (statvfs(path,buf)) #define STATFS_FN(path, buf) (statvfs(path,buf))
@ -133,6 +137,21 @@ struct fileinfo
} }
g_fileinfo[MAX_OPEN_FILES]; g_fileinfo[MAX_OPEN_FILES];
time_t
get_create_time(struct stat *st)
{
time_t ret, ret1;
ret = MIN(st->st_ctime, st->st_mtime);
ret1 = MIN(ret, st->st_atime);
if (ret1 != (time_t) 0)
return ret1;
return ret;
}
/* Convert seconds since 1970 to a filetime */ /* Convert seconds since 1970 to a filetime */
void void
seconds_since_1970_to_filetime(time_t seconds, uint32 * high, uint32 * low) seconds_since_1970_to_filetime(time_t seconds, uint32 * high, uint32 * low)
@ -144,6 +163,23 @@ seconds_since_1970_to_filetime(time_t seconds, uint32 * high, uint32 * low)
*high = (uint32) (ticks >> 32); *high = (uint32) (ticks >> 32);
} }
/* Convert seconds since 1970 back to filetime */
time_t
convert_1970_to_filetime(uint32 high, uint32 low)
{
unsigned long long ticks;
time_t val;
ticks = low + (((unsigned long long) high) << 32);
ticks /= 10000000;
ticks -= 11644473600LL;
val = (time_t) ticks;
return (val);
}
/* Enumeration of devices from rdesktop.c */ /* Enumeration of devices from rdesktop.c */
/* returns numer of units found and initialized. */ /* returns numer of units found and initialized. */
/* optarg looks like ':h:=/mnt/floppy,b:=/mnt/usbdevice1' */ /* optarg looks like ':h:=/mnt/floppy,b:=/mnt/usbdevice1' */
@ -188,12 +224,14 @@ disk_create(uint32 device_id, uint32 accessmask, uint32 sharemode, uint32 create
DIR *dirp; DIR *dirp;
int flags, mode; int flags, mode;
char path[256]; char path[256];
struct stat filestat;
handle = 0; handle = 0;
dirp = NULL; dirp = NULL;
flags = 0; flags = 0;
mode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH; mode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
if (filename[strlen(filename) - 1] == '/') if (filename[strlen(filename) - 1] == '/')
filename[strlen(filename) - 1] = 0; filename[strlen(filename) - 1] = 0;
sprintf(path, "%s%s", g_rdpdr_device[device_id].local_path, filename); sprintf(path, "%s%s", g_rdpdr_device[device_id].local_path, filename);
@ -233,13 +271,14 @@ disk_create(uint32 device_id, uint32 accessmask, uint32 sharemode, uint32 create
//printf("Open: \"%s\" flags: %u, accessmask: %u sharemode: %u create disp: %u\n", path, flags_and_attributes, accessmask, sharemode, create_disposition); //printf("Open: \"%s\" flags: %u, accessmask: %u sharemode: %u create disp: %u\n", path, flags_and_attributes, accessmask, sharemode, create_disposition);
/* since we can't trust the FILE_DIRECTORY_FILE flag */
/* we need to double check that the file isn't a dir */
struct stat filestat;
// Get information about file and set that flag ourselfs // Get information about file and set that flag ourselfs
if ((stat(path, &filestat) == 0) && (S_ISDIR(filestat.st_mode))) if ((stat(path, &filestat) == 0) && (S_ISDIR(filestat.st_mode)))
{
if (flags_and_attributes & FILE_NON_DIRECTORY_FILE)
return STATUS_FILE_IS_A_DIRECTORY;
else
flags_and_attributes |= FILE_DIRECTORY_FILE; flags_and_attributes |= FILE_DIRECTORY_FILE;
}
if (flags_and_attributes & FILE_DIRECTORY_FILE) if (flags_and_attributes & FILE_DIRECTORY_FILE)
{ {
@ -291,6 +330,10 @@ disk_create(uint32 device_id, uint32 accessmask, uint32 sharemode, uint32 create
{ {
switch (errno) switch (errno)
{ {
case EISDIR:
return STATUS_FILE_IS_A_DIRECTORY;
case EACCES: case EACCES:
return STATUS_ACCESS_DENIED; return STATUS_ACCESS_DENIED;
@ -352,6 +395,7 @@ disk_read(HANDLE handle, uint8 * data, uint32 length, uint32 offset, uint32 * re
{ {
int n; int n;
#if 0
/* browsing dir ???? */ /* browsing dir ???? */
/* each request is 24 bytes */ /* each request is 24 bytes */
if (g_fileinfo[handle].flags_and_attributes & FILE_DIRECTORY_FILE) if (g_fileinfo[handle].flags_and_attributes & FILE_DIRECTORY_FILE)
@ -359,6 +403,7 @@ disk_read(HANDLE handle, uint8 * data, uint32 length, uint32 offset, uint32 * re
*result = 0; *result = 0;
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
#endif
if (offset) if (offset)
lseek(handle, offset, SEEK_SET); lseek(handle, offset, SEEK_SET);
@ -366,10 +411,16 @@ disk_read(HANDLE handle, uint8 * data, uint32 length, uint32 offset, uint32 * re
if (n < 0) if (n < 0)
{ {
perror("read");
*result = 0; *result = 0;
switch (errno)
{
case EISDIR:
return STATUS_FILE_IS_A_DIRECTORY;
default:
perror("read");
return STATUS_INVALID_PARAMETER; return STATUS_INVALID_PARAMETER;
} }
}
*result = n; *result = n;
@ -390,8 +441,14 @@ disk_write(HANDLE handle, uint8 * data, uint32 length, uint32 offset, uint32 * r
{ {
perror("write"); perror("write");
*result = 0; *result = 0;
switch (errno)
{
case ENOSPC:
return STATUS_DISK_FULL;
default:
return STATUS_ACCESS_DENIED; return STATUS_ACCESS_DENIED;
} }
}
*result = n; *result = n;
@ -418,21 +475,26 @@ disk_query_information(HANDLE handle, uint32 info_class, STREAM out)
// Set file attributes // Set file attributes
file_attributes = 0; file_attributes = 0;
if (S_ISDIR(filestat.st_mode)) if (S_ISDIR(filestat.st_mode))
{
file_attributes |= FILE_ATTRIBUTE_DIRECTORY; file_attributes |= FILE_ATTRIBUTE_DIRECTORY;
}
filename = 1 + strrchr(path, '/'); filename = 1 + strrchr(path, '/');
if (filename && filename[0] == '.') if (filename && filename[0] == '.')
{
file_attributes |= FILE_ATTRIBUTE_HIDDEN; file_attributes |= FILE_ATTRIBUTE_HIDDEN;
}
if (!file_attributes)
file_attributes |= FILE_ATTRIBUTE_NORMAL;
if (!(filestat.st_mode & S_IWUSR))
file_attributes |= FILE_ATTRIBUTE_READONLY;
// Return requested data // Return requested data
switch (info_class) switch (info_class)
{ {
case 4: /* FileBasicInformation */ case 4: /* FileBasicInformation */
seconds_since_1970_to_filetime(get_create_time(&filestat), &ft_high,
out_uint8s(out, 8); //create_time not available; &ft_low);
out_uint32_le(out, ft_low); //create_access_time
out_uint32_le(out, ft_high);
seconds_since_1970_to_filetime(filestat.st_atime, &ft_high, &ft_low); seconds_since_1970_to_filetime(filestat.st_atime, &ft_high, &ft_low);
out_uint32_le(out, ft_low); //last_access_time out_uint32_le(out, ft_low); //last_access_time
@ -442,7 +504,10 @@ disk_query_information(HANDLE handle, uint32 info_class, STREAM out)
out_uint32_le(out, ft_low); //last_write_time out_uint32_le(out, ft_low); //last_write_time
out_uint32_le(out, ft_high); out_uint32_le(out, ft_high);
out_uint8s(out, 8); //unknown zero seconds_since_1970_to_filetime(filestat.st_ctime, &ft_high, &ft_low);
out_uint32_le(out, ft_low); //last_change_time
out_uint32_le(out, ft_high);
out_uint32_le(out, file_attributes); out_uint32_le(out, file_attributes);
break; break;
@ -478,13 +543,92 @@ disk_set_information(HANDLE handle, uint32 info_class, STREAM in, STREAM out)
char newname[256], fullpath[256]; char newname[256], fullpath[256];
struct fileinfo *pfinfo; struct fileinfo *pfinfo;
int mode;
struct stat filestat;
time_t write_time, change_time, access_time, mod_time;
struct utimbuf tvs;
pfinfo = &(g_fileinfo[handle]); pfinfo = &(g_fileinfo[handle]);
switch (info_class) switch (info_class)
{ {
case 4: /* FileBasicInformation */ case 4: /* FileBasicInformation */
write_time = change_time = access_time = 0;
// Probably safe to ignore in_uint8s(in, 4); /* Handle of root dir? */
in_uint8s(in, 24); /* unknown */
// CreationTime
in_uint32_le(in, ft_low);
in_uint32_le(in, ft_high);
// AccessTime
in_uint32_le(in, ft_low);
in_uint32_le(in, ft_high);
if (ft_low || ft_high)
access_time = convert_1970_to_filetime(ft_high, ft_low);
// WriteTime
in_uint32_le(in, ft_low);
in_uint32_le(in, ft_high);
if (ft_low || ft_high)
write_time = convert_1970_to_filetime(ft_high, ft_low);
// ChangeTime
in_uint32_le(in, ft_low);
in_uint32_le(in, ft_high);
if (ft_low || ft_high)
change_time = convert_1970_to_filetime(ft_high, ft_low);
in_uint32_le(in, file_attributes);
if (fstat(handle, &filestat))
return STATUS_ACCESS_DENIED;
tvs.modtime = filestat.st_mtime;
tvs.actime = filestat.st_atime;
if (access_time)
tvs.actime = access_time;
if (write_time || change_time)
mod_time = MIN(write_time, change_time);
else
mod_time = write_time ? write_time : change_time;
if (mod_time)
tvs.modtime = mod_time;
if (access_time || write_time || change_time)
{
#if WITH_DEBUG_RDP5
printf("FileBasicInformation access time %s",
ctime(&tvs.actime));
printf("FileBasicInformation modification time %s",
ctime(&tvs.modtime));
#endif
if (utime(pfinfo->path, &tvs))
return STATUS_ACCESS_DENIED;
}
if (!file_attributes)
break; // not valid
mode = filestat.st_mode;
if (file_attributes & FILE_ATTRIBUTE_READONLY)
mode &= ~(S_IWUSR | S_IWGRP | S_IWOTH);
else
mode |= S_IWUSR;
mode &= 0777;
#if WITH_DEBUG_RDP5
printf("FileBasicInformation set access mode 0%o", mode);
#endif
if (fchmod(handle, mode))
return STATUS_ACCESS_DENIED;
break; break;
case 10: /* FileRenameInformation */ case 10: /* FileRenameInformation */
@ -527,10 +671,14 @@ disk_set_information(HANDLE handle, uint32 info_class, STREAM in, STREAM out)
break; break;
case 20: /* FileEndOfFileInformation */ case 20: /* FileEndOfFileInformation */
in_uint8s(in, 28); /* unknown */
in_uint32_le(in, length); /* file size */
printf("FileEndOfFileInformation length = %d\n", length);
// ????????????
unimpl("IRP Set File Information class: FileEndOfFileInformation\n"); unimpl("IRP Set File Information class: FileEndOfFileInformation\n");
break; break;
default: default:
unimpl("IRP Set File Information class: 0x%x\n", info_class); unimpl("IRP Set File Information class: 0x%x\n", info_class);
@ -550,7 +698,7 @@ disk_query_volume_information(HANDLE handle, uint32 info_class, STREAM out)
volume = "RDESKTOP"; volume = "RDESKTOP";
fs_type = "RDPFS"; fs_type = "RDPFS";
if (STATFS_FN(pfinfo->path, &stat_fs) != 0) /* FIXME: statfs is not portable */ if (STATFS_FN(pfinfo->path, &stat_fs) != 0)
{ {
perror("statfs"); perror("statfs");
return STATUS_ACCESS_DENIED; return STATUS_ACCESS_DENIED;
@ -629,17 +777,14 @@ disk_query_directory(HANDLE handle, uint32 info_class, char *pattern, STREAM out
// find next dirent matching pattern // find next dirent matching pattern
pdirent = readdir(pdir); pdirent = readdir(pdir);
while (pdirent && fnmatch(pfinfo->pattern, pdirent->d_name, 0) != 0) while (pdirent && fnmatch(pfinfo->pattern, pdirent->d_name, 0) != 0)
{
pdirent = readdir(pdir); pdirent = readdir(pdir);
}
if (pdirent == NULL) if (pdirent == NULL)
{
return STATUS_NO_MORE_FILES; return STATUS_NO_MORE_FILES;
}
// Get information for directory entry // Get information for directory entry
sprintf(fullpath, "%s/%s", dirname, pdirent->d_name); sprintf(fullpath, "%s/%s", dirname, pdirent->d_name);
/* JIF /* JIF
printf("Stat: %s\n", fullpath); */ printf("Stat: %s\n", fullpath); */
if (stat(fullpath, &fstat)) if (stat(fullpath, &fstat))
@ -653,10 +798,17 @@ disk_query_directory(HANDLE handle, uint32 info_class, char *pattern, STREAM out
file_attributes |= FILE_ATTRIBUTE_DIRECTORY; file_attributes |= FILE_ATTRIBUTE_DIRECTORY;
if (pdirent->d_name[0] == '.') if (pdirent->d_name[0] == '.')
file_attributes |= FILE_ATTRIBUTE_HIDDEN; file_attributes |= FILE_ATTRIBUTE_HIDDEN;
if (!file_attributes)
file_attributes |= FILE_ATTRIBUTE_NORMAL;
if (!(fstat.st_mode & S_IWUSR))
file_attributes |= FILE_ATTRIBUTE_READONLY;
// Return requested information // Return requested information
out_uint8s(out, 8); //unknown zero out_uint8s(out, 8); //unknown zero
out_uint8s(out, 8); //create_time not available in posix;
seconds_since_1970_to_filetime(get_create_time(&fstat), &ft_high, &ft_low);
out_uint32_le(out, ft_low); // create time
out_uint32_le(out, ft_high);
seconds_since_1970_to_filetime(fstat.st_atime, &ft_high, &ft_low); seconds_since_1970_to_filetime(fstat.st_atime, &ft_high, &ft_low);
out_uint32_le(out, ft_low); //last_access_time out_uint32_le(out, ft_low); //last_access_time
@ -666,7 +818,10 @@ disk_query_directory(HANDLE handle, uint32 info_class, char *pattern, STREAM out
out_uint32_le(out, ft_low); //last_write_time out_uint32_le(out, ft_low); //last_write_time
out_uint32_le(out, ft_high); out_uint32_le(out, ft_high);
out_uint8s(out, 8); //unknown zero seconds_since_1970_to_filetime(fstat.st_ctime, &ft_high, &ft_low);
out_uint32_le(out, ft_low); //change_write_time
out_uint32_le(out, ft_high);
out_uint32_le(out, fstat.st_size); //filesize low out_uint32_le(out, fstat.st_size); //filesize low
out_uint32_le(out, 0); //filesize high out_uint32_le(out, 0); //filesize high
out_uint32_le(out, fstat.st_size); //filesize low out_uint32_le(out, fstat.st_size); //filesize low
@ -688,10 +843,38 @@ disk_query_directory(HANDLE handle, uint32 info_class, char *pattern, STREAM out
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
static NTSTATUS
disk_device_control(HANDLE handle, uint32 request, STREAM in, STREAM out)
{
uint32 result;
if (((request >> 16) != 20) || ((request >> 16) != 9))
return STATUS_INVALID_PARAMETER;
/* extract operation */
request >>= 2;
request &= 0xfff;
printf("DISK IOCTL %d\n", request);
switch (request)
{
case 25: // ?
case 42: // ?
default:
unimpl("DISK IOCTL %d\n", request);
return STATUS_INVALID_PARAMETER;
}
return STATUS_SUCCESS;
}
DEVICE_FNS disk_fns = { DEVICE_FNS disk_fns = {
disk_create, disk_create,
disk_close, disk_close,
disk_read, disk_read,
disk_write, disk_write,
NULL /* device_control */ disk_device_control /* device_control */
}; };