Qore Programming Language  0.9.3.2
qore_qf_private.h
1 /* -*- mode: c++; indent-tabs-mode: nil -*- */
2 /*
3  qore_qf_private.h
4 
5  Qore Programming Language
6 
7  Copyright (C) 2003 - 2019 Qore Technologies, s.r.o.
8 
9  Permission is hereby granted, free of charge, to any person obtaining a
10  copy of this software and associated documentation files (the "Software"),
11  to deal in the Software without restriction, including without limitation
12  the rights to use, copy, modify, merge, publish, distribute, sublicense,
13  and/or sell copies of the Software, and to permit persons to whom the
14  Software is furnished to do so, subject to the following conditions:
15 
16  The above copyright notice and this permission notice shall be included in
17  all copies or substantial portions of the Software.
18 
19  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25  DEALINGS IN THE SOFTWARE.
26 
27  Note that the Qore library is released under a choice of three open-source
28  licenses: MIT (as above), LGPL 2+, or GPL 2+; see README-LICENSE for more
29  information.
30 */
31 
32 #ifndef _QORE_INTERN_QORE_QF_PRIVATE_H
33 #define _QORE_INTERN_QORE_QF_PRIVATE_H
34 
35 #include "qore/intern/QC_Queue.h"
36 #ifdef HAVE_TERMIOS_H
37 #include "qore/intern/QC_TermIOS.h"
38 #endif
39 
40 #include "qore/intern/StringReaderHelper.h"
41 
42 #include <cerrno>
43 #include <cstdio>
44 #include <cstdlib>
45 #include <cstring>
46 #include <string>
47 #include <sys/file.h>
48 #include <sys/types.h>
49 #include <unistd.h>
50 
51 #if defined HAVE_POLL
52 #include <poll.h>
53 #elif defined HAVE_SELECT
54 #include <sys/select.h>
55 #elif (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
56 #define HAVE_SELECT 1
57 #else
58 #error no async I/O APIs available
59 #endif
60 
61 #ifndef DEFAULT_FILE_BUFSIZE
62 #define DEFAULT_FILE_BUFSIZE 16384
63 #endif
64 
65 hashdecl qore_qf_private {
66  int fd = -1;
67  bool is_open = false;
68  bool special_file = false;
69  const QoreEncoding* charset;
70  std::string filename;
71  mutable QoreThreadLock m;
72  Queue* cb_queue = nullptr;
73 
74  DLLLOCAL qore_qf_private(const QoreEncoding* cs) : charset(cs) {
75  }
76 
77  DLLLOCAL ~qore_qf_private() {
78  close_intern();
79 
80  // must be dereferenced and removed before deleting
81  assert(!cb_queue);
82  }
83 
84  DLLLOCAL int close_intern(bool detach = false) {
85  filename.clear();
86 
87  int rc;
88  if (is_open) {
89  if (special_file) {
90  rc = -1;
91  } else if (!detach) {
92  rc = ::close(fd);
93  is_open = false;
94  do_close_event_unlocked();
95  } else {
96  rc = 0;
97  }
98  } else {
99  rc = 0;
100  }
101  return rc;
102  }
103 
104  DLLLOCAL int redirect(qore_qf_private& file, ExceptionSink* xsink) {
105  if (&file == this)
106  return 0;
107 
108  // lock both files
109  AutoLocker al(m);
110  AutoLocker al2(file.m);
111 
112  // dup2() will close this file descriptor
113  int rc = dup2(file.fd, fd);
114  if (rc == -1) {
115  xsink->raiseErrnoException("FILE-REDIRECT-ERROR", errno, "error in dup2()");
116  return -1;
117  }
118  filename = file.filename;
119 
120  return 0;
121  }
122 
123  DLLLOCAL int open_intern(const char* fn, int flags, int mode, const QoreEncoding* cs) {
124  close_intern();
125 
126  if (!flags)
127  flags = O_RDONLY;
128 
129 #ifdef _Q_WINDOWS
130  // open files in binary mode by default on Windows
131  if (!(flags & O_TEXT))
132  flags |= O_BINARY;
133 #endif
134 
135  do_open_event_unlocked(fn, flags, mode, cs);
136 
137  fd = ::open(fn, flags, mode);
138  if (fd < 0)
139  return fd;
140 
141  do_opened_event_unlocked(fn, flags, mode, cs);
142 
143  filename = fn;
144  if (cs)
145  charset = cs;
146  is_open = true;
147  return 0;
148  }
149 
150  DLLLOCAL int open(const char* fn, int flags, int mode, const QoreEncoding* cs) {
151  if (!fn || special_file)
152  return -1;
153 
154  AutoLocker al(m);
155  return open_intern(fn, flags, mode, cs);
156  }
157 
158  // returns -1 for exception
159  DLLLOCAL int check_read_open(ExceptionSink* xsink) const {
160  if (is_open)
161  return 0;
162 
163  xsink->raiseException("FILE-READ-ERROR", "file has not been opened");
164  return -1;
165  }
166 
167  // returns -1 for exception
168  DLLLOCAL int check_write_open(ExceptionSink* xsink) const {
169  if (is_open)
170  return 0;
171 
172  xsink->raiseException("FILE-WRITE-ERROR", "file has not been opened");
173  return -1;
174  }
175 
176  // returns -1 for exception
177  DLLLOCAL int check_open(ExceptionSink* xsink) const {
178  if (is_open)
179  return 0;
180 
181  xsink->raiseException("FILE-OPERATION-ERROR", "file has not been opened");
182  return -1;
183  }
184 
185  DLLLOCAL bool isOpen() const {
186  return is_open;
187  }
188 
189  DLLLOCAL bool isDataAvailable(int timeout_ms, ExceptionSink *xsink) const {
190  AutoLocker al(m);
191 
192  if (check_read_open(xsink))
193  return false;
194 
195  return isDataAvailableIntern(timeout_ms, "isDataAvailable", xsink);
196  }
197 
198  // fd must be open or -1 is returned and a Qore-language exception is raised
199  /* return values:
200  -1: error
201  0: timeout
202  > 0: I/O can continue
203  */
204  DLLLOCAL int select(int timeout_ms, bool read, const char* mname, ExceptionSink* xsink) const {
205  //printd(5, "select() to: %d read: %d mname: '%s'\n", timeout_ms, read, mname);
206  if (check_open(xsink))
207  return -1;
208 
209 #if defined HAVE_POLL
210  return poll_intern(timeout_ms, read, mname, xsink);
211 #elif defined HAVE_SELECT
212  return select_intern(timeout_ms, read, mname, xsink);
213 #else
214 #error no async I/O operations supported
215 #endif
216  }
217 
218 #if defined HAVE_POLL
219  DLLLOCAL int poll_intern(int timeout_ms, bool read, const char* mname, ExceptionSink* xsink) const {
220  int rc;
221  pollfd fds = {fd, (short)(read ? POLLIN : POLLOUT), 0};
222  while (true) {
223  rc = poll(&fds, 1, timeout_ms);
224  if (rc == -1 && errno == EINTR)
225  continue;
226  break;
227  }
228  if (rc < 0)
229  xsink->raiseException("FILE-SELECT-ERROR", "poll(2) returned an error in call to File::%s()", mname);
230  else if (!rc && ((fds.revents & POLLHUP) || (fds.revents & (POLLERR|POLLNVAL))))
231  rc = -1;
232 
233  return rc;
234  }
235 #elif defined HAVE_SELECT
236  DLLLOCAL int select_intern(int timeout_ms, bool read, const char* mname, ExceptionSink* xsink) const {
237 #if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
238  // async I/O ignored on files on windows
239  return 1;
240 #else
241  // select is inherently broken since it can only handle descriptors < FD_SETSIZE, which is 1024 on Linux for example
242  if (fd >= FD_SETSIZE) {
243  if (xsink)
244  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);
245  return -1;
246  }
247  hashdecl timeval tv;
248  int rc;
249  while (true) {
250  // to be safe, we set the file descriptor arg after each EINTR (required on Linux for example)
251  fd_set sfs;
252 
253  FD_ZERO(&sfs);
254  FD_SET(fd, &sfs);
255 
256  tv.tv_sec = timeout_ms / 1000;
257  tv.tv_usec = (timeout_ms % 1000) * 1000;
258 
259  rc = read ? ::select(fd + 1, &sfs, 0, 0, &tv) : ::select(fd + 1, 0, &sfs, 0, &tv);
260  if (rc >= 0 || errno != EINTR)
261  break;
262  }
263  if (rc == -1) {
264  rc = 0;
265  xsink->raiseException("FILE-SELECT-ERROR", "select(2) returned an error in call to File::%s()", mname);
266  }
267 
268  return rc;
269 #endif
270  }
271 #endif
272 
273  // assumes lock is held and file is open
274  DLLLOCAL bool isDataAvailableIntern(int timeout_ms, const char* mname, ExceptionSink *xsink) const {
275  return select(timeout_ms, true, mname, xsink);
276  }
277 
278 #ifdef HAVE_TERMIOS_H
279  DLLLOCAL int setTerminalAttributes(int action, QoreTermIOS* ios, ExceptionSink* xsink) const {
280  AutoLocker al(m);
281 
282  if (check_open(xsink))
283  return -1;
284 
285  return ios->set(fd, action, xsink);
286  }
287 
288  DLLLOCAL int getTerminalAttributes(QoreTermIOS* ios, ExceptionSink* xsink) const {
289  AutoLocker al(m);
290 
291  if (check_open(xsink))
292  return -1;
293 
294  return ios->get(fd, xsink);
295  }
296 #endif
297 
298  // unlocked, assumes file is open
299  DLLLOCAL qore_size_t read(void *buf, qore_size_t bs) const {
300  qore_offset_t rc;
301  while (true) {
302  rc = ::read(fd, buf, bs);
303  // try again if we were interrupted by a signal
304  if (rc >= 0 || errno != EINTR)
305  break;
306  }
307 
308  if (rc > 0)
309  do_read_event_unlocked(rc, rc, bs);
310 
311  return rc;
312  }
313 
314  // unlocked, assumes file is open
315  DLLLOCAL qore_size_t write(const void* buf, qore_size_t len, ExceptionSink* xsink = 0) const {
316  qore_offset_t rc;
317  while (true) {
318  rc = ::write(fd, buf, len);
319  // try again if we are interrupted by a signal
320  if (rc >= 0 || errno != EINTR)
321  break;
322  }
323 
324  if (rc > 0)
325  do_write_event_unlocked(rc, rc, len);
326  else if (xsink && rc < 0)
327  xsink->raiseErrnoException("FILE-WRITE-ERROR", errno, "failed writing " QSD " byte%s to File", len, len == 1 ? "" : "s");
328 
329  return rc;
330  }
331 
332  // private function, unlocked
333  DLLLOCAL int readChar() const {
334  unsigned char ch = 0;
335  if (read(&ch, 1) != 1)
336  return -1;
337  return (int)ch;
338  }
339 
340  // private function, unlocked
341  DLLLOCAL int readUnicode(int* n_len = 0) const;
342 
343  DLLLOCAL qore_offset_t readData(void* dest, qore_size_t limit, int timeout_ms, const char* mname, ExceptionSink* xsink) {
344  // wait for data
345  if (timeout_ms >= 0 && !isDataAvailableIntern(timeout_ms, mname, xsink)) {
346  if (!*xsink)
347  xsink->raiseException("FILE-READ-TIMEOUT", "timeout limit exceeded (%d ms) reading file block in ReadOnlyFile::%s()", timeout_ms, mname);
348  return -1;
349  }
350 
351  qore_offset_t rc;
352  while (true) {
353  rc = ::read(fd, dest, limit);
354  // try again if we were interrupted by a signal
355  if (rc >= 0)
356  break;
357  if (errno != EINTR) {
358  xsink->raiseErrnoException("FILE-READ-ERROR", errno, "error reading file in ReadOnlyFile::%s()", mname);
359  return -1;
360  }
361  }
362 
363  return rc;
364  }
365 
366  DLLLOCAL QoreStringNode* readString(qore_offset_t size, int timeout_ms, const char* mname, ExceptionSink* xsink) {
367  return q_read_string(xsink, size, charset, std::bind(&qore_qf_private::readData, this, _1, _2, timeout_ms, mname, _3));
368  }
369 
370  DLLLOCAL char* readBlock(qore_offset_t &size, int timeout_ms, const char* mname, ExceptionSink* xsink) {
371  qore_size_t bs = size > 0 && size < DEFAULT_FILE_BUFSIZE ? size : DEFAULT_FILE_BUFSIZE;
372  qore_size_t br = 0;
373  char* buf = (char* )malloc(sizeof(char) * bs);
374  char* bbuf = 0;
375 
376  while (true) {
377  // wait for data
378  if (timeout_ms >= 0 && !isDataAvailableIntern(timeout_ms, mname, xsink)) {
379  if (!*xsink)
380  xsink->raiseException("FILE-READ-TIMEOUT", "timeout limit exceeded (%d ms) reading file block in ReadOnlyFile::%s()", timeout_ms, mname);
381  br = 0;
382  break;
383  }
384 
385  qore_offset_t rc;
386  while (true) {
387  rc = ::read(fd, buf, bs);
388  // try again if we were interrupted by a signal
389  if (rc >= 0)
390  break;
391  if (errno != EINTR) {
392  xsink->raiseErrnoException("FILE-READ-ERROR", errno, "error reading file after " QSD " bytes read in File::%s()", br, mname);
393  break;
394  }
395  }
396  //printd(5, "readBlock(fd: %d, buf: %p, bs: %d) rc: %d\n", fd, buf, bs, rc);
397  if (rc <= 0)
398  break;
399 
400  // enlarge bbuf (ensure buffer is 1 byte bigger than needed)
401  bbuf = (char* )realloc(bbuf, br + rc + 1);
402  // append buffer to bbuf
403  memcpy(bbuf + br, buf, rc);
404  br += rc;
405 
406  do_read_event_unlocked(rc, br, size);
407 
408  if (size > 0) {
409  if (size - br < bs)
410  bs = size - br;
411  if (br >= (qore_size_t)size)
412  break;
413  }
414  }
415  free(buf);
416  if (*xsink) {
417  if (bbuf)
418  free(bbuf);
419  return 0;
420  }
421  size = br;
422  return bbuf;
423  }
424 
425  DLLLOCAL QoreStringNode* readLine(bool incl_eol, ExceptionSink* xsink) {
426  QoreStringNodeHolder str(new QoreStringNode(charset));
427 
428  int rc = readLine(**str, incl_eol);
429 
430  if (rc == -2) {
431  xsink->raiseException("FILE-READLINE-ERROR", "file has not been opened");
432  return 0;
433  }
434 
435  return rc == -1 ? 0 : str.release();
436  }
437 
438  DLLLOCAL int readLine(QoreString& str, bool incl_eol = true) {
439  str.clear();
440 
441  AutoLocker al(m);
442 
443  if (!is_open)
444  return -2;
445 
446  bool tty = (bool)isatty(fd);
447 
448  int ch, rc = -1;
449 
450  while ((ch = readChar()) >= 0) {
451  str.concat((char)ch);
452  if (rc == -1)
453  rc = 0;
454 
455  if (ch == '\r') {
456  // see if next byte is \n' if we're not connected to a terminal device
457  if (!tty) {
458  ch = readChar();
459  if (ch >= 0) {
460  if (ch == '\n') {
461  if (incl_eol)
462  str.concat((char)ch);
463  }
464  else {
465  // reset file to previous byte position
466  lseek(fd, -1, SEEK_CUR);
467  }
468  }
469  }
470  if (!incl_eol)
471  str.terminate(str.strlen() - 1);
472  break;
473  }
474 
475  if (ch == '\n') {
476  if (!incl_eol)
477  str.terminate(str.strlen() - 1);
478  break;
479  }
480  }
481 
482  return rc;
483  }
484 
485  DLLLOCAL int readUntil(char byte, QoreString& str, bool incl_byte = true) {
486  str.clear();
487 
488  AutoLocker al(m);
489 
490  if (!is_open)
491  return -2;
492 
493  int ch, rc = -1;
494 
495  while ((ch = readChar()) >= 0) {
496  char c = ch;
497  str.concat(c);
498  if (rc == -1)
499  rc = 0;
500  if (c == byte) {
501  if (!incl_byte)
502  str.terminate(str.strlen() - 1);
503  break;
504  }
505  }
506 
507  return rc;
508  }
509 
510  DLLLOCAL QoreStringNode* readUntil(const char* bytes, bool incl_bytes, ExceptionSink* xsink) {
511  QoreStringNodeHolder str(new QoreStringNode(charset));
512 
513  int rc = readUntil(bytes, **str, incl_bytes);
514 
515  if (rc == -2) {
516  xsink->raiseException("FILE-READLINE-ERROR", "file has not been opened");
517  return 0;
518  }
519 
520  return rc == -1 ? 0 : str.release();
521  }
522 
523  DLLLOCAL int readLineUnicode(QoreString& str, bool incl_eol = true) {
524  str.clear();
525 
526  AutoLocker al(m);
527 
528  if (!is_open)
529  return -2;
530 
531  bool tty = (bool)isatty(fd);
532 
533  int ch, rc = -1;
534 
535  while ((ch = readUnicode()) >= 0) {
536  // skip BOM
537  if (ch == 0xfeff)
538  continue;
539  else if (ch == 0xfffe && charset == QCS_UTF16 && str.empty()) {
540  charset = QCS_UTF16LE;
541  continue;
542  }
543 
544  str.concatUnicode(ch);
545 
546  if (rc == -1)
547  rc = 0;
548 
549  char c = str[str.size() - 1];
550 
551  if (c == '\r') {
552  // see if next byte is \n' if we're not connected to a terminal device
553  if (!tty) {
554  int len = 0;
555  ch = readUnicode(&len);
556  if (ch >= 0) {
557  if (ch == '\n') {
558  if (incl_eol)
559  str.concatUnicode(ch);
560  }
561  else {
562  // reset file to previous byte position
563  lseek(fd, -len, SEEK_CUR);
564  }
565  }
566  }
567  if (!incl_eol)
568  str.terminate(str.strlen() - 1);
569  break;
570  }
571 
572  if (ch == '\n') {
573  if (!incl_eol)
574  str.terminate(str.strlen() - 1);
575  break;
576  }
577  }
578 
579  return rc;
580  }
581 
582  DLLLOCAL int readUntilUnicode(char byte, QoreString& str, bool incl_byte = true) {
583  str.clear();
584 
585  AutoLocker al(m);
586 
587  if (!is_open)
588  return -2;
589 
590  int ch, rc = -1;
591 
592  while ((ch = readUnicode()) >= 0) {
593  // skip BOM
594  if (ch == 0xfeff)
595  continue;
596  else if (ch == 0xfffe && charset == QCS_UTF16 && str.empty()) {
597  charset = QCS_UTF16LE;
598  continue;
599  }
600 
601  str.concatUnicode(ch);
602 
603  if (rc == -1)
604  rc = 0;
605  if (ch == byte) {
606  if (!incl_byte)
607  str.terminate(str.strlen() - 1);
608  break;
609  }
610  }
611 
612  return rc;
613  }
614  DLLLOCAL int readUntilUnicode(const char* bytes, QoreString& str, bool incl_bytes) {
615  str.clear();
616 
617  AutoLocker al(m);
618 
619  if (!is_open)
620  return -2;
621 
622  // offset in bytes
623  unsigned pos = 0;
624 
625  int ch, rc = -1;
626 
627  while ((ch = readUnicode()) >= 0) {
628  // skip BOM
629  if (ch == 0xfeff)
630  continue;
631  else if (ch == 0xfffe && charset == QCS_UTF16 && str.empty()) {
632  charset = QCS_UTF16LE;
633  continue;
634  }
635 
636  str.concatUnicode(ch);
637 
638  if (rc == -1)
639  rc = 0;
640 
641  if (ch == bytes[pos]) {
642  ++pos;
643  if (!bytes[pos]) {
644  if (!incl_bytes)
645  str.terminate(str.strlen() - pos);
646  break;
647  }
648  }
649  else if (pos) {
650  // bytes=aaac read=aaaac str=aaa pos=3
651  // ^ ^
652  // restart search with characters already added to the string if more than 1 character was matched previously
653  if (pos > 1) {
654  unsigned ps = 1;
655  while (ps < pos) {
656  if (!strncmp(str.getBuffer() + ps, bytes, pos - ps)) {
657  pos -= ps;
658  break;
659  }
660  ++ps;
661  }
662  if (pos == ps)
663  pos = 0;
664  }
665  else {
666  // restart search if failed
667  pos = 0;
668  }
669  }
670  }
671 
672  return rc;
673  }
674 
675  // not the most efficient search algorithm, restarts the search the byte after it fails for multi-byte patterns
676  DLLLOCAL int readUntil(const char* bytes, QoreString& str, bool incl_bytes) {
677  if (!bytes[1])
678  return readUntil(bytes[0], str, incl_bytes);
679 
680  str.clear();
681 
682  AutoLocker al(m);
683 
684  if (!is_open)
685  return -2;
686 
687  // offset in bytes
688  unsigned pos = 0;
689 
690  int ch, rc = -1;
691 
692  while ((ch = readChar()) >= 0) {
693  char c = ch;
694  str.concat(c);
695  if (rc == -1)
696  rc = 0;
697 
698  if (c == bytes[pos]) {
699  ++pos;
700  if (!bytes[pos]) {
701  if (!incl_bytes)
702  str.terminate(str.strlen() - pos);
703  break;
704  }
705  }
706  else if (pos) {
707  // bytes=aaac read=aaaac str=aaa pos=3
708  // ^ ^
709  // restart search with characters already added to the string if more than 1 character was matched previously
710  if (pos > 1) {
711  unsigned ps = 1;
712  while (ps < pos) {
713  if (!strncmp(str.getBuffer() + ps, bytes, pos - ps)) {
714  pos -= ps;
715  break;
716  }
717  ++ps;
718  }
719  if (pos == ps)
720  pos = 0;
721  }
722  else {
723  // restart search if failed
724  pos = 0;
725  }
726  }
727  }
728 
729  return rc;
730  }
731 
732  DLLLOCAL bool isTty() const {
733  AutoLocker al(m);
734 
735  if (!is_open)
736  return false;
737 
738  return (bool)isatty(fd);
739  }
740 
741  DLLLOCAL int detachFd() {
742  AutoLocker al(m);
743 
744  if (!is_open) {
745  return -1;
746  }
747 
748  int rc = fd;
749  // special files (stdout/stderr/stdin) are not closed anyway, so we don't mark the object closed in this case
750  if (!special_file) {
751  close_intern(true);
752  }
753  return rc;
754  }
755 
756  DLLLOCAL qore_size_t getPos() const {
757  AutoLocker al(m);
758 
759  if (!is_open)
760  return -1;
761 
762  return lseek(fd, 0, SEEK_CUR);
763  }
764 
765  DLLLOCAL void setEventQueue(Queue* cbq, ExceptionSink* xsink) {
766  AutoLocker al(m);
767  if (cb_queue)
768  cb_queue->deref(xsink);
769  cb_queue = cbq;
770  }
771 
772  DLLLOCAL void cleanup(ExceptionSink* xsink) {
773  AutoLocker al(m);
774  if (cb_queue) {
775  // close the file before the delete message is put on the queue
776  // the file would be closed anyway in the destructor
777  close_intern();
778 
779  QoreHashNode* h = new QoreHashNode(autoTypeInfo);
780  h->setKeyValue("event", QORE_EVENT_DELETED, 0);
781  h->setKeyValue("source", QORE_SOURCE_FILE, 0);
782  h->setKeyValue("id", (int64)this, 0);
783  cb_queue->pushAndTakeRef(h);
784 
785  // deref and remove event queue
786  cb_queue->deref(xsink);
787  cb_queue = 0;
788  }
789  }
790 
791  DLLLOCAL void do_open_event_unlocked(const char* fn, int flags, int mode, const QoreEncoding* enc) const {
792  if (cb_queue) {
793  QoreHashNode* h = new QoreHashNode(autoTypeInfo);
794  h->setKeyValue("event", QORE_EVENT_OPEN_FILE, 0);
795  h->setKeyValue("source", QORE_SOURCE_FILE, 0);
796  h->setKeyValue("id", (int64)this, 0);
797  h->setKeyValue("filename", new QoreStringNode(fn), 0);
798  h->setKeyValue("flags", flags, 0);
799  h->setKeyValue("mode", mode, 0);
800  h->setKeyValue("encoding", new QoreStringNode(enc->getCode()), 0);
801  cb_queue->pushAndTakeRef(h);
802  }
803  }
804 
805  DLLLOCAL void do_opened_event_unlocked(const char* fn, int flags, int mode, const QoreEncoding* enc) const {
806  if (cb_queue) {
807  QoreHashNode* h = new QoreHashNode(autoTypeInfo);
808  h->setKeyValue("event", QORE_EVENT_FILE_OPENED, 0);
809  h->setKeyValue("source", QORE_SOURCE_FILE, 0);
810  h->setKeyValue("id", (int64)this, 0);
811  h->setKeyValue("filename", new QoreStringNode(fn), 0);
812  h->setKeyValue("flags", flags, 0);
813  h->setKeyValue("mode", mode, 0);
814  h->setKeyValue("encoding", new QoreStringNode(enc->getCode()), 0);
815  cb_queue->pushAndTakeRef(h);
816  }
817  }
818 
819  DLLLOCAL void do_close_event_unlocked() const {
820  if (cb_queue) {
821  QoreHashNode* h = new QoreHashNode(autoTypeInfo);
822  h->setKeyValue("event", QORE_EVENT_CHANNEL_CLOSED, 0);
823  h->setKeyValue("source", QORE_SOURCE_FILE, 0);
824  h->setKeyValue("id", (int64)this, 0);
825  cb_queue->pushAndTakeRef(h);
826  }
827  }
828 
829  DLLLOCAL void do_read_event_unlocked(int bytes_read, int total_read, int bufsize) const {
830  // post bytes read on event queue, if any
831  if (cb_queue) {
832  QoreHashNode* h = new QoreHashNode(autoTypeInfo);
833  h->setKeyValue("event", QORE_EVENT_DATA_READ, 0);
834  h->setKeyValue("source", QORE_SOURCE_FILE, 0);
835  h->setKeyValue("id", (int64)this, 0);
836  h->setKeyValue("read", bytes_read, 0);
837  h->setKeyValue("total_read", total_read, 0);
838  h->setKeyValue("total_to_read", bufsize, 0);
839  cb_queue->pushAndTakeRef(h);
840  }
841  }
842 
843  DLLLOCAL void do_write_event_unlocked(int bytes_written, int total_written, int bufsize) const {
844  // post bytes sent on event queue, if any
845  if (cb_queue) {
846  QoreHashNode* h = new QoreHashNode(autoTypeInfo);
847  h->setKeyValue("event", QORE_EVENT_DATA_WRITTEN, 0);
848  h->setKeyValue("source", QORE_SOURCE_FILE, 0);
849  h->setKeyValue("id", (int64)this, 0);
850  h->setKeyValue("written", bytes_written, 0);
851  h->setKeyValue("total_written", total_written, 0);
852  h->setKeyValue("total_to_write", bufsize, 0);
853  cb_queue->pushAndTakeRef(h);
854  }
855  }
856 
857  DLLLOCAL QoreListNode* stat(ExceptionSink* xsink) const {
858  AutoLocker al(m);
859 
860  if (check_read_open(xsink))
861  return 0;
862 
863  hashdecl stat sbuf;
864  if (fstat(fd, &sbuf)) {
865  xsink->raiseErrnoException("FILE-STAT-ERROR", errno, "fstat() call failed");
866  return 0;
867  }
868 
869  return stat_to_list(sbuf);
870  }
871 
872  DLLLOCAL QoreHashNode* hstat(ExceptionSink* xsink) const {
873  AutoLocker al(m);
874 
875  if (check_read_open(xsink))
876  return 0;
877 
878  hashdecl stat sbuf;
879  if (fstat(fd, &sbuf)) {
880  xsink->raiseErrnoException("FILE-HSTAT-ERROR", errno, "fstat() call failed");
881  return 0;
882  }
883 
884  return stat_to_hash(sbuf);
885  }
886 
887 #ifdef Q_HAVE_STATVFS
888  DLLLOCAL QoreHashNode* statvfs(ExceptionSink* xsink) const {
889  AutoLocker al(m);
890 
891  if (check_read_open(xsink))
892  return 0;
893 
894  hashdecl statvfs vfs;
895 #ifdef HAVE_SYS_STATVFS_H
896  if (fstatvfs(fd, &vfs)) {
897  xsink->raiseErrnoException("FILE-STATVFS-ERROR", errno, "fstatvfs() call failed");
898  return 0;
899  }
900 #else
901  if (q_fstatvfs(filename.c_str(), &vfs)) {
902  xsink->raiseErrnoException("FILE-STATVFS-ERROR", errno, "fstatvfs() call failed");
903  return 0;
904  }
905 #endif
906 
907  return statvfs_to_hash(vfs);
908  }
909 #endif
910 };
911 
912 #endif
defines string encoding functions in Qore
Definition: QoreEncoding.h:83
DLLEXPORT bool empty() const
returns true if the string is empty, false if not
This is the hash or associative list container type in Qore, dynamically allocated only...
Definition: QoreHashNode.h:50
DLLEXPORT const QoreEncoding * QCS_UTF16
UTF-16 (only UTF-8 and UTF-16* are multi-byte encodings)
DLLEXPORT int setKeyValue(const char *key, QoreValue value, ExceptionSink *xsink)
sets the value of "key" to "value"
size_t qore_size_t
used for sizes (same range as a pointer)
Definition: common.h:73
DLLEXPORT AbstractQoreNode * raiseException(const char *err, const char *fmt,...)
appends a Qore-language exception to the list
DLLEXPORT AbstractQoreNode * raiseErrnoException(const char *err, int en, const char *fmt,...)
appends a Qore-language exception to the list and appends the result of strerror(errno) to the descri...
Qore&#39;s string type supported by the QoreEncoding class.
Definition: QoreString.h:81
Qore&#39;s string value type, reference counted, dynamically-allocated only.
Definition: QoreStringNode.h:50
DLLEXPORT const char * getBuffer() const
returns the string&#39;s buffer; this data should not be changed
DLLEXPORT void concat(const QoreString *str, ExceptionSink *xsink)
concatenates a string and converts encodings if necessary
provides a safe and exception-safe way to hold locks in Qore, only to be used on the stack...
Definition: QoreThreadLock.h:128
This is the list container type in Qore, dynamically allocated only, reference counted.
Definition: QoreListNode.h:52
DLLEXPORT qore_size_t strlen() const
returns number of bytes in the string (not including the null pointer)
DLLEXPORT const char * getCode() const
returns the string code (ex: "UTF-8") for the encoding
container for holding Qore-language exception information and also for registering a "thread_exit" ca...
Definition: ExceptionSink.h:46
long long int64
64bit integer type, cannot use int64_t here since it breaks the API on some 64-bit systems due to equ...
Definition: common.h:260
DLLEXPORT void terminate(qore_size_t size)
terminates the string at byte position "size", the string is reallocated if necessary ...
intptr_t qore_offset_t
used for offsets that could be negative
Definition: common.h:76
DLLEXPORT int concatUnicode(unsigned code, ExceptionSink *xsink)
append a character sequence from a unicode code point (returns 0 for OK, -1 for exception) ...
provides a mutually-exclusive thread lock
Definition: QoreThreadLock.h:47
DLLEXPORT const QoreEncoding * QCS_UTF16LE
UTF-16LE (only UTF-8 and UTF-16* are multi-byte encodings)
DLLEXPORT void clear()
reset string to zero length; memory is not deallocated; string encoding does not change ...
DLLEXPORT qore_size_t size() const
returns number of bytes in the string (not including the null pointer)