mirror of
https://github.com/RetroShare/RetroShare.git
synced 2025-01-15 09:27:09 -05:00
commit
f14573bf4e
@ -347,6 +347,7 @@ list(
|
||||
util/rsurl.cc
|
||||
util/folderiterator.cc
|
||||
util/rsdir.cc
|
||||
util/rsfile.cc
|
||||
util/dnsresolver.cc
|
||||
util/extaddrfinder.cc
|
||||
util/rsdebug.cc
|
||||
|
@ -487,6 +487,7 @@ HEADERS += util/folderiterator.h \
|
||||
util/rsmemory.h \
|
||||
util/smallobject.h \
|
||||
util/rsdir.h \
|
||||
util/rsfile.h \
|
||||
util/argstream.h \
|
||||
util/rsdiscspace.h \
|
||||
util/rsnet.h \
|
||||
@ -641,6 +642,7 @@ SOURCES += util/folderiterator.cc \
|
||||
util/rsexpr.cc \
|
||||
util/smallobject.cc \
|
||||
util/rsdir.cc \
|
||||
util/rsfile.cc \
|
||||
util/rsdiscspace.cc \
|
||||
util/rsnet.cc \
|
||||
util/rsnet_ss.cc \
|
||||
|
@ -21,10 +21,11 @@
|
||||
******************************************************************************/
|
||||
|
||||
#include "util/rsprint.h"
|
||||
#include "util/rsfile.h"
|
||||
#include "pqi/pqifdbin.h"
|
||||
|
||||
RsFdBinInterface::RsFdBinInterface(int file_descriptor)
|
||||
: mCLintConnt(file_descriptor),mIsActive(false)
|
||||
RsFdBinInterface::RsFdBinInterface(int file_descriptor, bool is_socket)
|
||||
: mCLintConnt(file_descriptor),mIsSocket(is_socket),mIsActive(false)
|
||||
{
|
||||
mTotalReadBytes=0;
|
||||
mTotalInBufferBytes=0;
|
||||
@ -53,8 +54,11 @@ void RsFdBinInterface::setSocket(int s)
|
||||
|
||||
#else
|
||||
// On windows, there is no way to determine whether a socket is blocking or not, so we set it to non blocking whatsoever.
|
||||
unsigned long int on = 1;
|
||||
ioctlsocket(s, FIONBIO, &on);
|
||||
if (mIsSocket) {
|
||||
unix_fcntl_nonblock(s);
|
||||
} else {
|
||||
RsFileUtil::set_fd_nonblock(s);
|
||||
}
|
||||
#endif
|
||||
|
||||
mCLintConnt = s;
|
||||
@ -82,8 +86,15 @@ int RsFdBinInterface::read_pending()
|
||||
char inBuffer[1025];
|
||||
memset(inBuffer,0,1025);
|
||||
|
||||
ssize_t readbytes = read(mCLintConnt, inBuffer, sizeof(inBuffer)); // Needs read instead of recv which is only for sockets.
|
||||
// Sockets should be set to non blocking by the client process.
|
||||
ssize_t readbytes;
|
||||
#if WINDOWS_SYS
|
||||
if (mIsSocket)
|
||||
// Windows needs recv for sockets
|
||||
readbytes = recv(mCLintConnt, inBuffer, sizeof(inBuffer), 0);
|
||||
else
|
||||
#endif
|
||||
readbytes = read(mCLintConnt, inBuffer, sizeof(inBuffer)); // Needs read instead of recv which is only for sockets.
|
||||
// Sockets should be set to non blocking by the client process.
|
||||
|
||||
if(readbytes == 0)
|
||||
{
|
||||
@ -95,7 +106,11 @@ int RsFdBinInterface::read_pending()
|
||||
}
|
||||
if(readbytes < 0)
|
||||
{
|
||||
if(errno != EWOULDBLOCK && errno != EAGAIN)
|
||||
if(errno != 0 && errno != EWOULDBLOCK && errno != EAGAIN)
|
||||
#ifdef WINDOWS_SYS
|
||||
// A non blocking read to file descriptor gets ERROR_NO_DATA for empty data
|
||||
if (mIsSocket == true || GetLastError() != ERROR_NO_DATA)
|
||||
#endif
|
||||
RsErr() << "read() failed. Errno=" << errno ;
|
||||
|
||||
return mTotalInBufferBytes;
|
||||
@ -138,7 +153,14 @@ int RsFdBinInterface::write_pending()
|
||||
return mTotalOutBufferBytes;
|
||||
|
||||
auto& p = out_buffer.front();
|
||||
int written = write(mCLintConnt, p.first, p.second);
|
||||
int written;
|
||||
#if WINDOWS_SYS
|
||||
if (mIsSocket)
|
||||
// Windows needs send for sockets
|
||||
written = send(mCLintConnt, (char*) p.first, p.second, 0);
|
||||
else
|
||||
#endif
|
||||
written = write(mCLintConnt, p.first, p.second);
|
||||
|
||||
if(written < 0)
|
||||
{
|
||||
|
@ -25,7 +25,7 @@
|
||||
class RsFdBinInterface: public BinInterface
|
||||
{
|
||||
public:
|
||||
RsFdBinInterface(int file_descriptor);
|
||||
RsFdBinInterface(int file_descriptor, bool is_socket);
|
||||
~RsFdBinInterface();
|
||||
|
||||
// Implements BinInterface methods
|
||||
@ -70,6 +70,7 @@ private:
|
||||
int write_pending();
|
||||
|
||||
int mCLintConnt;
|
||||
bool mIsSocket;
|
||||
bool mIsActive;
|
||||
uint32_t mTotalReadBytes;
|
||||
uint32_t mTotalInBufferBytes;
|
||||
|
@ -18,12 +18,12 @@
|
||||
#include "rstcpsocket.h"
|
||||
|
||||
RsTcpSocket::RsTcpSocket(const std::string& tcp_address,uint16_t tcp_port)
|
||||
:RsFdBinInterface(0),mState(DISCONNECTED),mConnectAddress(tcp_address),mConnectPort(tcp_port),mSocket(0)
|
||||
:RsFdBinInterface(0, true),mState(DISCONNECTED),mConnectAddress(tcp_address),mConnectPort(tcp_port),mSocket(0)
|
||||
{
|
||||
}
|
||||
|
||||
RsTcpSocket::RsTcpSocket()
|
||||
:RsFdBinInterface(0),mState(DISCONNECTED),mConnectAddress("0.0.0.0"),mConnectPort(0),mSocket(0)
|
||||
:RsFdBinInterface(0, true),mState(DISCONNECTED),mConnectAddress("0.0.0.0"),mConnectPort(0),mSocket(0)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -33,6 +33,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include <string>
|
||||
|
||||
/* Represents an asynchronous operation for reporting status
|
||||
*
|
||||
|
@ -39,7 +39,7 @@ ByteArray quotedString(const ByteArray &string)
|
||||
|
||||
out.push_back('"');
|
||||
|
||||
for (uint i = 0; i < string.size(); ++i)
|
||||
for (ByteArray::size_type i = 0; i < string.size(); ++i)
|
||||
{
|
||||
switch (string[i])
|
||||
{
|
||||
@ -67,7 +67,7 @@ ByteArray unquotedString(const ByteArray& string)
|
||||
ByteArray out;
|
||||
out.reserve(string.size() - 2);
|
||||
|
||||
for (uint i = 1; i < string.size(); ++i)
|
||||
for (ByteArray::size_type i = 1; i < string.size(); ++i)
|
||||
{
|
||||
switch (string[i])
|
||||
{
|
||||
@ -89,9 +89,9 @@ std::list<ByteArray> splitQuotedStrings(const ByteArray &input, char separator)
|
||||
{
|
||||
std::list<ByteArray> out;
|
||||
bool inquote = false;
|
||||
uint start = 0;
|
||||
ByteArray::size_type start = 0;
|
||||
|
||||
for (uint i = 0; i < input.size(); ++i)
|
||||
for (ByteArray::size_type i = 0; i < input.size(); ++i)
|
||||
{
|
||||
switch (input[i])
|
||||
{
|
||||
|
@ -68,6 +68,11 @@ TorControl::TorControl()
|
||||
: mControlPort(0),mSocksPort(0),mStatus(NotConnected), mTorStatus(TorOffline),mHasOwnership(false)
|
||||
{
|
||||
mSocket = new TorControlSocket(this);
|
||||
mControlPort = 0;
|
||||
mSocksPort = 0;
|
||||
mStatus = NotConnected;
|
||||
mTorStatus = TorUnknown;
|
||||
mHasOwnership = false;
|
||||
}
|
||||
|
||||
static RsTorConnectivityStatus torConnectivityStatus(Tor::TorControl::Status t)
|
||||
|
@ -623,7 +623,7 @@ std::string TorManagerPrivate::torExecutablePath() const
|
||||
return path;
|
||||
#endif
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
#ifdef WINDOWS_SYS
|
||||
std::string filename("/tor/tor.exe");
|
||||
#else
|
||||
std::string filename("/tor");
|
||||
|
@ -35,11 +35,19 @@
|
||||
#include <stdio.h>
|
||||
|
||||
#include "util/rsdir.h"
|
||||
#include "util/rsfile.h"
|
||||
#include "pqi/pqifdbin.h"
|
||||
|
||||
#include "TorProcess.h"
|
||||
#include "CryptoKey.h"
|
||||
|
||||
#ifdef WINDOWS_SYS
|
||||
#include "util/rsstring.h"
|
||||
|
||||
#include <fcntl.h>
|
||||
#define pipe(fds) _pipe(fds, 1024, _O_BINARY)
|
||||
#endif
|
||||
|
||||
using namespace Tor;
|
||||
|
||||
static const int INTERVAL_BETWEEN_CONTROL_PORT_READ_TRIES = 5; // try every 5 secs.
|
||||
@ -110,7 +118,7 @@ std::string TorProcess::errorMessage() const
|
||||
// Does a popen, but dup all file descriptors (STDIN STDOUT and STDERR) to the
|
||||
// FDs supplied by the parent process
|
||||
|
||||
int popen3(int fd[3],const char **const cmd,pid_t& pid)
|
||||
int popen3(int fd[3],const std::vector<std::string>& args,TorProcessHandle& pid)
|
||||
{
|
||||
RsErr() << "Launching Tor in background..." ;
|
||||
|
||||
@ -123,42 +131,120 @@ int popen3(int fd[3],const char **const cmd,pid_t& pid)
|
||||
for(int i=0; i<3; i++)
|
||||
if(pipe(p[i]))
|
||||
goto error;
|
||||
// and fork
|
||||
pid = fork();
|
||||
if(-1 == pid)
|
||||
goto error;
|
||||
// in the parent?
|
||||
if(pid)
|
||||
{
|
||||
// parent
|
||||
fd[STDIN_FILENO] = p[STDIN_FILENO][1];
|
||||
close(p[STDIN_FILENO][0]);
|
||||
fd[STDOUT_FILENO] = p[STDOUT_FILENO][0];
|
||||
close(p[STDOUT_FILENO][1]);
|
||||
fd[STDERR_FILENO] = p[STDERR_FILENO][0];
|
||||
close(p[STDERR_FILENO][1]);
|
||||
// success
|
||||
return 0;
|
||||
|
||||
#ifdef WINDOWS_SYS
|
||||
// Set up members of the PROCESS_INFORMATION structure.
|
||||
PROCESS_INFORMATION pi;
|
||||
ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
|
||||
|
||||
// Set up members of the STARTUPINFO structure.
|
||||
// This structure specifies the STDIN and STDOUT handles for redirection.
|
||||
STARTUPINFO si;
|
||||
ZeroMemory(&si, sizeof(STARTUPINFO));
|
||||
si.cb = sizeof(STARTUPINFO);
|
||||
si.hStdInput = (HANDLE) _get_osfhandle(p[STDIN_FILENO][0]);
|
||||
si.hStdOutput = (HANDLE) _get_osfhandle(p[STDOUT_FILENO][1]);
|
||||
si.hStdError = (HANDLE) _get_osfhandle(p[STDERR_FILENO][1]);
|
||||
si.dwFlags |= STARTF_USESTDHANDLES;
|
||||
|
||||
if (si.hStdInput != INVALID_HANDLE_VALUE &&
|
||||
si.hStdOutput != INVALID_HANDLE_VALUE &&
|
||||
si.hStdError != INVALID_HANDLE_VALUE) {
|
||||
// build commandline
|
||||
std::string cmd;
|
||||
for (std::vector<std::string>::const_iterator it = args.begin(); it != args.end(); ++it) {
|
||||
if (it != args.begin()) {
|
||||
cmd += " ";
|
||||
}
|
||||
cmd += *it;
|
||||
}
|
||||
|
||||
std::wstring wcmd;
|
||||
if (!librs::util::ConvertUtf8ToUtf16(cmd, wcmd)) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
WINBOOL success = CreateProcess(nullptr,
|
||||
(LPWSTR) wcmd.c_str(), // command line
|
||||
nullptr, // process security attributes
|
||||
nullptr, // primary thread security attributes
|
||||
TRUE, // handles are inherited
|
||||
0, // creation flags
|
||||
nullptr, // use parent's environment
|
||||
nullptr, // use parent's current directory
|
||||
&si, // STARTUPINFO pointer
|
||||
&pi); // receives PROCESS_INFORMATION
|
||||
|
||||
if (success) {
|
||||
pid = pi.hProcess;
|
||||
|
||||
CloseHandle(pi.hThread);
|
||||
|
||||
fd[STDIN_FILENO] = p[STDIN_FILENO][1];
|
||||
close(p[STDIN_FILENO][0]);
|
||||
fd[STDOUT_FILENO] = p[STDOUT_FILENO][0];
|
||||
close(p[STDOUT_FILENO][1]);
|
||||
fd[STDERR_FILENO] = p[STDERR_FILENO][0];
|
||||
close(p[STDERR_FILENO][1]);
|
||||
|
||||
// success
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
// fall through error
|
||||
|
||||
#else
|
||||
{
|
||||
RsErr() << "Launching sub-process..." ;
|
||||
// child
|
||||
dup2(p[STDIN_FILENO][0],STDIN_FILENO);
|
||||
close(p[STDIN_FILENO][1]);
|
||||
dup2(p[STDOUT_FILENO][1],STDOUT_FILENO);
|
||||
close(p[STDOUT_FILENO][0]);
|
||||
dup2(p[STDERR_FILENO][1],STDERR_FILENO);
|
||||
close(p[STDERR_FILENO][0]);
|
||||
const char *arguments[args.size()+1];
|
||||
int n=0;
|
||||
|
||||
// here we try and run it
|
||||
// We first pushed everything into a vector of strings to save the pointers obtained from string returning methods
|
||||
// by the time the process is launched.
|
||||
|
||||
execv(*cmd,const_cast<char*const*>(cmd));
|
||||
for(uint32_t i=0;i<args.size();++i)
|
||||
arguments[n++]= args[i].data();
|
||||
|
||||
// if we are there, then we failed to launch our program
|
||||
perror("Could not launch");
|
||||
fprintf(stderr," \"%s\"\n",*cmd);
|
||||
arguments[n] = nullptr;
|
||||
|
||||
// and fork
|
||||
pid = fork();
|
||||
if(-1 == pid)
|
||||
goto error;
|
||||
// in the parent?
|
||||
if(pid)
|
||||
{
|
||||
// parent
|
||||
fd[STDIN_FILENO] = p[STDIN_FILENO][1];
|
||||
close(p[STDIN_FILENO][0]);
|
||||
fd[STDOUT_FILENO] = p[STDOUT_FILENO][0];
|
||||
close(p[STDOUT_FILENO][1]);
|
||||
fd[STDERR_FILENO] = p[STDERR_FILENO][0];
|
||||
close(p[STDERR_FILENO][1]);
|
||||
// success
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
RsErr() << "Launching sub-process..." ;
|
||||
// child
|
||||
dup2(p[STDIN_FILENO][0],STDIN_FILENO);
|
||||
close(p[STDIN_FILENO][1]);
|
||||
dup2(p[STDOUT_FILENO][1],STDOUT_FILENO);
|
||||
close(p[STDOUT_FILENO][0]);
|
||||
dup2(p[STDERR_FILENO][1],STDERR_FILENO);
|
||||
close(p[STDERR_FILENO][0]);
|
||||
|
||||
// here we try and run it
|
||||
|
||||
execv(*arguments,const_cast<char*const*>(arguments));
|
||||
|
||||
// if we are there, then we failed to launch our program
|
||||
perror("Could not launch");
|
||||
fprintf(stderr," \"%s\"\n",*arguments);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
error:
|
||||
e = errno;
|
||||
@ -250,31 +336,20 @@ void TorProcess::start()
|
||||
for(auto s:mExtraSettings)
|
||||
args.push_back(s);
|
||||
|
||||
const char *arguments[args.size()+1];
|
||||
int n=0;
|
||||
|
||||
// We first pushed everything into a vector of strings to save the pointers obtained from string returning methods
|
||||
// by the time the process is launched.
|
||||
|
||||
for(uint32_t i=0;i<args.size();++i)
|
||||
arguments[n++]= args[i].data();
|
||||
|
||||
arguments[n] = nullptr;
|
||||
|
||||
int fd[3]; // File descriptors array
|
||||
|
||||
if(popen3(fd,arguments,mTorProcessId))
|
||||
if(popen3(fd,args,mTorProcessId))
|
||||
{
|
||||
RsErr() << "Could not start Tor process. errno=" << errno ;
|
||||
mState = Failed;
|
||||
return; // stop the control thread
|
||||
}
|
||||
|
||||
unix_fcntl_nonblock(fd[STDOUT_FILENO]);
|
||||
unix_fcntl_nonblock(fd[STDERR_FILENO]);
|
||||
RsFileUtil::set_fd_nonblock(fd[STDOUT_FILENO]);
|
||||
RsFileUtil::set_fd_nonblock(fd[STDERR_FILENO]);
|
||||
|
||||
mStdOutFD = new RsFdBinInterface(fd[STDOUT_FILENO]);
|
||||
mStdErrFD = new RsFdBinInterface(fd[STDERR_FILENO]);
|
||||
mStdOutFD = new RsFdBinInterface(fd[STDOUT_FILENO], false);
|
||||
mStdErrFD = new RsFdBinInterface(fd[STDERR_FILENO], false);
|
||||
}
|
||||
|
||||
void TorProcess::tick()
|
||||
@ -321,7 +396,11 @@ void TorProcess::stop()
|
||||
while(mState == Starting)
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
|
||||
#ifdef WINDOWS_SYS
|
||||
TerminateProcess (mTorProcessId, 0);
|
||||
#else
|
||||
kill(mTorProcessId,SIGTERM);
|
||||
#endif
|
||||
|
||||
RsInfo() << "Tor process has been normally terminated. Exiting.";
|
||||
|
||||
@ -408,10 +487,12 @@ bool TorProcess::tryReadControlPort()
|
||||
char *line = nullptr;
|
||||
size_t tmp_buffsize = 0;
|
||||
|
||||
size_t size = getline(&line,&tmp_buffsize,file);
|
||||
size_t size = RsFileUtil::rs_getline(&line,&tmp_buffsize,file);
|
||||
ByteArray data = ByteArray((unsigned char*)line,size).trimmed();
|
||||
free(line);
|
||||
|
||||
fclose(file);
|
||||
|
||||
int p;
|
||||
if (data.startsWith("PORT=") && (p = data.lastIndexOf(':')) > 0) {
|
||||
mControlHost = data.mid(5, p - 5).toString();
|
||||
|
@ -38,6 +38,12 @@
|
||||
|
||||
class RsFdBinInterface ;
|
||||
|
||||
#ifdef WINDOWS_SYS
|
||||
#define TorProcessHandle HANDLE
|
||||
#else
|
||||
#define TorProcessHandle pid_t
|
||||
#endif
|
||||
|
||||
namespace Tor
|
||||
{
|
||||
|
||||
@ -114,7 +120,7 @@ private:
|
||||
std::string controlPortFilePath() const;
|
||||
bool ensureFilesExist();
|
||||
|
||||
pid_t mTorProcessId;
|
||||
TorProcessHandle mTorProcessId;
|
||||
time_t mLastTryReadControlPort ;
|
||||
int mControlPortReadNbTries ;
|
||||
|
||||
|
107
libretroshare/src/util/rsfile.cc
Normal file
107
libretroshare/src/util/rsfile.cc
Normal file
@ -0,0 +1,107 @@
|
||||
/*******************************************************************************
|
||||
* libretroshare/src/util: rsfile.cc *
|
||||
* *
|
||||
* libretroshare: retroshare core library *
|
||||
* *
|
||||
* Copyright (C) 2021 Retroshare Team <retroshare.project@gmail.com> *
|
||||
* *
|
||||
* This program is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License as *
|
||||
* published by the Free Software Foundation, either version 3 of the *
|
||||
* License, or (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public License *
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
*******************************************************************************/
|
||||
|
||||
#include "util/rsfile.h"
|
||||
|
||||
#ifdef WINDOWS_SYS
|
||||
#include <wtypes.h>
|
||||
#include <io.h>
|
||||
#include <namedpipeapi.h>
|
||||
#include <errno.h>
|
||||
#else
|
||||
#include <fcntl.h>
|
||||
#endif
|
||||
|
||||
int RsFileUtil::set_fd_nonblock(int fd)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
/******************* OS SPECIFIC PART ******************/
|
||||
#ifdef WINDOWS_SYS
|
||||
DWORD mode = PIPE_NOWAIT;
|
||||
WINBOOL result = SetNamedPipeHandleState((HANDLE) _get_osfhandle(fd), &mode, nullptr, nullptr);
|
||||
|
||||
if (!result) {
|
||||
ret = -1;
|
||||
}
|
||||
#else // ie UNIX
|
||||
int flags = fcntl(fd, F_GETFL);
|
||||
ret = fcntl(fd, F_SETFL, flags | O_NONBLOCK);
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
ssize_t RsFileUtil::rs_getline(char **lineptr, size_t *n, FILE *stream)
|
||||
{
|
||||
/******************* OS SPECIFIC PART ******************/
|
||||
#ifdef WINDOWS_SYS
|
||||
if (lineptr == nullptr || n == nullptr || stream == nullptr) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (*lineptr == nullptr || *n < 1) {
|
||||
*n = BUFSIZ;
|
||||
*lineptr = (char*) malloc(*n);
|
||||
if (*lineptr == nullptr) {
|
||||
*n = 0;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
char *ptr = *lineptr;
|
||||
while (true) {
|
||||
int c = fgetc(stream);
|
||||
if (c == -1) {
|
||||
if (feof(stream)) {
|
||||
*ptr = '\0';
|
||||
return (ssize_t) (ptr - *lineptr);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
*ptr = c;
|
||||
++ptr;
|
||||
|
||||
if (c == '\n') {
|
||||
*ptr = '\0';
|
||||
return ptr - *lineptr;
|
||||
}
|
||||
if (ptr + 2 >= *lineptr + *n) {
|
||||
size_t new_size = *n * 2;
|
||||
ssize_t diff = ptr - *lineptr;
|
||||
|
||||
char *new_lineptr = (char*) realloc(*lineptr, new_size);
|
||||
if (new_lineptr == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
*lineptr = new_lineptr;
|
||||
*n = new_size;
|
||||
ptr = new_lineptr + diff;
|
||||
}
|
||||
}
|
||||
#else // ie UNIX
|
||||
return getline(lineptr, n, stream);
|
||||
#endif
|
||||
}
|
32
libretroshare/src/util/rsfile.h
Normal file
32
libretroshare/src/util/rsfile.h
Normal file
@ -0,0 +1,32 @@
|
||||
/*******************************************************************************
|
||||
* libretroshare/src/util: rsfile.h *
|
||||
* *
|
||||
* libretroshare: retroshare core library *
|
||||
* *
|
||||
* Copyright (C) 2021 Retroshare Team <retroshare.project@gmail.com> *
|
||||
* *
|
||||
* This program is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License as *
|
||||
* published by the Free Software Foundation, either version 3 of the *
|
||||
* License, or (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public License *
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
*******************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
namespace RsFileUtil {
|
||||
|
||||
int set_fd_nonblock(int fd);
|
||||
ssize_t rs_getline(char **lineptr, size_t *n, FILE *stream);
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user