GNU libmicrohttpd  0.9.63
response_from_fd.c
Go to the documentation of this file.
1 /*
2  This file is part of libmicrohttpd
3  Copyright (C) 2007-2018 Daniel Pittman and Christian Grothoff
4 
5  This library is free software; you can redistribute it and/or
6  modify it under the terms of the GNU Lesser General Public
7  License as published by the Free Software Foundation; either
8  version 2.1 of the License, or (at your option) any later version.
9 
10  This library is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  Lesser General Public License for more details.
14 
15  You should have received a copy of the GNU Lesser General Public
16  License along with this library; if not, write to the Free Software
17  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19 
27 #include "internal.h"
28 
29 
40 static ssize_t
41 file_reader (void *cls,
42  uint64_t pos,
43  char *buf,
44  size_t max)
45 {
46  struct MHD_Response *response = cls;
47 #if !defined(_WIN32) || defined(__CYGWIN__)
48  ssize_t n;
49 #else /* _WIN32 && !__CYGWIN__ */
50  const HANDLE fh = (HANDLE) _get_osfhandle (response->fd);
51 #endif /* _WIN32 && !__CYGWIN__ */
52  const int64_t offset64 = (int64_t)(pos + response->fd_off);
53 
54  if (offset64 < 0)
55  return MHD_CONTENT_READER_END_WITH_ERROR; /* seek to required position is not possible */
56 
57 #if !defined(_WIN32) || defined(__CYGWIN__)
58  if (max > SSIZE_MAX)
59  max = SSIZE_MAX; /* Clamp to maximum return value. */
60 
61 #if defined(HAVE_PREAD64)
62  n = pread64 (response->fd,
63  buf,
64  max,
65  offset64);
66 #elif defined(HAVE_PREAD)
67  if ( (sizeof(off_t) < sizeof (uint64_t)) &&
68  (offset64 > (uint64_t)INT32_MAX) )
69  return MHD_CONTENT_READER_END_WITH_ERROR; /* Read at required position is not possible. */
70 
71  n = pread (response->fd,
72  buf,
73  max,
74  (off_t) offset64);
75 #else /* ! HAVE_PREAD */
76 #if defined(HAVE_LSEEK64)
77  if (lseek64 (response->fd,
78  offset64,
79  SEEK_SET) != offset64)
80  return MHD_CONTENT_READER_END_WITH_ERROR; /* can't seek to required position */
81 #else /* ! HAVE_LSEEK64 */
82  if ( (sizeof(off_t) < sizeof (uint64_t)) &&
83  (offset64 > (uint64_t)INT32_MAX) )
84  return MHD_CONTENT_READER_END_WITH_ERROR; /* seek to required position is not possible */
85 
86  if (lseek (response->fd,
87  (off_t) offset64,
88  SEEK_SET) != (off_t) offset64)
89  return MHD_CONTENT_READER_END_WITH_ERROR; /* can't seek to required position */
90 #endif /* ! HAVE_LSEEK64 */
91  n = read (response->fd,
92  buf,
93  max);
94 
95 #endif /* ! HAVE_PREAD */
96  if (0 == n)
98  if (n < 0)
100  return n;
101 #else /* _WIN32 && !__CYGWIN__ */
102  if (INVALID_HANDLE_VALUE == fh)
103  return MHD_CONTENT_READER_END_WITH_ERROR; /* Value of 'response->fd' is not valid. */
104  else
105  {
106  OVERLAPPED f_ol = {0, 0, {{0, 0}}, 0}; /* Initialize to zero. */
107  ULARGE_INTEGER pos_uli;
108  DWORD toRead = (max > INT32_MAX) ? INT32_MAX : (DWORD) max;
109  DWORD resRead;
110 
111  pos_uli.QuadPart = (uint64_t) offset64; /* Simple transformation 64bit -> 2x32bit. */
112  f_ol.Offset = pos_uli.LowPart;
113  f_ol.OffsetHigh = pos_uli.HighPart;
114  if (! ReadFile (fh,
115  (void*)buf,
116  toRead,
117  &resRead,
118  &f_ol))
119  return MHD_CONTENT_READER_END_WITH_ERROR; /* Read error. */
120  if (0 == resRead)
122  return (ssize_t) resRead;
123  }
124 #endif /* _WIN32 && !__CYGWIN__ */
125 }
126 
127 
134 static void
135 free_callback (void *cls)
136 {
137  struct MHD_Response *response = cls;
138 
139  (void) close (response->fd);
140  response->fd = -1;
141 }
142 
143 
162 struct MHD_Response *
163 MHD_response_from_fd (enum MHD_HTTP_StatusCode sc,
164  int fd,
165  uint64_t offset,
166  uint64_t size)
167 {
168  struct MHD_Response *response;
169 
170  mhd_assert (-1 != fd);
171 #if !defined(HAVE___LSEEKI64) && !defined(HAVE_LSEEK64)
172  if ( (sizeof (uint64_t) > sizeof (off_t)) &&
173  ( (size > (uint64_t)INT32_MAX) ||
174  (offset > (uint64_t)INT32_MAX) ||
175  ((size + offset) >= (uint64_t)INT32_MAX) ) )
176  return NULL;
177 #endif
178  if ( ((int64_t) size < 0) ||
179  ((int64_t) offset < 0) ||
180  ((int64_t) (size + offset) < 0) )
181  return NULL;
182 
183  response = MHD_response_from_callback (sc,
184  size,
186  &file_reader,
187  NULL,
188  &free_callback);
189  if (NULL == response)
190  return NULL;
191  response->fd = fd;
192  response->fd_off = offset;
193  response->crc_cls = response;
194  return response;
195 }
196 
197 /* end of response_from_fd.c */
198 
uint64_t fd_off
Definition: internal.h:1650
static void free_callback(void *cls)
#define MHD_FD_BLOCK_SIZE
Definition: mhd_limits.h:150
internal shared structures
void * crc_cls
Definition: internal.h:1591
int fd
Definition: microhttpd.h:2837
struct MHD_Response * MHD_response_from_fd(enum MHD_HTTP_StatusCode sc, int fd, uint64_t offset, uint64_t size)
#define MHD_CONTENT_READER_END_OF_STREAM
Definition: microhttpd.h:160
#define NULL
Definition: reason_phrase.c:30
#define INT32_MAX
Definition: mhd_limits.h:65
static ssize_t file_reader(void *cls, uint64_t pos, char *buf, size_t max)
int off_t offset
Definition: microhttpd.h:2837
#define mhd_assert(CHK)
Definition: mhd_assert.h:39
#define MHD_CONTENT_READER_END_WITH_ERROR
Definition: microhttpd.h:161
struct MHD_Response * MHD_response_from_callback(enum MHD_HTTP_StatusCode sc, uint64_t size, size_t block_size, MHD_ContentReaderCallback crc, void *crc_cls, MHD_ContentReaderFreeCallback crfc)