32 #ifndef _QORE_INTERN_QORE_QF_PRIVATE_H
33 #define _QORE_INTERN_QORE_QF_PRIVATE_H
35 #include "qore/intern/QC_Queue.h"
37 #include "qore/intern/QC_TermIOS.h"
40 #include "qore/intern/StringReaderHelper.h"
48 #include <sys/types.h>
53 #elif defined HAVE_SELECT
54 #include <sys/select.h>
55 #elif (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
58 #error no async I/O APIs available
61 #ifndef DEFAULT_FILE_BUFSIZE
62 #define DEFAULT_FILE_BUFSIZE 16384
65 hashdecl qore_qf_private {
68 bool special_file =
false;
72 Queue* event_queue =
nullptr;
76 bool event_data =
false;
78 DLLLOCAL qore_qf_private(
const QoreEncoding* cs) : charset(cs) {
81 DLLLOCAL ~qore_qf_private() {
88 DLLLOCAL
int close_intern(
bool detach =
false) {
98 do_close_event_unlocked();
108 DLLLOCAL
int redirect(qore_qf_private& file,
ExceptionSink* xsink) {
117 int rc = dup2(file.fd, fd);
122 filename = file.filename;
127 DLLLOCAL
int open_intern(
const char* fn,
int flags,
int mode,
const QoreEncoding* cs) {
135 if (!(flags & O_TEXT))
139 do_open_event_unlocked(fn, flags, mode, cs);
141 fd = ::open(fn, flags, mode);
145 do_opened_event_unlocked(fn, flags, mode, cs);
154 DLLLOCAL
int open(
const char* fn,
int flags,
int mode,
const QoreEncoding* cs) {
155 if (!fn || special_file)
159 return open_intern(fn, flags, mode, cs);
167 xsink->
raiseException(
"FILE-READ-ERROR",
"file has not been opened");
176 xsink->
raiseException(
"FILE-WRITE-ERROR",
"file has not been opened");
185 xsink->
raiseException(
"FILE-OPERATION-ERROR",
"file has not been opened");
189 DLLLOCAL
bool isOpen()
const {
193 DLLLOCAL
bool isDataAvailable(
int timeout_ms,
ExceptionSink *xsink)
const {
196 if (check_read_open(xsink))
199 return isDataAvailableIntern(timeout_ms,
"isDataAvailable", xsink);
208 DLLLOCAL
int select(
int timeout_ms,
bool read,
const char* mname,
ExceptionSink* xsink)
const {
210 if (check_open(xsink))
213 #if defined HAVE_POLL
214 return poll_intern(timeout_ms, read, mname, xsink);
215 #elif defined HAVE_SELECT
216 return select_intern(timeout_ms, read, mname, xsink);
218 #error no async I/O operations supported
222 #if defined HAVE_POLL
223 DLLLOCAL
int poll_intern(
int timeout_ms,
bool read,
const char* mname,
ExceptionSink* xsink)
const {
225 pollfd fds = {fd, (short)(read ? POLLIN : POLLOUT), 0};
227 rc = poll(&fds, 1, timeout_ms);
228 if (rc == -1 && errno == EINTR)
233 xsink->
raiseException(
"FILE-SELECT-ERROR",
"poll(2) returned an error in call to File::%s()", mname);
234 else if (!rc && ((fds.revents & POLLHUP) || (fds.revents & (POLLERR|POLLNVAL))))
239 #elif defined HAVE_SELECT
240 DLLLOCAL
int select_intern(
int timeout_ms,
bool read,
const char* mname,
ExceptionSink* xsink)
const {
241 #if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
246 if (fd >= FD_SETSIZE) {
248 xsink->
raiseException(
"FILE-SELECT-ERROR",
"fd is %d in call to File::%s() which is >= %d; contact the Qore developers to implement an alternative to select() on this platform", fd, mname, FD_SETSIZE);
260 tv.tv_sec = timeout_ms / 1000;
261 tv.tv_usec = (timeout_ms % 1000) * 1000;
263 rc = read ? ::select(fd + 1, &sfs, 0, 0, &tv) : ::select(fd + 1, 0, &sfs, 0, &tv);
264 if (rc >= 0 || errno != EINTR)
269 xsink->
raiseException(
"FILE-SELECT-ERROR",
"select(2) returned an error in call to File::%s()", mname);
278 DLLLOCAL
bool isDataAvailableIntern(
int timeout_ms,
const char* mname,
ExceptionSink *xsink)
const {
279 return select(timeout_ms,
true, mname, xsink);
282 #ifdef HAVE_TERMIOS_H
283 DLLLOCAL
int setTerminalAttributes(
int action, QoreTermIOS* ios,
ExceptionSink* xsink)
const {
286 if (check_open(xsink))
289 return ios->set(fd, action, xsink);
292 DLLLOCAL
int getTerminalAttributes(QoreTermIOS* ios,
ExceptionSink* xsink)
const {
295 if (check_open(xsink))
298 return ios->get(fd, xsink);
306 rc = ::read(fd, buf, bs);
308 if (rc >= 0 || errno != EINTR)
313 do_read_event_unlocked(rc, rc, bs);
322 rc = ::write(fd, buf, len);
324 if (rc >= 0 || errno != EINTR)
329 do_write_event_unlocked(rc, rc, len);
330 else if (xsink && rc < 0)
331 xsink->
raiseErrnoException(
"FILE-WRITE-ERROR", errno,
"failed writing " QSD
" byte%s to File", len, len == 1 ?
"" :
"s");
337 DLLLOCAL
int readChar()
const {
338 unsigned char ch = 0;
339 if (read(&ch, 1) != 1)
345 DLLLOCAL
int readUnicode(
int* n_len = 0)
const;
349 if (timeout_ms >= 0 && !isDataAvailableIntern(timeout_ms, mname, xsink)) {
351 xsink->
raiseException(
"FILE-READ-TIMEOUT",
"timeout limit exceeded (%d ms) reading file block in ReadOnlyFile::%s()", timeout_ms, mname);
357 rc = ::read(fd, dest, limit);
361 if (errno != EINTR) {
362 xsink->
raiseErrnoException(
"FILE-READ-ERROR", errno,
"error reading file in ReadOnlyFile::%s()", mname);
371 return q_read_string(xsink, size, charset, std::bind(&qore_qf_private::readData,
this, _1, _2, timeout_ms, mname, _3));
375 qore_size_t bs = size > 0 && size < DEFAULT_FILE_BUFSIZE ? size : DEFAULT_FILE_BUFSIZE;
377 char* buf = (
char* )malloc(
sizeof(
char) * bs);
382 if (timeout_ms >= 0 && !isDataAvailableIntern(timeout_ms, mname, xsink)) {
384 xsink->
raiseException(
"FILE-READ-TIMEOUT",
"timeout limit exceeded (%d ms) reading file block in ReadOnlyFile::%s()", timeout_ms, mname);
391 rc = ::read(fd, buf, bs);
395 if (errno != EINTR) {
396 xsink->
raiseErrnoException(
"FILE-READ-ERROR", errno,
"error reading file after " QSD
" bytes read in File::%s()", br, mname);
405 bbuf = (
char* )realloc(bbuf, br + rc + 1);
407 memcpy(bbuf + br, buf, rc);
410 do_read_event_unlocked(rc, br, size);
432 int rc = readLine(**str, incl_eol);
435 xsink->
raiseException(
"FILE-READLINE-ERROR",
"file has not been opened");
439 return rc == -1 ? 0 : str.release();
442 DLLLOCAL
int readLine(
QoreString& str,
bool incl_eol =
true) {
450 bool tty = (bool)isatty(fd);
454 while ((ch = readChar()) >= 0) {
469 lseek(fd, -1, SEEK_CUR);
488 DLLLOCAL
int readUntil(
char byte,
QoreString& str,
bool incl_byte =
true) {
498 while ((ch = readChar()) >= 0) {
516 int rc = readUntil(bytes, **str, incl_bytes);
519 xsink->
raiseException(
"FILE-READLINE-ERROR",
"file has not been opened");
523 return rc == -1 ? 0 : str.release();
526 DLLLOCAL
int readLineUnicode(
QoreString& str,
bool incl_eol =
true) {
534 bool tty = (bool)isatty(fd);
538 while ((ch = readUnicode()) >= 0) {
552 char c = str[str.
size() - 1];
558 ch = readUnicode(&len);
566 lseek(fd, -len, SEEK_CUR);
585 DLLLOCAL
int readUntilUnicode(
char byte,
QoreString& str,
bool incl_byte =
true) {
595 while ((ch = readUnicode()) >= 0) {
617 DLLLOCAL
int readUntilUnicode(
const char* bytes,
QoreString& str,
bool incl_bytes) {
630 while ((ch = readUnicode()) >= 0) {
644 if (ch == bytes[pos]) {
658 if (!strncmp(str.
getBuffer() + ps, bytes, pos - ps)) {
677 DLLLOCAL
int readUntil(
const char* bytes,
QoreString& str,
bool incl_bytes) {
679 return readUntil(bytes[0], str, incl_bytes);
693 while ((ch = readChar()) >= 0) {
699 if (c == bytes[pos]) {
713 if (!strncmp(str.
getBuffer() + ps, bytes, pos - ps)) {
731 DLLLOCAL
bool isTty()
const {
737 return (
bool)isatty(fd);
740 DLLLOCAL
int detachFd() {
761 return lseek(fd, 0, SEEK_CUR);
764 DLLLOCAL
QoreHashNode* getEvent(
int event,
int source = QORE_SOURCE_FILE)
const {
783 event_queue->deref(xsink);
787 event_data = with_data;
797 event_queue->pushAndTakeRef(getEvent(QORE_EVENT_DELETED));
804 event_queue->deref(xsink);
805 event_queue =
nullptr;
809 DLLLOCAL
void do_open_event_unlocked(
const char* fn,
int flags,
int mode,
const QoreEncoding* enc)
const {
816 event_queue->pushAndTakeRef(h);
820 DLLLOCAL
void do_opened_event_unlocked(
const char* fn,
int flags,
int mode,
const QoreEncoding* enc)
const {
823 h->
setKeyValue(
"source", QORE_SOURCE_FILE,
nullptr);
829 event_queue->pushAndTakeRef(h);
833 DLLLOCAL
void do_close_event_unlocked()
const {
835 event_queue->pushAndTakeRef(getEvent(QORE_EVENT_CHANNEL_CLOSED));
839 DLLLOCAL
void do_read_event_unlocked(
int bytes_read,
int total_read,
int bufsize)
const {
846 event_queue->pushAndTakeRef(h);
850 DLLLOCAL
void do_write_event_unlocked(
int bytes_written,
int total_written,
int bufsize)
const {
855 h->
setKeyValue(
"total_written", total_written,
nullptr);
856 h->
setKeyValue(
"total_to_write", bufsize,
nullptr);
857 event_queue->pushAndTakeRef(h);
864 if (check_read_open(xsink))
868 if (fstat(fd, &sbuf)) {
873 return stat_to_list(sbuf);
879 if (check_read_open(xsink))
883 if (fstat(fd, &sbuf)) {
888 return stat_to_hash(sbuf);
891 #ifdef Q_HAVE_STATVFS
895 if (check_read_open(xsink))
898 hashdecl statvfs vfs;
899 #ifdef HAVE_SYS_STATVFS_H
900 if (fstatvfs(fd, &vfs)) {
905 if (q_fstatvfs(filename.c_str(), &vfs)) {
911 return statvfs_to_hash(vfs);