RESTinio
sendfile_defs_default.hpp
Go to the documentation of this file.
1 /*
2  restinio
3 */
4 
5 /*!
6  Sendfile routine definitions (default implementation via <cstdio>).
7 
8  @since v.0.4.3
9 */
10 
11 #pragma once
12 
13 #include <cstdio>
14 #include <cerrno>
15 
16 // for fixing #199 (https://github.com/Stiffstream/restinio/issues/199)
17 // fopen_s seems to be defined in the global namespace.
18 #include <stdio.h>
19 
20 namespace restinio
21 {
22 
23 /** @name Aliases for sendfile operation.
24  */
25 ///@{
29 ///@}
30 
31 
32 /** @name File operations.
33  * @brief A minimal set of file operations.
34  *
35  * Incapsulates the details *cstdio* API for a set of file operations neccessary
36  * for sendfile_t class implementation.
37  */
38 ///@{
39 
40 //! Get file descriptor which stands for null.
41 [[nodiscard]]
42 constexpr file_descriptor_t null_file_descriptor(){ return nullptr; }
43 
44 //FIXME: document platform-specific behavior.
45 //! Open file.
46 [[nodiscard]]
47 inline file_descriptor_t
48 open_file( const char * file_path )
49 {
50 //NOTE: fopen_s is only used for VC++ compiler.
51 #if defined(_MSC_VER)
52  file_descriptor_t file_descriptor{};
53  const auto result = fopen_s( &file_descriptor, file_path, "rb" );
54 
55  if( result )
56  {
57  const auto err_code = errno;
58  throw exception_t{
59  fmt::format(
60  RESTINIO_FMT_FORMAT_STRING( "fopen_s('{}') failed; errno={}" ),
61  file_path, err_code )
62  };
63  }
64 
65  return file_descriptor;
66 #else
67  file_descriptor_t file_descriptor = std::fopen( file_path, "rb" );
68 
69  if( null_file_descriptor() == file_descriptor )
70  {
71  throw exception_t{
72  fmt::format(
73  RESTINIO_FMT_FORMAT_STRING( "std::fopen failed: '{}'" ),
74  file_path )
75  };
76  }
77 
78  return file_descriptor;
79 #endif
80 }
81 
82 //FIXME: document platform-specific behavior!
83 /*!
84  * @brief Helper function that accepts std::filesystem::path.
85  *
86  * @since v.0.7.1
87  */
88 [[nodiscard]]
89 inline file_descriptor_t
91 {
92 //NOTE: _wfopen_s is only used for VC++ compiler.
93 #if defined(_MSC_VER)
94  file_descriptor_t file_descriptor{};
95  const auto result = _wfopen_s( &file_descriptor, file_path.c_str(), L"rb" );
96 
97  if( result )
98  {
99  const auto err_code = errno;
100  throw exception_t{
101  fmt::format(
102  RESTINIO_FMT_FORMAT_STRING( "_wfopen_s failed; errno={}" ),
103  err_code )
104  };
105  }
106 
107  return file_descriptor;
108 #else
109  // Just delegate to ordinary open_file assuming that file_path is in UTF-8.
110  return open_file( file_path.c_str() );
111 #endif
112 }
113 
114 //! Get file size.
115 template < typename META >
116 [[nodiscard]]
117 META
118 get_file_meta( file_descriptor_t fd )
119 {
120  file_size_t fsize = 0;
121 
122  if( null_file_descriptor() != fd )
123  {
124  // Obtain file size:
125  if( 0 == std::fseek( fd , 0 , SEEK_END ) )
126  {
127  const auto end_pos = std::ftell( fd );
128 
129  if( -1 != end_pos )
130  {
131  fsize = static_cast< file_size_t >( end_pos );
132  std::rewind( fd );
133  }
134  else
135  {
136  throw exception_t{ "std::ftell failed" };
137  }
138  }
139  else
140  {
141  throw exception_t{ "std::fseek failed" };
142  }
143  }
144 
145  // No way to get last modification,
146  // Use current time instead.
147  return META{ fsize, std::chrono::system_clock::now() };
148 }
149 
150 //! Close file by its descriptor.
151 inline void
152 close_file( file_descriptor_t fd )
153 {
154  std::fclose( fd );
155 }
156 ///@}
157 
158 } /* namespace restinio */
constexpr file_descriptor_t null_file_descriptor()
Get file descriptor which stands for null.
std::enable_if< std::is_same< Parameter_Container, query_string_params_t >::value||std::is_same< Parameter_Container, router::route_params_t >::value, std::optional< Value_Type > >::type opt_value(const Parameter_Container &params, string_view_t key)
Gets the value of a parameter specified by key wrapped in std::optional<Value_Type> if parameter exis...
Definition: value_or.hpp:64
file_descriptor_t open_file(const std::filesystem::path &file_path)
Helper function that accepts std::filesystem::path.
void close_file(file_descriptor_t fd)
Close file by its descriptor.
META get_file_meta(file_descriptor_t fd)
Get file size.
file_descriptor_t open_file(const char *file_path)
Open file.