libzypp 17.31.23
IOTools.cc
Go to the documentation of this file.
1/*---------------------------------------------------------------------\
2| ____ _ __ __ ___ |
3| |__ / \ / / . \ . \ |
4| / / \ V /| _/ _/ |
5| / /__ | | | | | | |
6| /_____||_| |_| |_| |
7| |
8\---------------------------------------------------------------------*/
13#include <errno.h>
14#include <fcntl.h>
15#include <iostream>
16#include <glib.h>
17
18#include <zypp-core/AutoDispose.h>
19#include <zypp-core/base/IOTools.h>
20#include <zypp-core/base/LogTools.h>
21#include <zypp-core/zyppng/base/private/linuxhelpers_p.h>
22
23namespace zypp::io {
24
25 BlockingMode setFILEBlocking (FILE * file, bool mode )
26 {
27 if ( !file ) return BlockingMode::FailedToSetMode;
28 return setFDBlocking( ::fileno( file ), mode );
29 }
30
31 BlockingMode setFDBlocking(int fd, bool mode)
32 {
33 if ( fd == -1 )
34 { ERR << strerror( errno ) << std::endl; return BlockingMode::FailedToSetMode; }
35
36 int flags = ::fcntl( fd, F_GETFL );
37
38 if ( flags == -1 )
39 { ERR << strerror( errno ) << std::endl; return BlockingMode::FailedToSetMode; }
40
41 BlockingMode oldMode = ( flags & O_NONBLOCK ) == O_NONBLOCK ? BlockingMode::WasNonBlocking : BlockingMode::WasBlocking;
42 if ( !mode )
43 flags = flags | O_NONBLOCK;
44 else if ( flags & O_NONBLOCK )
45 flags = flags ^ O_NONBLOCK;
46
47 flags = ::fcntl( fd,F_SETFL,flags );
48
49 if ( flags == -1 )
50 { ERR << strerror(errno) << std::endl; return BlockingMode::FailedToSetMode; }
51
52 return oldMode;
53 }
54
55 bool writeAll(int fd, void *buf, size_t size)
56 {
57 char *tmpBuf = ( char *) buf;
58
59 size_t written = 0;
60 while ( written < size ) {
61 const auto res = zyppng::eintrSafeCall( ::write, fd, tmpBuf+written, size-written );
62 if ( res < 0 ) // error
63 return false;
64 written += res;
65 }
66 return true;
67 }
68
69 ReadAllResult readAll (int fd, void *buf, size_t size )
70 {
71 char *tmpBuf = (char *)buf;
72 size_t read = 0;
73 while ( read != size ) {
74 const auto r = zyppng::eintrSafeCall( ::read, fd, tmpBuf+read, size - read );
75 if ( r == 0 )
76 return ReadAllResult::Eof;
77 if ( r < 0 )
79
80 read += r;
81 }
82 return ReadAllResult::Ok;
83 }
84
85 std::pair<ReceiveUpToResult, std::string> receiveUpto(FILE *file, char c, timeout_type timeout, bool failOnUnblockError )
86 {
87 FILE * inputfile = file;
88 if ( !file )
89 return std::make_pair( ReceiveUpToResult::Error, std::string() );
90
91 int inputfileFd = ::fileno( inputfile );
92
93 size_t linebuffer_size = 0;
95
96 const auto prevMode = setFILEBlocking( file, false );
97 if ( prevMode == BlockingMode::FailedToSetMode && failOnUnblockError )
98 return std::make_pair( ReceiveUpToResult::Error, std::string() );
99
100 // reset the blocking mode when we are done
101 zypp::OnScopeExit resetMode([ prevMode, fd = file ]( ){
102 if ( prevMode == BlockingMode::WasBlocking )
103 setFILEBlocking( fd, true );
104 });
105
106 bool haveTimeout = (timeout != no_timeout);
107 int remainingTimeout = static_cast<int>( timeout );
108 zypp::AutoDispose<GTimer *> timer( nullptr );
109 if ( haveTimeout )
110 timer = zypp::AutoDispose<GTimer *>( g_timer_new(), &g_free );
111
112 std::string line;
113 do
114 {
115 /* Watch inputFile to see when it has input. */
116
117 GPollFD fd;
118 fd.fd = inputfileFd;
119 fd.events = G_IO_IN | G_IO_HUP | G_IO_ERR;
120 fd.revents = 0;
121
122 if ( timer )
123 g_timer_start( timer );
124
125 clearerr( inputfile );
126
127 int retval = g_poll( &fd, 1, remainingTimeout );
128 if ( retval == -1 )
129 {
130 if ( errno != EINTR ) {
131 ERR << "select error: " << strerror(errno) << std::endl;
132 return std::make_pair( ReceiveUpToResult::Error, std::string() );
133 }
134 }
135 else if ( retval )
136 {
137 // Data is available now.
138 ssize_t nread = getdelim( &linebuf.value(), &linebuffer_size, c, inputfile );
139 if ( nread == -1 ) {
140 if ( ::feof( inputfile ) )
141 return std::make_pair( ReceiveUpToResult::EndOfFile, std::move(line) );
142 }
143 else
144 {
145 if ( nread > 0 )
146 line += std::string( linebuf, nread );
147
148 if ( ! ::ferror( inputfile ) || ::feof( inputfile ) ) {
149 return std::make_pair( ReceiveUpToResult::Success, std::move(line) ); // complete line
150 }
151 }
152 }
153
154 // we timed out, or were interrupted for some reason
155 // check if we can wait more
156 if ( timer ) {
157 remainingTimeout -= g_timer_elapsed( timer, nullptr ) * 1000;
158 if ( remainingTimeout <= 0 )
159 return std::make_pair( ReceiveUpToResult::Timeout, std::move(line) );
160 }
161 } while ( true );
162 }
163
165 { }
166
167}
Reference counted access to a Tp object calling a custom Dispose function when the last AutoDispose h...
Definition: AutoDispose.h:94
reference value() const
Reference to the Tp object.
Definition: AutoDispose.h:147
virtual ~TimeoutException() noexcept override
Dtor.
Definition: IOTools.cc:164
ReadAllResult
Definition: IOTools.h:43
bool writeAll(int fd, void *buf, size_t size)
Definition: IOTools.cc:55
BlockingMode setFILEBlocking(FILE *file, bool mode)
Enables or disabled non blocking mode on a file descriptor.
Definition: IOTools.cc:25
static const timeout_type no_timeout
Definition: IOTools.h:77
std::pair< ReceiveUpToResult, std::string > receiveUpto(FILE *file, char c, timeout_type timeout, bool failOnUnblockError)
Definition: IOTools.cc:85
BlockingMode
Definition: IOTools.h:22
@ WasBlocking
FD was blocking before.
@ FailedToSetMode
Failed to block or unblock the fd.
@ WasNonBlocking
FD was non blocking before.
@ Timeout
Definition: IOTools.h:71
@ Success
Definition: IOTools.h:70
@ Error
Definition: IOTools.h:73
@ EndOfFile
Definition: IOTools.h:72
ReadAllResult readAll(int fd, void *buf, size_t size)
Definition: IOTools.cc:69
BlockingMode setFDBlocking(int fd, bool mode)
Definition: IOTools.cc:31
size_t timeout_type
Definition: IOTools.h:76
#define ERR
Definition: Logger.h:98