in src/protocols/rdp/fs.c [213:411]
int guac_rdp_fs_open(guac_rdp_fs* fs, const char* path,
int access, int file_attributes, int create_disposition,
int create_options) {
char real_path[GUAC_RDP_FS_MAX_PATH];
char normalized_path[GUAC_RDP_FS_MAX_PATH];
struct stat file_stat;
int fd;
int file_id;
guac_rdp_fs_file* file;
int flags = 0;
guac_client_log(fs->client, GUAC_LOG_DEBUG,
"%s: path=\"%s\", access=0x%x, file_attributes=0x%x, "
"create_disposition=0x%x, create_options=0x%x",
__func__, path, access, file_attributes,
create_disposition, create_options);
/* If no files available, return too many open */
if (fs->open_files >= GUAC_RDP_FS_MAX_FILES) {
guac_client_log(fs->client, GUAC_LOG_DEBUG,
"%s: Too many open files.",
__func__, path);
return GUAC_RDP_FS_ENFILE;
}
/* If path empty, transform to root path */
if (path[0] == '\0')
path = "\\";
/* If path is relative, the file does not exist */
else if (path[0] != '\\' && path[0] != '/') {
guac_client_log(fs->client, GUAC_LOG_DEBUG,
"%s: Access denied - supplied path \"%s\" is relative.",
__func__, path);
return GUAC_RDP_FS_ENOENT;
}
/* Translate access into flags */
if (access & GENERIC_ALL)
flags = O_RDWR;
else if ((access & ( GENERIC_WRITE
| FILE_WRITE_DATA
| FILE_APPEND_DATA))
&& (access & (GENERIC_READ | FILE_READ_DATA)))
flags = O_RDWR;
else if (access & ( GENERIC_WRITE
| FILE_WRITE_DATA
| FILE_APPEND_DATA))
flags = O_WRONLY;
else
flags = O_RDONLY;
/* Normalize path, return no-such-file if invalid */
if (guac_rdp_fs_normalize_path(path, normalized_path)) {
guac_client_log(fs->client, GUAC_LOG_DEBUG,
"%s: Normalization of path \"%s\" failed.", __func__, path);
return GUAC_RDP_FS_ENOENT;
}
guac_client_log(fs->client, GUAC_LOG_DEBUG,
"%s: Normalized path \"%s\" to \"%s\".",
__func__, path, normalized_path);
/* Translate normalized path to real path */
__guac_rdp_fs_translate_path(fs, normalized_path, real_path);
guac_client_log(fs->client, GUAC_LOG_DEBUG,
"%s: Translated path \"%s\" to \"%s\".",
__func__, normalized_path, real_path);
switch (create_disposition) {
/* Create if not exist, fail otherwise */
case FILE_CREATE:
flags |= O_CREAT | O_EXCL;
break;
/* Open file if exists and do not overwrite, fail otherwise */
case FILE_OPEN:
/* No flag necessary - default functionality of open */
break;
/* Open if exists, create otherwise */
case FILE_OPEN_IF:
flags |= O_CREAT;
break;
/* Overwrite if exists, fail otherwise */
case FILE_OVERWRITE:
flags |= O_TRUNC;
break;
/* Overwrite if exists, create otherwise */
case FILE_OVERWRITE_IF:
flags |= O_CREAT | O_TRUNC;
break;
/* Supersede (replace) if exists, otherwise create */
case FILE_SUPERSEDE:
unlink(real_path);
flags |= O_CREAT | O_TRUNC;
break;
/* Unrecognised disposition */
default:
return GUAC_RDP_FS_ENOSYS;
}
/* Create directory first, if necessary */
if ((create_options & FILE_DIRECTORY_FILE) && (flags & O_CREAT)) {
/* Create directory */
if (mkdir(real_path, S_IRWXU)) {
if (errno != EEXIST || (flags & O_EXCL)) {
guac_client_log(fs->client, GUAC_LOG_DEBUG,
"%s: mkdir() failed: %s",
__func__, strerror(errno));
return guac_rdp_fs_get_errorcode(errno);
}
}
/* Unset O_CREAT and O_EXCL as directory must exist before open() */
flags &= ~(O_CREAT | O_EXCL);
}
guac_client_log(fs->client, GUAC_LOG_DEBUG,
"%s: native open: real_path=\"%s\", flags=0x%x",
__func__, real_path, flags);
/* Open file */
fd = open(real_path, flags, S_IRUSR | S_IWUSR);
/* If file open failed as we're trying to write a dir, retry as read-only */
if (fd == -1 && errno == EISDIR) {
flags &= ~(O_WRONLY | O_RDWR);
flags |= O_RDONLY;
fd = open(real_path, flags, S_IRUSR | S_IWUSR);
}
if (fd == -1) {
guac_client_log(fs->client, GUAC_LOG_DEBUG,
"%s: open() failed: %s", __func__, strerror(errno));
return guac_rdp_fs_get_errorcode(errno);
}
/* Get file ID, init file */
file_id = guac_pool_next_int_below_or_die(fs->file_id_pool, GUAC_RDP_FS_MAX_FILES);
file = &(fs->files[file_id]);
file->id = file_id;
file->fd = fd;
file->dir = NULL;
file->dir_pattern[0] = '\0';
file->absolute_path = guac_strdup(normalized_path);
file->real_path = guac_strdup(real_path);
file->bytes_written = 0;
guac_client_log(fs->client, GUAC_LOG_DEBUG,
"%s: Opened \"%s\" as file_id=%i",
__func__, normalized_path, file_id);
/* Attempt to pull file information */
if (fstat(fd, &file_stat) == 0) {
/* Load size and times */
file->size = file_stat.st_size;
file->ctime = WINDOWS_TIME(file_stat.st_ctime);
file->mtime = WINDOWS_TIME(file_stat.st_mtime);
file->atime = WINDOWS_TIME(file_stat.st_atime);
/* Set type */
if (S_ISDIR(file_stat.st_mode))
file->attributes = FILE_ATTRIBUTE_DIRECTORY;
else
file->attributes = FILE_ATTRIBUTE_NORMAL;
}
/* If information cannot be retrieved, fake it */
else {
/* Init information to 0, lacking any alternative */
file->size = 0;
file->ctime = 0;
file->mtime = 0;
file->atime = 0;
file->attributes = FILE_ATTRIBUTE_NORMAL;
}
fs->open_files++;
return file_id;
}