int get_fd_from_cache(FDcache fd_cache, const char path[], off_t* pst_size) { struct pathfd_t* p; int fd; struct stat stat_buf; if (fd_cache == NULL) return -1; if (strlen(path) >= FD_CACHE_MAX_PATH_LEN - 1) return -1; for (p = fd_cache->a; p != fd_cache->aend; ++p) { if (!strcmp(p->path, path)) { *pst_size = p->st_size; return p->fd; } } if ((fd = add_fd_to_cache(fd_cache, path, pst_size)) == -1) { if ((fd = open(fd_cache->dir_prefix_buf, O_RDONLY|O_NONBLOCK)) == -1) return -1; if (fstat(fd, &stat_buf) == -1) { logfl(fd_cache->logger, "fstat error: %s", strerror(errno)); return -1; } *pst_size = stat_buf.st_size; return fd; } else { return fd; } }
/*********************************************************************** * server_get_unix_fd * * The returned unix_fd should be closed iff needs_close is non-zero. */ int server_get_unix_fd( HANDLE handle, unsigned int wanted_access, int *unix_fd, int *needs_close, enum server_fd_type *type, unsigned int *options ) { sigset_t sigset; obj_handle_t fd_handle; int ret = 0, fd; unsigned int access = 0; *unix_fd = -1; *needs_close = 0; wanted_access &= FILE_READ_DATA | FILE_WRITE_DATA; server_enter_uninterrupted_section( &fd_cache_section, &sigset ); fd = get_cached_fd( handle, type, &access, options ); if (fd != -1) goto done; SERVER_START_REQ( get_handle_fd ) { req->handle = wine_server_obj_handle( handle ); if (!(ret = wine_server_call( req ))) { if (type) *type = reply->type; if (options) *options = reply->options; access = reply->access; if ((fd = receive_fd( &fd_handle )) != -1) { assert( wine_server_ptr_handle(fd_handle) == handle ); *needs_close = (reply->removable || !add_fd_to_cache( handle, fd, reply->type, reply->access, reply->options )); } else ret = STATUS_TOO_MANY_OPENED_FILES; } } SERVER_END_REQ; done: server_leave_uninterrupted_section( &fd_cache_section, &sigset ); if (!ret && ((access & wanted_access) != wanted_access)) { ret = STATUS_ACCESS_DENIED; if (*needs_close) close( fd ); } if (!ret) *unix_fd = fd; return ret; }