RESTinio
Loading...
Searching...
No Matches
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
20namespace restinio
21{
22
23/** @name Aliases for sendfile operation.
24 */
25///@{
26using file_descriptor_t = std::FILE*;
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]]
42constexpr file_descriptor_t null_file_descriptor(){ return nullptr; }
43
44//FIXME: document platform-specific behavior.
45//! Open file.
46[[nodiscard]]
48open_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]]
90open_file( const std::filesystem::path & file_path )
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.
115template < typename META >
116[[nodiscard]]
117META
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.
151inline void
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.
void close_file(file_descriptor_t fd)
Close file by its descriptor.
file_descriptor_t open_file(const char *file_path)
Open file.
std::FILE * file_descriptor_t
file_descriptor_t open_file(const std::filesystem::path &file_path)
Helper function that accepts std::filesystem::path.
META get_file_meta(file_descriptor_t fd)
Get file size.