?? disk.c
字號:
/* -*- c-basic-offset: 8 -*- rdesktop: A Remote Desktop Protocol client. Disk Redirection Copyright (C) Jeroen Meijer 2003-2007 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.*/#include "disk.h"#include <sys/types.h>#include <sys/stat.h>#include <unistd.h>#include <fcntl.h> /* open, close */#include <dirent.h> /* opendir, closedir, readdir */#include <fnmatch.h>#include <errno.h> /* errno */#include <stdio.h>#include <utime.h>#include <time.h> /* ctime */#if (defined(HAVE_DIRFD) || (HAVE_DECL_DIRFD == 1))#define DIRFD(a) (dirfd(a))#else#define DIRFD(a) ((a)->DIR_FD_MEMBER_NAME)#endif/* TODO: Fix mntent-handling for solaris * #include <sys/mntent.h> */#if (defined(HAVE_MNTENT_H) && defined(HAVE_SETMNTENT))#include <mntent.h>#define MNTENT_PATH "/etc/mtab"#define USE_SETMNTENT#endif#ifdef HAVE_SYS_VFS_H#include <sys/vfs.h>#endif#ifdef HAVE_SYS_STATVFS_H#include <sys/statvfs.h>#endif#ifdef HAVE_SYS_STATFS_H#include <sys/statfs.h>#endif#ifdef HAVE_SYS_PARAM_H#include <sys/param.h>#endif#ifdef HAVE_SYS_MOUNT_H#include <sys/mount.h>#endif#include "rdesktop.h"#ifdef STAT_STATFS3_OSF1#define STATFS_FN(path, buf) (statfs(path,buf,sizeof(buf)))#define STATFS_T statfs#define USE_STATFS#endif#ifdef STAT_STATVFS#define STATFS_FN(path, buf) (statvfs(path,buf))#define STATFS_T statvfs#define USE_STATVFS#endif#ifdef STAT_STATVFS64#define STATFS_FN(path, buf) (statvfs64(path,buf))#define STATFS_T statvfs64#define USE_STATVFS#endif#if (defined(STAT_STATFS2_FS_DATA) || defined(STAT_STATFS2_BSIZE) || defined(STAT_STATFS2_FSIZE))#define STATFS_FN(path, buf) (statfs(path,buf))#define STATFS_T statfs#define USE_STATFS#endif#ifdef STAT_STATFS4#define STATFS_FN(path, buf) (statfs(path,buf,sizeof(buf),0))#define STATFS_T statfs#define USE_STATFS#endif#if ((defined(USE_STATFS) && defined(HAVE_STRUCT_STATFS_F_NAMEMAX)) || (defined(USE_STATVFS) && defined(HAVE_STRUCT_STATVFS_F_NAMEMAX)))#define F_NAMELEN(buf) ((buf).f_namemax)#endif#if ((defined(USE_STATFS) && defined(HAVE_STRUCT_STATFS_F_NAMELEN)) || (defined(USE_STATVFS) && defined(HAVE_STRUCT_STATVFS_F_NAMELEN)))#define F_NAMELEN(buf) ((buf).f_namelen)#endif#ifndef F_NAMELEN#define F_NAMELEN(buf) (255)#endif/* Dummy statfs fallback */#ifndef STATFS_Tstruct dummy_statfs_t{ long f_bfree; long f_bsize; long f_blocks; int f_namelen; int f_namemax;};static intdummy_statfs(struct dummy_statfs_t *buf){ buf->f_blocks = 262144; buf->f_bfree = 131072; buf->f_bsize = 512; buf->f_namelen = 255; buf->f_namemax = 255; return 0;}#define STATFS_T dummy_statfs_t#define STATFS_FN(path,buf) (dummy_statfs(buf))#endifextern RDPDR_DEVICE g_rdpdr_device[];FILEINFO g_fileinfo[MAX_OPEN_FILES];RD_BOOL g_notify_stamp = False;typedef struct{ char name[PATH_MAX]; char label[PATH_MAX]; unsigned long serial; char type[PATH_MAX];} FsInfoType;static RD_NTSTATUS NotifyInfo(RD_NTHANDLE handle, uint32 info_class, NOTIFY * p);static time_tget_create_time(struct stat *filestat){ time_t ret, ret1; ret = MIN(filestat->st_ctime, filestat->st_mtime); ret1 = MIN(ret, filestat->st_atime); if (ret1 != (time_t) 0) return ret1; return ret;}/* Convert seconds since 1970 to a filetime */static voidseconds_since_1970_to_filetime(time_t seconds, uint32 * high, uint32 * low){ unsigned long long ticks; ticks = (seconds + 11644473600LL) * 10000000; *low = (uint32) ticks; *high = (uint32) (ticks >> 32);}/* Convert seconds since 1970 back to filetime */static time_tconvert_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);}/* A wrapper for ftruncate which supports growing files, even if the native ftruncate doesn't. This is needed on Linux FAT filesystems, for example. */static intftruncate_growable(int fd, off_t length){ int ret; off_t pos; static const char zero = 0; /* Try the simple method first */ if ((ret = ftruncate(fd, length)) != -1) { return ret; } /* * Some kind of error. Perhaps we were trying to grow. Retry * in a safe way. */ /* Get current position */ if ((pos = lseek(fd, 0, SEEK_CUR)) == -1) { perror("lseek"); return -1; } /* Seek to new size */ if (lseek(fd, length, SEEK_SET) == -1) { perror("lseek"); return -1; } /* Write a zero */ if (write(fd, &zero, 1) == -1) { perror("write"); return -1; } /* Truncate. This shouldn't fail. */ if (ftruncate(fd, length) == -1) { perror("ftruncate"); return -1; } /* Restore position */ if (lseek(fd, pos, SEEK_SET) == -1) { perror("lseek"); return -1; } return 0;}/* Just like open(2), but if a open with O_EXCL fails, retry with GUARDED semantics. This might be necessary because some filesystems (such as NFS filesystems mounted from a unfsd server) doesn't support O_EXCL. GUARDED semantics are subject to race conditions, but we can live with that.*/static intopen_weak_exclusive(const char *pathname, int flags, mode_t mode){ int ret; struct stat filestat; ret = open(pathname, flags, mode); if (ret != -1 || !(flags & O_EXCL)) { /* Success, or not using O_EXCL */ return ret; } /* An error occured, and we are using O_EXCL. In case the FS doesn't support O_EXCL, some kind of error will be returned. Unfortunately, we don't know which one. Linux 2.6.8 seems to return 524, but I cannot find a documented #define for this case. So, we'll return only on errors that we know aren't related to O_EXCL. */ switch (errno) { case EACCES: case EEXIST: case EINTR: case EISDIR: case ELOOP: case ENAMETOOLONG: case ENOENT: case ENOTDIR: return ret; } /* Retry with GUARDED semantics */ if (stat(pathname, &filestat) != -1) { /* File exists */ errno = EEXIST; return -1; } else { return open(pathname, flags & ~O_EXCL, mode); }}/* Enumeration of devices from rdesktop.c *//* returns numer of units found and initialized. *//* optarg looks like ':h=/mnt/floppy,b=/mnt/usbdevice1' *//* when it arrives to this function. */intdisk_enum_devices(uint32 * id, char *optarg){ char *pos = optarg; char *pos2; int count = 0; /* skip the first colon */ optarg++; while ((pos = next_arg(optarg, ',')) && *id < RDPDR_MAX_DEVICES) { pos2 = next_arg(optarg, '='); strncpy(g_rdpdr_device[*id].name, optarg, sizeof(g_rdpdr_device[*id].name) - 1); if (strlen(optarg) > (sizeof(g_rdpdr_device[*id].name) - 1)) fprintf(stderr, "share name %s truncated to %s\n", optarg, g_rdpdr_device[*id].name); g_rdpdr_device[*id].local_path = (char *) xmalloc(strlen(pos2) + 1); strcpy(g_rdpdr_device[*id].local_path, pos2); g_rdpdr_device[*id].device_type = DEVICE_TYPE_DISK; count++; (*id)++; optarg = pos; } return count;}/* Opens or creates a file or directory */static RD_NTSTATUSdisk_create(uint32 device_id, uint32 accessmask, uint32 sharemode, uint32 create_disposition, uint32 flags_and_attributes, char *filename, RD_NTHANDLE * phandle){ RD_NTHANDLE handle; DIR *dirp; int flags, mode; char path[PATH_MAX]; struct stat filestat; handle = 0; dirp = NULL; flags = 0; mode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH; if (*filename && filename[strlen(filename) - 1] == '/') filename[strlen(filename) - 1] = 0; sprintf(path, "%s%s", g_rdpdr_device[device_id].local_path, filename); switch (create_disposition) { case CREATE_ALWAYS: /* Delete existing file/link. */ unlink(path); flags |= O_CREAT; break; case CREATE_NEW: /* If the file already exists, then fail. */ flags |= O_CREAT | O_EXCL; break; case OPEN_ALWAYS: /* Create if not already exists. */ flags |= O_CREAT; break; case OPEN_EXISTING: /* Default behaviour */ break; case TRUNCATE_EXISTING: /* If the file does not exist, then fail. */ flags |= O_TRUNC; break; } /*printf("Open: \"%s\" flags: %X, accessmask: %X sharemode: %X create disp: %X\n", path, flags_and_attributes, accessmask, sharemode, create_disposition); */ /* Get information about file and set that flag ourselfs */ if ((stat(path, &filestat) == 0) && (S_ISDIR(filestat.st_mode))) { if (flags_and_attributes & FILE_NON_DIRECTORY_FILE) return RD_STATUS_FILE_IS_A_DIRECTORY; else flags_and_attributes |= FILE_DIRECTORY_FILE; } if (flags_and_attributes & FILE_DIRECTORY_FILE) { if (flags & O_CREAT) { mkdir(path, mode); } dirp = opendir(path); if (!dirp) { switch (errno) { case EACCES: return RD_STATUS_ACCESS_DENIED; case ENOENT: return RD_STATUS_NO_SUCH_FILE; default: perror("opendir"); return RD_STATUS_NO_SUCH_FILE; } } handle = DIRFD(dirp); } else { if (accessmask & GENERIC_ALL || (accessmask & GENERIC_READ && accessmask & GENERIC_WRITE)) { flags |= O_RDWR; } else if ((accessmask & GENERIC_WRITE) && !(accessmask & GENERIC_READ)) { flags |= O_WRONLY; } else { flags |= O_RDONLY; } handle = open_weak_exclusive(path, flags, mode); if (handle == -1) { switch (errno) { case EISDIR: return RD_STATUS_FILE_IS_A_DIRECTORY; case EACCES: return RD_STATUS_ACCESS_DENIED; case ENOENT: return RD_STATUS_NO_SUCH_FILE; case EEXIST: return RD_STATUS_OBJECT_NAME_COLLISION; default: perror("open"); return RD_STATUS_NO_SUCH_FILE; } } /* all read and writes of files should be non blocking */ if (fcntl(handle, F_SETFL, O_NONBLOCK) == -1) perror("fcntl"); } if (handle >= MAX_OPEN_FILES) { error("Maximum number of open files (%s) reached. Increase MAX_OPEN_FILES!\n", handle); exit(1); } if (dirp) g_fileinfo[handle].pdir = dirp; else g_fileinfo[handle].pdir = NULL; g_fileinfo[handle].device_id = device_id; g_fileinfo[handle].flags_and_attributes = flags_and_attributes; g_fileinfo[handle].accessmask = accessmask; strncpy(g_fileinfo[handle].path, path, PATH_MAX - 1); g_fileinfo[handle].delete_on_close = False; if (accessmask & GENERIC_ALL || accessmask & GENERIC_WRITE) g_notify_stamp = True; *phandle = handle; return RD_STATUS_SUCCESS;}static RD_NTSTATUSdisk_close(RD_NTHANDLE handle){ struct fileinfo *pfinfo; pfinfo = &(g_fileinfo[handle]); if (pfinfo->accessmask & GENERIC_ALL || pfinfo->accessmask & GENERIC_WRITE) g_notify_stamp = True; rdpdr_abort_io(handle, 0, RD_STATUS_CANCELLED); if (pfinfo->pdir) { if (closedir(pfinfo->pdir) < 0) { perror("closedir"); return RD_STATUS_INVALID_HANDLE; } if (pfinfo->delete_on_close) if (rmdir(pfinfo->path) < 0) { perror(pfinfo->path); return RD_STATUS_ACCESS_DENIED; } pfinfo->delete_on_close = False; } else { if (close(handle) < 0) { perror("close"); return RD_STATUS_INVALID_HANDLE; } if (pfinfo->delete_on_close) if (unlink(pfinfo->path) < 0) { perror(pfinfo->path); return RD_STATUS_ACCESS_DENIED; } pfinfo->delete_on_close = False; } return RD_STATUS_SUCCESS;}static RD_NTSTATUSdisk_read(RD_NTHANDLE handle, uint8 * data, uint32 length, uint32 offset, uint32 * result){ int n;#if 0 /* browsing dir ???? */ /* each request is 24 bytes */ if (g_fileinfo[handle].flags_and_attributes & FILE_DIRECTORY_FILE) { *result = 0; return STATUS_SUCCESS; }#endif lseek(handle, offset, SEEK_SET); n = read(handle, data, length); if (n < 0) { *result = 0; switch (errno) { case EISDIR: /* Implement 24 Byte directory read ?? with STATUS_NOT_IMPLEMENTED server doesn't read again */ /* return STATUS_FILE_IS_A_DIRECTORY; */ return RD_STATUS_NOT_IMPLEMENTED; default: perror("read"); return RD_STATUS_INVALID_PARAMETER; } } *result = n; return RD_STATUS_SUCCESS;}static RD_NTSTATUSdisk_write(RD_NTHANDLE handle, uint8 * data, uint32 length, uint32 offset, uint32 * result){ int n; lseek(handle, offset, SEEK_SET); n = write(handle, data, length); if (n < 0) { perror("write"); *result = 0; switch (errno) { case ENOSPC: return RD_STATUS_DISK_FULL; default: return RD_STATUS_ACCESS_DENIED; } } *result = n; return RD_STATUS_SUCCESS;}RD_NTSTATUSdisk_query_information(RD_NTHANDLE handle, uint32 info_class, STREAM out){ uint32 file_attributes, ft_high, ft_low; struct stat filestat; char *path, *filename; path = g_fileinfo[handle].path; /* Get information about file */
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -