Merge branch 'u2_10_12_branch' of git://git.code.sf.net/p/undernet-ircu/ircu2
[ircu2.10.12-pk.git] / ircd / fileio.c
diff --git a/ircd/fileio.c b/ircd/fileio.c
new file mode 100644 (file)
index 0000000..af225c5
--- /dev/null
@@ -0,0 +1,238 @@
+/*
+ * IRC - Internet Relay Chat, ircd/fileio.c
+ * Copyright (C) 1998 Thomas Helvey <tomh@inxpress.net>
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                  University of Oulu, Co Center
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/** @file
+ * @brief ANSI FILE* clone API implementation.
+ * @version $Id$
+ */
+#include "config.h"
+
+#include "fileio.h"
+#include "ircd_alloc.h"         /* MyMalloc, MyFree */
+#include "ircd_log.h"           /* assert */
+
+/* #include <assert.h> -- Now using assert in ircd_log.h */       /* assert */
+#include <fcntl.h>              /* O_RDONLY, O_WRONLY, ... */
+#include <stdio.h>              /* BUFSIZ, EOF */
+#include <sys/stat.h>           /* struct stat */
+#include <unistd.h>             /* read, write, open, close */
+#include <string.h>
+
+#define FB_EOF  0x01            /**< File has reached EOF. */
+#define FB_FAIL 0x02            /**< File operation failed. */
+
+/** Tracks status and buffer for a file on disk. */
+struct FileBuf {
+  int fd;                       /**< file descriptor */
+  char *endp;                   /**< one past the end */
+  char *ptr;                    /**< current read pos */
+  int flags;                    /**< file state */
+  char buf[BUFSIZ];             /**< buffer */
+};
+
+/** Open a new FBFILE.
+ * @param[in] filename Name of file to open.
+ * @param[in] mode fopen()-style mode string.
+ * @return Pointer to newly allocated FBFILE.
+ */
+FBFILE* fbopen(const char *filename, const char *mode)
+{
+  int openmode = 0;
+  int pmode = 0;
+  FBFILE *fb = NULL;
+  int fd;
+  assert(filename);
+  assert(mode);
+
+  while (*mode) {
+    switch (*mode) {
+    case 'r':
+      openmode = O_RDONLY;
+      break;
+    case 'w':
+      openmode = O_WRONLY | O_CREAT | O_TRUNC;
+      pmode = S_IRUSR | S_IWUSR;
+      break;
+    case 'a':
+      openmode = O_WRONLY | O_CREAT | O_APPEND;
+      pmode = S_IRUSR | S_IWUSR;
+      break;
+    case '+':
+      openmode &= ~(O_RDONLY | O_WRONLY);
+      openmode |= O_RDWR;
+      break;
+    default:
+      break;
+    }
+    ++mode;
+  }
+  /*
+   * stop NFS hangs...most systems should be able to open a file in
+   * 3 seconds. -avalon (courtesy of wumpus)
+   */
+  alarm(3);
+  if ((fd = open(filename, openmode, pmode)) == -1) {
+    alarm(0);
+    return fb;
+  }
+  alarm(0);
+
+  if (NULL == (fb = fdbopen(fd, NULL)))
+    close(fd);
+  return fb;
+}
+
+/** Open a FBFILE from a file descriptor.
+ * @param[in] fd File descriptor to use.
+ * @param[in] mode fopen()-style mode string (ignored).
+ */
+FBFILE* fdbopen(int fd, const char *mode)
+{
+  /*
+   * ignore mode, if file descriptor hasn't been opened with the
+   * correct mode, the first use will fail
+   */
+  FBFILE *fb = (FBFILE *) MyMalloc(sizeof(FBFILE));
+  assert(0 != fb);
+  fb->ptr   = fb->endp = fb->buf;
+  fb->fd    = fd;
+  fb->flags = 0;
+
+  return fb;
+}
+
+/** Close a FBFILE.
+ * @param[in] fb File buffer to close.
+ */
+void fbclose(FBFILE* fb)
+{
+  assert(fb);
+  close(fb->fd);
+  MyFree(fb);
+}
+
+/** Attempt to fill a file's buffer.
+ * @param[in] fb File to operate on.
+ * @return Number of bytes read into buffer, or a negative number on error.
+ */
+static int fbfill(FBFILE * fb)
+{
+  int n;
+  assert(fb);
+  if (fb->flags)
+    return -1;
+  n = read(fb->fd, fb->buf, BUFSIZ);
+  if (0 < n)
+  {
+    fb->ptr = fb->buf;
+    fb->endp = fb->buf + n;
+  }
+  else if (n < 0)
+    fb->flags |= FB_FAIL;
+  else
+    fb->flags |= FB_EOF;
+  return n;
+}
+
+/** Get a single character from a file.
+ * @param[in] fb File to fetch from.
+ * @return Character value read, or EOF on error or end-of-file.
+ */
+int fbgetc(FBFILE * fb)
+{
+  assert(fb);
+  if (fb->ptr < fb->endp || fbfill(fb) > 0)
+    return *fb->ptr++;
+  return EOF;
+}
+
+/** Get a line of input from a file.
+ * @param[out] buf Output buffer to read to.
+ * @param[in] len Maximum number of bytes to write to buffer
+ * (including terminating NUL).
+ * @param[in] fb File to read from.
+ */
+char *fbgets(char *buf, size_t len, FBFILE * fb)
+{
+  char *p = buf;
+  assert(buf);
+  assert(fb);
+  assert(0 < len);
+
+  if (fb->ptr == fb->endp && fbfill(fb) < 1)
+    return 0;
+  --len;
+  while (len--) {
+    *p = *fb->ptr++;
+    if ('\n' == *p)
+    {
+      ++p;
+      break;
+    }
+    /*
+     * deal with CR's
+     */
+    else if ('\r' == *p) {
+      if (fb->ptr < fb->endp || fbfill(fb) > 0) {
+        if ('\n' == *fb->ptr)
+          ++fb->ptr;
+      }
+      *p++ = '\n';
+      break;
+    }
+    ++p;
+    if (fb->ptr == fb->endp && fbfill(fb) < 1)
+      break;
+  }
+  *p = '\0';
+  return buf;
+}
+
+/** Write a string to a file.
+ * @param[in] str String to write to file.
+ * @param[in] fb File to write to.
+ * @return Number of bytes written, or -1 on error.
+ */
+int fbputs(const char *str, FBFILE * fb)
+{
+  int n = -1;
+  assert(str);
+  assert(fb);
+
+  if (0 == fb->flags) {
+    n = write(fb->fd, str, strlen(str));
+    if (-1 == n)
+      fb->flags |= FB_FAIL;
+  }
+  return n;
+}
+
+/** Get file status.
+ * @param[out] sb Receives file status.
+ * @param[in] fb File to get status for.
+ * @return Zero on success, -1 on error.
+ */
+int fbstat(struct stat *sb, FBFILE * fb)
+{
+  assert(sb);
+  assert(fb);
+  return fstat(fb->fd, sb);
+}
+