aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--acconfig.h6
-rw-r--r--acinclude.m4200
-rw-r--r--lib/Makefile.am3
-rw-r--r--lib/bool.h20
-rw-r--r--lib/bufferarray.cc68
-rw-r--r--lib/bufferarray.h25
-rw-r--r--lib/bufferstore.cc166
-rw-r--r--lib/bufferstore.h50
-rw-r--r--lib/iowatch.cc77
-rw-r--r--lib/iowatch.h21
-rw-r--r--lib/ppsocket.cc863
-rw-r--r--lib/ppsocket.h117
-rw-r--r--plpnfsd/Makefile.am9
-rw-r--r--plpnfsd/main.cc215
-rw-r--r--plpnfsd/mount_aix.c170
-rw-r--r--plpnfsd/mp_inode.c325
-rw-r--r--plpnfsd/mp_main.c147
-rw-r--r--plpnfsd/mp_mount.c601
-rw-r--r--plpnfsd/mp_pfs_ops.c1040
-rw-r--r--plpnfsd/mtab_aix.c145
-rw-r--r--plpnfsd/nfs_prot_svc.c231
-rw-r--r--plpnfsd/nfs_prot_xdr.c518
-rw-r--r--plpnfsd/rfsv32.cc889
-rw-r--r--plpnfsd/rfsv32.h172
-rw-r--r--plpnfsd/rfsv_api.h29
25 files changed, 6107 insertions, 0 deletions
diff --git a/acconfig.h b/acconfig.h
new file mode 100644
index 0000000..298dea7
--- /dev/null
+++ b/acconfig.h
@@ -0,0 +1,6 @@
+/* Define if the C++ compiler supports BOOL */
+#undef HAVE_BOOL
+
+#undef VERSION
+
+#undef PACKAGE
diff --git a/acinclude.m4 b/acinclude.m4
new file mode 100644
index 0000000..d406121
--- /dev/null
+++ b/acinclude.m4
@@ -0,0 +1,200 @@
+AC_DEFUN(AC_FIND_FILE,
+[
+$2=NO
+for i in $1; do
+ if test -r "$i" ; then
+ $2=$i
+ break 2
+ fi
+done
+])
+
+AC_DEFUN(AC_FIND_CDEV,
+[
+$2=NO
+for i in $1; do
+ if test -c "$i" ; then
+ $2=$i
+ break 2
+ fi
+done
+])
+
+AC_DEFUN(AC_CHECK_COMPILERS,
+[
+ dnl this is somehow a fat lie, but prevents other macros from double checking
+ AC_PROVIDE([AC_PROG_CC])
+ AC_PROVIDE([AC_PROG_CPP])
+ AC_ARG_ENABLE(debug,[ --enable-debug creates debugging code [default=no]],
+ [
+ if test $enableval = "no"; dnl
+ then ac_use_debug_code="no"
+ else ac_use_debug_code="yes"
+ fi
+ ], [ac_use_debug_code="no"])
+
+ AC_ARG_ENABLE(strict,[ --enable-strict compiles with strict compiler options (may not work!)],
+ [
+ if test $enableval = "no"; then
+ ac_use_strict_options="no"
+ else
+ ac_use_strict_options="yes"
+ fi
+ ], [ac_use_strict_options="no"])
+
+dnl this was AC_PROG_CC. I had to include it manualy, since I had to patch it
+ AC_MSG_CHECKING(for a C-Compiler)
+ dnl if there is one, print out. if not, don't matter
+ AC_MSG_RESULT($CC)
+
+ if test -z "$CC"; then AC_CHECK_PROG(CC, gcc, gcc) fi
+ if test -z "$CC"; then AC_CHECK_PROG(CC, cc, cc, , , /usr/ucb/cc) fi
+ if test -z "$CC"; then AC_CHECK_PROG(CC, xlc, xlc) fi
+ test -z "$CC" && AC_MSG_ERROR([no acceptable cc found in \$PATH])
+
+ AC_PROG_CC_WORKS
+ AC_PROG_CC_GNU
+
+ if test $ac_cv_prog_gcc = yes; then
+ GCC=yes
+ else
+ GCC=
+ fi
+
+ if test -z "$CFLAGS"; then
+ if test "$ac_use_debug_code" = "yes"; then
+ AC_PROG_CC_G
+ if test $ac_cv_prog_cc_g = yes; then
+ CFLAGS="-g"
+ fi
+ else
+ if test "$GCC" = "yes"; then
+ CFLAGS="-O2"
+ else
+ CFLAGS=""
+ fi
+ fi
+
+ if test "$GCC" = "yes"; then
+ CFLAGS="$CFLAGS -Wall"
+
+ if test "$ac_use_strict_options" = "yes"; then
+ CFLAGS="$CFLAGS -W -ansi -pedantic"
+ fi
+ fi
+
+ fi
+
+ case "$host" in
+ *-*-sysv4.2uw*) CFLAGS="$CFLAGS -D_UNIXWARE";;
+ esac
+
+ if test -z "$LDFLAGS" && test "$ac_use_debug_code" = "no" && test "$GCC" = "yes"; then
+ LDFLAGS="-s"
+ fi
+
+
+dnl this is AC_PROG_CPP. I had to include it here, since autoconf checks
+dnl dependecies between AC_PROG_CPP and AC_PROG_CC (or is it automake?)
+
+ AC_MSG_CHECKING(how to run the C preprocessor)
+ # On Suns, sometimes $CPP names a directory.
+ if test -n "$CPP" && test -d "$CPP"; then
+ CPP=
+ fi
+ if test -z "$CPP"; then
+ AC_CACHE_VAL(ac_cv_prog_CPP,
+ [ # This must be in double quotes, not single quotes, because CPP may get
+ # substituted into the Makefile and "${CC-cc}" will confuse make.
+ CPP="${CC-cc} -E"
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp.
+ dnl Use a header file that comes with gcc, so configuring glibc
+ dnl with a fresh cross-compiler works.
+ AC_TRY_CPP([#include <assert.h>
+ Syntax Error], ,
+ CPP="${CC-cc} -E -traditional-cpp"
+ AC_TRY_CPP([#include <assert.h>
+ Syntax Error], , CPP=/lib/cpp))
+ ac_cv_prog_CPP="$CPP"])dnl
+ CPP="$ac_cv_prog_CPP"
+ else
+ ac_cv_prog_CPP="$CPP"
+ fi
+ AC_MSG_RESULT($CPP)
+ AC_SUBST(CPP)dnl
+
+
+ AC_MSG_CHECKING(for a C++-Compiler)
+ dnl if there is one, print out. if not, don't matter
+ AC_MSG_RESULT($CXX)
+
+ if test -z "$CXX"; then AC_CHECK_PROG(CXX, g++, g++) fi
+ if test -z "$CXX"; then AC_CHECK_PROG(CXX, CC, CC) fi
+ if test -z "$CXX"; then AC_CHECK_PROG(CXX, xlC, xlC) fi
+ if test -z "$CXX"; then AC_CHECK_PROG(CXX, DCC, DCC) fi
+ test -z "$CXX" && AC_MSG_ERROR([no acceptable C++-compiler found in \$PATH])
+
+ AC_PROG_CXX_WORKS
+ AC_PROG_CXX_GNU
+
+ if test $ac_cv_prog_gxx = yes; then
+ GXX=yes
+ else
+ AC_MSG_CHECKING(whether we are using SPARC CC)
+ GXX=
+ cat > conftest.C << EOF
+#ifdef __SUNPRO_CC
+ yes;
+#endif
+EOF
+
+ ac_try="$CXX -E conftest.C"
+ if { (eval echo configure:__online__: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } | egrep yes >/dev/null 2>&1; then
+ ac_cv_prog_CC=yes
+ else
+ ac_cv_prog_CC=no
+ fi
+ AC_MSG_RESULT($ac_cv_prog_CC)
+ fi
+
+ if test -z "$CXXFLAGS"; then
+ if test "$ac_use_debug_code" = "yes"; then
+ AC_PROG_CXX_G
+ if test $ac_cv_prog_cxx_g = yes; then
+ CXXFLAGS="-g"
+ fi
+ if test "$ac_cv_prog_CC" = "yes"; then
+ CXXFLAGS="$CXXFLAGS -pto"
+ fi
+ else
+ if test "$GXX" = "yes"; then
+ CXXFLAGS="-O2"
+ else
+ if test "$ac_cv_prog_CC" = "yes"; then
+ CXXFLAGS="-pto -O2"
+ else
+ CXXFLAGS=""
+ fi
+ fi
+ fi
+
+ if test "$GXX" = "yes"; then
+ CXXFLAGS="$CXXFLAGS -Wall"
+
+ if test "$ac_use_strict_options" = "yes"; then
+ CXXFLAGS="$CXXFLAGS -W -ansi -Wtraditional -Wpointer-arith -Wcast-qual -Wcast-align -Wwrite-strings -Woverloaded-virtual -Wbad-function-cast -Wsynth"
+ fi
+
+ if test "$ac_very_strict" = "yes"; then
+ CXXFLAGS="$CXXFLAGS -Wold-style-cast -Wshadow -Wredundant-decls -Wconversion"
+ fi
+ fi
+ fi
+
+ case "$host" in
+ *-*-sysv4.2uw*) CXXFLAGS="$CXXFLAGS -D_UNIXWARE";;
+ esac
+
+])
+
diff --git a/lib/Makefile.am b/lib/Makefile.am
new file mode 100644
index 0000000..ec2faee
--- /dev/null
+++ b/lib/Makefile.am
@@ -0,0 +1,3 @@
+noinst_LIBRARIES = libutils.a
+
+libutils_a_SOURCES = bufferarray.cc bufferstore.cc iowatch.cc ppsocket.cc
diff --git a/lib/bool.h b/lib/bool.h
new file mode 100644
index 0000000..7525d6c
--- /dev/null
+++ b/lib/bool.h
@@ -0,0 +1,20 @@
+#ifndef _bool_h_
+#define _bool_h_
+
+#ifndef __GNUC__
+
+#ifndef bool
+#define bool int
+#endif
+
+#ifndef true
+#define true 1
+#endif
+
+#ifndef false
+#define false 0
+#endif
+
+#endif
+
+#endif
diff --git a/lib/bufferarray.cc b/lib/bufferarray.cc
new file mode 100644
index 0000000..4dc3971
--- /dev/null
+++ b/lib/bufferarray.cc
@@ -0,0 +1,68 @@
+//
+// PLP - An implementation of the PSION link protocol
+//
+// Copyright (C) 1999 Philip Proudman
+//
+// 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 2 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 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// e-mail philip.proudman@btinternet.com
+
+
+#include <stdio.h>
+
+#include "bufferstore.h"
+#include "bufferarray.h"
+
+bufferArray::bufferArray() {
+ len = 0;
+ lenAllocd = 5;
+ buff = new bufferStore [lenAllocd];
+}
+
+bufferArray::bufferArray(const bufferArray &a) {
+ len = a.len;
+ lenAllocd = a.lenAllocd;
+ buff = new bufferStore [lenAllocd];
+ for (int i=0; i < len; i++) buff[i] = a.buff[i];
+}
+
+bufferArray::~bufferArray() {
+ delete [] buff;
+}
+
+bufferStore bufferArray::popBuffer() {
+ bufferStore ret;
+ if (len > 0) {
+ ret = buff[0];
+ len--;
+ for (long i=0; i<len; i++) {
+ buff[i] = buff[i+1];
+ }
+ }
+ return ret;
+}
+
+void bufferArray::pushBuffer(const bufferStore &b) {
+ if (len == lenAllocd) {
+ lenAllocd += 5;
+ bufferStore* nb = new bufferStore [lenAllocd];
+ for (long i=0; i<len; i++) {
+ nb[i] = buff[i];
+ }
+ delete [] buff;
+ buff = nb;
+ }
+ buff[len++] = b;
+}
diff --git a/lib/bufferarray.h b/lib/bufferarray.h
new file mode 100644
index 0000000..089eb4e
--- /dev/null
+++ b/lib/bufferarray.h
@@ -0,0 +1,25 @@
+#ifndef _bufferarray_h
+#define _bufferarray_h
+
+#include "bool.h"
+class bufferStore;
+
+class bufferArray {
+public:
+ bufferArray();
+ bufferArray(const bufferArray &a);
+ ~bufferArray();
+ void operator =(const bufferArray &a);
+
+ bool empty() const;
+ bufferStore popBuffer();
+ void pushBuffer(const bufferStore& b);
+private:
+ long len;
+ long lenAllocd;
+ bufferStore* buff;
+};
+
+inline bool bufferArray::empty() const { return len == 0; }
+
+#endif
diff --git a/lib/bufferstore.cc b/lib/bufferstore.cc
new file mode 100644
index 0000000..8138ad2
--- /dev/null
+++ b/lib/bufferstore.cc
@@ -0,0 +1,166 @@
+//
+// PLP - An implementation of the PSION link protocol
+//
+// Copyright (C) 1999 Philip Proudman
+//
+// 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 2 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 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// e-mail philip.proudman@btinternet.com
+
+#include <stream.h>
+#include <iomanip.h>
+#include <string.h>
+
+#include "bufferstore.h"
+
+bufferStore::bufferStore() {
+ lenAllocd = 0;
+ buff = NULL;
+ len = 0;
+ start = 0;
+}
+
+bufferStore::bufferStore(const bufferStore &a) {
+ lenAllocd = (a.getLen() > MIN_LEN) ? a.getLen() : MIN_LEN;
+ buff = new unsigned char [lenAllocd];
+ len = a.getLen();
+ for (long i=0; i<len; i++) buff[i] = a.getByte(i);
+ start = 0;
+}
+
+bufferStore::bufferStore(const unsigned char*_buff, long _len) {
+ lenAllocd = (_len > MIN_LEN) ? _len : MIN_LEN;
+ buff = new unsigned char [lenAllocd];
+ len = _len;
+ for (long i=0; i<len; i++) buff[i] = _buff[i];
+ start = 0;
+}
+
+void bufferStore::operator =(const bufferStore &a) {
+ checkAllocd(a.getLen());
+ len = a.getLen();
+ for (long i=0; i<len; i++) buff[i] = a.getByte(i);
+ start = 0;
+}
+
+void bufferStore::init() {
+ start = 0;
+ len = 0;
+}
+
+void bufferStore::init(const unsigned char*_buff, long _len) {
+ checkAllocd(_len);
+ start = 0;
+ len = _len;
+ for (long i=0; i<len; i++) buff[i] = _buff[i];
+}
+
+bufferStore::~bufferStore() {
+ delete [] buff;
+}
+
+unsigned long bufferStore::getLen() const {
+ if (start > len) return 0;
+ return len - start;
+}
+
+unsigned char bufferStore::getByte(long pos) const {
+ return buff[pos+start];
+}
+
+unsigned int bufferStore::getWord(long pos) const {
+ return buff[pos+start] + (buff[pos+start+1] << 8);
+}
+
+unsigned int bufferStore::getDWord(long pos) const {
+ return buff[pos+start] +
+ (buff[pos+start+1] << 8) +
+ (buff[pos+start+2] << 16) +
+ (buff[pos+start+3] << 24);
+}
+
+const char* bufferStore::getString(long pos) const {
+ return (const char*)buff+pos+start;
+}
+
+ostream &operator<<(ostream &s, const bufferStore &m) {
+ {
+ for (int i = m.start; i < m.len; i++)
+ s << hex << setw(2) << setfill('0') << (int)m.buff[i] << " ";
+ }
+ s << "(";
+ {
+ for (int i = m.start; i < m.len; i++) {
+ unsigned char c = m.buff[i];
+ if (c>=' ' && c <= 'z') s << c;
+ }
+ }
+ s<< ")";
+ return s;
+}
+
+void bufferStore::discardFirstBytes(int n) {
+ start += n;
+ if (start > len) start = len;
+}
+
+void bufferStore::checkAllocd(long newLen) {
+ if (newLen >= lenAllocd) {
+ do {
+ if (lenAllocd < MIN_LEN)
+ lenAllocd = MIN_LEN;
+ else
+ lenAllocd *= 2;
+ } while (newLen >= lenAllocd);
+ unsigned char* newBuff = new unsigned char [lenAllocd];
+ for (int i=start; i<len; i++) newBuff[i] = buff[i];
+ delete [] buff;
+ buff = newBuff;
+ }
+}
+
+void bufferStore::addByte(unsigned char cc) {
+ checkAllocd(len + 1);
+ buff[len++] = cc;
+}
+
+void bufferStore::addString(const char* s) {
+ checkAllocd(len + strlen(s));
+ for (int i=0; s[i]; i++) buff[len++] = s[i];
+}
+
+void bufferStore::addStringT(const char* s) {
+ addString(s);
+ addByte(0);
+}
+
+void bufferStore::addBuff(const bufferStore &s, long maxLen) {
+ checkAllocd(len + s.getLen());
+ for (unsigned long i=0; i < s.getLen() && (maxLen < 0 || i < (unsigned long)maxLen); i++) buff[len++] = s.getByte(i);
+}
+
+void bufferStore::addWord(int a) {
+ checkAllocd(len + 2);
+ buff[len++] = a & 0xff;
+ buff[len++] = (a>>8) & 0xff;
+}
+
+void bufferStore::addDWord(long a) {
+ checkAllocd(len + 4);
+ buff[len++] = a & 0xff;
+ buff[len++] = (a>>8) & 0xff;
+ buff[len++] = (a>>16) & 0xff;
+ buff[len++] = (a>>24) & 0xff;
+}
diff --git a/lib/bufferstore.h b/lib/bufferstore.h
new file mode 100644
index 0000000..4840689
--- /dev/null
+++ b/lib/bufferstore.h
@@ -0,0 +1,50 @@
+#ifndef _bufferstore_h
+#define _bufferstore_h
+
+#include "bool.h"
+class ostream;
+
+class bufferStore {
+public:
+ bufferStore();
+ bufferStore(const unsigned char*buff, long len);
+ ~bufferStore();
+ bufferStore(const bufferStore &a);
+ void operator =(const bufferStore &a);
+
+ // Reading Utils
+ unsigned long getLen() const;
+ unsigned char getByte(long pos) const;
+ unsigned int getWord(long pos) const;
+ unsigned int getDWord(long pos) const;
+ const char* getString(long pos=0) const;
+ void discardFirstBytes(int n);
+ friend ostream &operator<<(ostream &s, const bufferStore &m);
+ bool empty() const;
+
+ // Writing utils
+ void init();
+ void init(const unsigned char*buff, long len);
+ void addByte(unsigned char c);
+ void addWord(int a);
+ void addDWord(long a);
+ void addString(const char* s);
+ void addStringT(const char* s);
+ void addBuff(const bufferStore &s, long maxLen=-1);
+
+private:
+ void checkAllocd(long newLen);
+
+ long len;
+ long lenAllocd;
+ long start;
+ unsigned char* buff;
+
+ enum c { MIN_LEN = 300 };
+};
+
+inline bool bufferStore::empty() const {
+ return (len-start) == 0;
+}
+
+#endif
diff --git a/lib/iowatch.cc b/lib/iowatch.cc
new file mode 100644
index 0000000..15e8ecf
--- /dev/null
+++ b/lib/iowatch.cc
@@ -0,0 +1,77 @@
+//
+// PLP - An implementation of the PSION link protocol
+//
+// Copyright (C) 1999 Philip Proudman
+//
+// 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 2 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 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// e-mail philip.proudman@btinternet.com
+
+#include <unistd.h>
+#include <stdio.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <stream.h>
+#include <memory.h>
+
+#include "bool.h"
+#include "iowatch.h"
+
+IOWatch::IOWatch() {
+ num = 0;
+ io = new int [MAX_IO];
+}
+
+IOWatch::~IOWatch() {
+ delete [] io;
+}
+
+void IOWatch::addIO(int a) {
+ int pos;
+ for (pos = 0; pos < num && a < io[pos]; pos++);
+ for (int i = num; i > pos; i--) io[i] = io[i-1];
+ io[pos] = a;
+ num++;
+}
+
+void IOWatch::remIO(int a) {
+ int pos;
+ for (pos = 0; pos < num && a != io[pos]; pos++);
+ if (pos != num) {
+ num--;
+ for (int i = pos; i <num; i++) io[i] = io[i+1];
+ }
+}
+
+bool IOWatch::watch(long secs, long usecs) {
+ if (num > 0) {
+ fd_set iop;
+ FD_ZERO(&iop);
+ for (int i=0; i<num; i++) {
+ FD_SET(io[i], &iop);
+ }
+ struct timeval t;
+ t.tv_usec = usecs;
+ t.tv_sec = secs;
+ return select(io[0]+1, &iop, NULL, NULL, &t);
+ }
+ else {
+ sleep(secs);
+ usleep(usecs);
+ }
+ return false;
+}
+
+
diff --git a/lib/iowatch.h b/lib/iowatch.h
new file mode 100644
index 0000000..18c0d44
--- /dev/null
+++ b/lib/iowatch.h
@@ -0,0 +1,21 @@
+#ifndef _iowatch_h
+#define _iowatch_h
+
+#include "bool.h"
+
+class IOWatch {
+public:
+ IOWatch();
+ ~IOWatch();
+
+ void addIO(int a);
+ void remIO(int a);
+ bool watch(long secs, long usecs);
+private:
+
+ enum consts { MAX_IO = 20 };
+ int *io;
+ int num;
+};
+
+#endif
diff --git a/lib/ppsocket.cc b/lib/ppsocket.cc
new file mode 100644
index 0000000..c9ef495
--- /dev/null
+++ b/lib/ppsocket.cc
@@ -0,0 +1,863 @@
+//
+// PLP - An implementation of the PSION link protocol
+//
+// Copyright (C) 1999 Philip Proudman
+//
+// 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 2 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 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// e-mail philip.proudman@btinternet.com
+
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <iostream.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+
+#include "../defaults.h"
+#include "bool.h"
+#include "bufferstore.h"
+#include "ppsocket.h"
+
+//**********************************************************************
+// For unix we need a few definitions
+//**********************************************************************
+
+#ifndef MAKEWORD
+#define MAKEWORD(a, b) ((WORD)(((BYTE)(a)) | ((WORD)((BYTE)(b))) << 8))
+#endif
+#ifndef SHORT
+#define SHORT int
+#endif
+
+//This constructor is useful when converting a socket
+//to a derived class of socket
+ppsocket::ppsocket(const ppsocket& another)
+{
+ m_Socket = another.m_Socket;
+ m_HostAddr = another.m_HostAddr;
+ m_PeerAddr = another.m_PeerAddr;
+ m_Bound = another.m_Bound;
+ m_Timeout = another.m_Timeout;
+ m_LastError = another.m_LastError;
+
+ m_Timeout = INFINITE;
+}
+
+
+ppsocket::ppsocket()
+{
+ m_Socket = INVALID_SOCKET;
+
+ memset(&m_HostAddr, 0, sizeof(m_HostAddr));
+ memset(&m_PeerAddr, 0, sizeof(m_PeerAddr));
+
+
+ ((struct sockaddr_in*) &m_HostAddr)->sin_family = AF_INET;
+ ((struct sockaddr_in*) &m_PeerAddr)->sin_family = AF_INET;
+
+ m_Bound = false;
+
+ m_Timeout = INFINITE;
+}
+
+
+ppsocket::~ppsocket()
+{
+ if (m_Socket != INVALID_SOCKET)
+ {
+ close(m_Socket);
+ }
+}
+
+
+bool ppsocket::startup(void)
+{
+#ifdef WIN32
+ WSADATA wd;
+ m_LastError = WSAStartup(MAKEWORD(1, 1), &wd);
+#else
+ m_LastError = 0;
+#endif
+
+ return(m_LastError == 0 ? true : false);
+}
+
+//pre : must be bound and peer info set
+bool ppsocket::reconnect()
+{
+ printPeer();
+ if (::connect(m_Socket, &m_PeerAddr, sizeof(m_PeerAddr)) != 0)
+ {
+ m_LastError = lastErrorCode();
+ cout << "Reconnect failed : status : " << m_LastError << endl << flush;
+ return(false);
+ }
+ return(true);
+}
+
+
+void ppsocket::printPeer()
+{
+ char* pPeer = 0;
+ int port;
+
+ pPeer = inet_ntoa(((struct sockaddr_in*) &m_PeerAddr)->sin_addr);
+ if (pPeer)
+ {
+ port = ntohs(((struct sockaddr_in*) &m_PeerAddr)->sin_port);
+ cout << "Peer : " << pPeer << " Port : " << port << endl;
+ }
+ else
+ {
+ cout << "Error getting Peer details\n";
+ }
+}
+
+bool ppsocket::connect(char* Peer, int PeerPort, char* Host, int HostPort)
+{
+
+ //****************************************************
+ //* If we aren't already bound set the host and bind *
+ //****************************************************
+
+ if (!bindSocket(Host, HostPort))
+ {
+ if (m_LastError != 0)
+ {
+ return(false);
+ }
+ }
+
+ //****************
+ //* Set the peer *
+ //****************
+ if (!setPeer(Peer, PeerPort))
+ {
+ return(false);
+ }
+
+ //***********
+ //* Connect *
+ //***********
+ if (::connect(m_Socket, &m_PeerAddr, sizeof(m_PeerAddr)) != 0)
+ {
+ m_LastError = lastErrorCode();
+ return(false);
+ }
+
+ return(true);
+}
+
+
+
+bool ppsocket::listen(char* Host, int Port)
+{
+ //****************************************************
+ //* If we aren't already bound set the host and bind *
+ //****************************************************
+
+ if (!bindSocket(Host, Port))
+ {
+ if (m_LastError != 0)
+ {
+ return(false);
+ }
+ }
+
+ //**********************
+ //* Listen on the port *
+ //**********************
+
+ if (::listen(m_Socket, 5) != 0)
+ {
+ m_LastError = lastErrorCode();
+ return(false);
+ }
+
+ return(true);
+}
+
+
+ppsocket* ppsocket::accept(char* Peer, int MaxLen)
+{
+ unsigned int len;
+ ppsocket* accepted;
+ char* peer;
+
+ //*****************************************************
+ //* Allocate a new object to hold the accepted socket *
+ //*****************************************************
+
+ accepted = new ppsocket;
+
+ if (!accepted)
+ {
+ m_LastError = lastErrorCode();
+ return(NULL);
+ }
+
+ //***********************
+ //* Accept a connection *
+ //***********************
+
+ len = sizeof(struct sockaddr);
+ fcntl(m_Socket, F_SETFL, O_NONBLOCK);
+ accepted->m_Socket = ::accept(m_Socket, &accepted->m_PeerAddr, &len);
+
+ if (accepted->m_Socket == INVALID_SOCKET)
+ {
+ m_LastError = lastErrorCode();
+ delete accepted;
+ return (NULL);
+ }
+
+ //****************************************************
+ //* Got a connection so fill in the other attributes *
+ //****************************************************
+
+ accepted->m_HostAddr = m_HostAddr;
+ accepted->m_Bound = true;
+
+ //****************************************************
+ //* If required get the name of the connected client *
+ //****************************************************
+
+ if (Peer)
+ {
+ peer = inet_ntoa(((struct sockaddr_in*) &accepted->m_PeerAddr)->sin_addr);
+ if (peer)
+ {
+ strncpy(Peer, peer, MaxLen);
+ Peer[MaxLen] = '\0';
+ }
+ }
+ else
+ {
+ strcpy(Peer, "");
+ }
+
+ return(accepted);
+}
+
+
+int ppsocket::printf(const char* Format, ...)
+{ int i;
+va_list ap;
+char s[512];
+
+va_start(ap, Format);
+vsprintf(s, Format, ap);
+va_end(ap);
+
+i = writeTimeout(s, strlen(s), 0);
+
+return(i);
+}
+
+bool ppsocket::dataToGet() const {
+ fd_set io;
+ FD_ZERO(&io);
+ FD_SET(m_Socket, &io);
+ struct timeval t;
+ t.tv_usec = 0;
+ t.tv_sec = 0;
+ return (select(m_Socket+1, &io, NULL, NULL, &t) != 0) ? true : false;
+}
+
+int ppsocket::getBufferStore(bufferStore &a, bool wait) {
+ /* Returns a 0 for for no message, 1 for message OK, and -1 for socket problem */
+ if (!wait && !dataToGet()) return 0;
+ a.init();
+ bool hadEscape = false;
+ do {
+ char data;
+ int j = readTimeout(&data, 1, 0);
+ if (j == SOCKET_ERROR || j == 0) {
+ return -1;
+ }
+ if (hadEscape) {
+ a.addByte(data);
+ hadEscape = false;
+ }
+ else {
+ if (data == '\\')
+ hadEscape = true;
+ else if (data == '\0')
+ break;
+ else
+ a.addByte(data);
+ }
+ } while (true);
+#ifdef SOCKET_DIAGNOSTICS
+ cout << "ppsocket got " << a << endl;
+#endif
+ return (a.getLen() == 0) ? 0 : 1;
+}
+
+bool ppsocket::sendBufferStore(const bufferStore &a) {
+#ifdef SOCKET_DIAGNOSTICS
+ cout << "ppsocket sending " << a << endl;
+#endif
+ bufferStore s;
+ long l = a.getLen();
+ for (long i = 0; i<l; i++) {
+ unsigned char cc = a.getByte(i);
+ if (cc == '\0' || cc == '\\') {
+ s.addByte('\\');
+ }
+ s.addByte(cc);
+ }
+ s.addByte('\0');
+
+ {
+ int tosend, sent, retries, i;
+
+ tosend = s.getLen();
+ sent = retries = 0;
+
+ while (tosend > 0)
+ {
+ i = writeTimeout(s.getString(sent), tosend, 0);
+
+ if (i == SOCKET_ERROR || i == 0)
+ return( false);
+
+ sent += i;
+ tosend -= i;
+
+ if (++retries > 5)
+ {
+ m_LastError = 0;
+ return(false);
+ }
+ }
+ }
+ return true;
+}
+
+int ppsocket::readEx(char* Data, int cTerm, int MaxLen)
+{
+ int i, j;
+
+ for (i = 0; i < MaxLen; i++)
+ {
+ j = readTimeout(Data + i, 1, 0);
+
+ if (j == SOCKET_ERROR || j == 0)
+ {
+ Data[i] = '\0';
+ return(i > 0 ? i : 0);
+ }
+
+ if (Data[i] == cTerm)
+ break;
+ }
+
+ return(i+1);
+}
+
+bool ppsocket::puts(const char* Data)
+{
+ int tosend, sent, retries, i;
+
+ tosend = strlen(Data);
+ sent = retries = 0;
+
+ while (tosend > 0)
+ {
+ i = writeTimeout(Data + sent, tosend, 0);
+
+ if (i == SOCKET_ERROR || i == 0)
+ return(sent > 0 ? true : false);
+
+ sent += i;
+ tosend -= i;
+
+ if (++retries > 5)
+ {
+ m_LastError = 0;
+ return(false);
+ }
+ }
+
+ return(true);
+}
+
+
+
+char ppsocket::sgetc(void)
+{
+ int i;
+ char c;
+
+ i = readTimeout(&c, 1, 0);
+ if (i == SOCKET_ERROR || i == 0)
+ {
+ return(0);
+ }
+ return(c);
+}
+
+
+bool ppsocket::sputc(char c)
+{
+ int i;
+
+ cout << hex << (int)c << endl;
+
+ i = writeTimeout(&c, 1, 0);
+
+ if (i == SOCKET_ERROR || i == 0)
+ {
+ return(false);
+ }
+
+ return(true);
+}
+
+
+int ppsocket::read(void* Data, size_t Size, size_t NumObj)
+{
+ int i = readTimeout((char*) Data, Size*NumObj, 0);
+
+ return(i);
+}
+
+
+int ppsocket::write(const void* Data, size_t Size, size_t NumObj)
+{
+ int i = writeTimeout((char*) Data, Size*NumObj, 0);
+
+ return(i);
+}
+
+
+int ppsocket::recv(char* buf, int len, int flags)
+{
+ int i = ::recv(m_Socket, buf, len, flags);
+
+ if (i < 0)
+ m_LastError = lastErrorCode();
+
+ return(i);
+}
+
+
+int ppsocket::send(const char* buf, int len, int flags)
+{
+ int i = ::send(m_Socket, buf, len, flags);
+
+ if (i < 0)
+ m_LastError = lastErrorCode();
+
+ return(i);
+}
+
+
+int ppsocket::readTimeout(char* buf, int len, int flags)
+{
+ int i;
+
+ //*********************************************************
+ //* If there is no timeout use the Berkeley recv function *
+ //*********************************************************
+
+ if (m_Timeout == INFINITE)
+ {
+ i = ::recv(m_Socket, buf, len, flags);
+
+ if (i == SOCKET_ERROR)
+ {
+ m_LastError = lastErrorCode();
+ }
+ }
+
+ //********************************************
+ //* If there is a timeout use overlapped i/o *
+ //********************************************
+
+ else
+ {
+ i = SOCKET_ERROR;
+ }
+
+
+ return(i);
+}
+
+
+int ppsocket::writeTimeout(const char* buf, int len, int flags)
+{
+ int i;
+ // If there is no timeout use the Berkeley send function
+
+ if (m_Timeout == INFINITE)
+ {
+ i = ::send(m_Socket, buf, len, flags);
+
+ if (i == SOCKET_ERROR)
+ {
+ m_LastError = lastErrorCode();
+ }
+ }
+ else
+ {
+ // If there is a timeout use overlapped i/o
+ i = SOCKET_ERROR;
+ }
+
+ return(i);
+}
+
+bool ppsocket::closeSocket(void)
+{
+ if (close(m_Socket) != 0)
+ {
+ m_LastError = lastErrorCode();
+ return(false);
+ }
+
+ m_Socket = INVALID_SOCKET;
+
+ return(true);
+}
+
+
+bool ppsocket::bindSocket(char* Host, int Port)
+{
+
+ // If we are already bound return FALSE but with no last error
+
+ m_LastError = 0;
+
+ if (m_Bound)
+ {
+ return(false);
+ }
+
+ // If the socket hasn't been created create it now
+
+ if (m_Socket == INVALID_SOCKET)
+ {
+ if (!createSocket())
+ {
+ return(false);
+ }
+ }
+
+ // If a host name was supplied then use it
+ if (!setHost(Host, Port))
+ {
+ return(false);
+ }
+
+ // Now bind the socket
+ if (::bind(m_Socket, &m_HostAddr, sizeof(m_HostAddr)) != 0)
+ {
+ m_LastError = lastErrorCode();
+ return(false);
+ }
+
+ m_Bound = true;
+
+ return(true);
+}
+
+
+bool ppsocket::bindInRange(char* Host, int Low, int High, int Retries)
+{
+ int port, i;
+
+ // If we are already bound return FALSE but with no last error
+
+ m_LastError = 0;
+
+ if (m_Bound)
+ {
+ return(false);
+ }
+
+ // If the socket hasn't been created create it now
+
+ if (m_Socket == INVALID_SOCKET)
+ {
+ if (!createSocket())
+ {
+ return(false);
+ }
+ }
+ // If the number of retries is greater than the range then work through the
+ // range sequentially.
+
+ if (Retries > High - Low)
+ {
+ for (port = Low; port <= High; port++)
+ {
+ if (!setHost(Host, port))
+ return(false);
+
+ if (::bind(m_Socket, &m_HostAddr, sizeof(m_HostAddr)) == 0)
+ break;
+ }
+
+ if (port > High)
+ {
+ m_LastError = lastErrorCode();
+ return(false);
+ }
+ }
+
+ // Else select numbers within the range at random
+
+ else
+ {
+ for (i = 0; i < Retries; i++)
+ {
+ port = Low + (rand() % (High - Low));
+
+ if (!setHost(Host, port))
+ return(false);
+
+ if (::bind(m_Socket, &m_HostAddr, sizeof(m_HostAddr)) == 0)
+ break;
+ }
+
+ if (i >= Retries)
+ {
+ m_LastError = lastErrorCode();
+ return(false);
+ }
+ }
+
+ m_Bound = true;
+
+ return(true);
+}
+
+bool ppsocket::linger(bool LingerOn, int LingerTime)
+{
+ int i;
+ struct linger l;
+
+ // If the socket hasn't been created create it now
+
+ if (m_Socket == INVALID_SOCKET)
+ {
+ if (!createSocket())
+ {
+ return(false);
+ }
+ }
+ // Set the lingering
+
+ if (LingerOn)
+ {
+ l.l_onoff = 1;
+ l.l_linger = LingerTime;
+ }
+ else
+ {
+ l.l_onoff = 0;
+ l.l_linger = 0;
+ }
+ i = setsockopt(m_Socket, SOL_SOCKET, SO_LINGER, (const char*) &l, sizeof(l));
+
+ // Check for errors
+
+ if (i != 0)
+ {
+ m_LastError = lastErrorCode();
+ return(false);
+ }
+
+ // Return indicating success
+
+ return(true);
+}
+
+
+bool ppsocket::createSocket(void)
+{
+ // If the socket has already been created just return true
+ if (m_Socket != INVALID_SOCKET)
+ {
+ return(true);
+ }
+
+ // Create the socket
+ m_Socket = ::socket(PF_INET, SOCK_STREAM, 0);
+
+ if (m_Socket == INVALID_SOCKET)
+ {
+ m_LastError = lastErrorCode();
+ return(false);
+ }
+
+ // By default set no lingering
+
+ linger(FALSE, 0);
+
+ // Return indicating success
+
+ return(true);
+}
+
+bool ppsocket::setPeer(char* Peer, int Port)
+{
+ struct hostent* he;
+
+ // If a peer name was supplied then use it
+ if (Peer)
+ {
+ he = gethostbyname(Peer);
+ if (!he)
+ {
+ unsigned long ipaddress = inet_addr(Peer);
+ if (ipaddress == INADDR_NONE)
+ {
+ m_LastError = lastErrorCode();
+ return(false);
+ }
+
+ he = gethostbyaddr((const char*) &ipaddress, 4, PF_INET);
+ if (!he)
+ {
+ m_LastError = lastErrorCode();
+ return(false);
+ }
+ }
+ memcpy((void*) &((struct sockaddr_in*) &m_PeerAddr)->sin_addr, (void*) he->h_addr_list[0], 4);
+ }
+
+ // If a port name was supplied use it
+
+ if (Port > 0)
+ {
+ ((struct sockaddr_in*) &m_PeerAddr)->sin_port = htons((SHORT) Port);
+ }
+
+ return(true);
+}
+
+
+bool ppsocket::getPeer(char* Peer, int MaxLen, int* Port)
+{
+ char* peer;
+
+ if (Peer)
+ {
+ peer = inet_ntoa(((struct sockaddr_in*) &m_PeerAddr)->sin_addr);
+
+ if (!peer)
+ {
+ m_LastError = lastErrorCode();
+ return(false);
+ }
+
+ strncpy(Peer, peer, MaxLen);
+ Peer[MaxLen] = '\0';
+ }
+
+ if (Port)
+ {
+ *Port = ntohs(((struct sockaddr_in*) &m_PeerAddr)->sin_port);
+ }
+
+ return(false);
+}
+
+
+bool ppsocket::setHost(char* Host, int Port)
+{
+ struct hostent* he;
+
+ // If a host name was supplied then use it
+ if (Host)
+ {
+ he = gethostbyname(Host);
+
+ if (!he)
+ {
+ unsigned long ipaddress = inet_addr(Host);
+ if (ipaddress == INADDR_NONE)
+ {
+ m_LastError = lastErrorCode();
+ return(false);
+ }
+
+ he = gethostbyaddr((const char*) &ipaddress, 4, PF_INET);
+
+ if (!he)
+ {
+ m_LastError = lastErrorCode();
+ return(false);
+ }
+ }
+
+ memcpy((void*) &((struct sockaddr_in*) &m_HostAddr)->sin_addr, (void*) he->h_addr_list[0], 4);
+ }
+
+
+ // If a port name was supplied use it
+
+ if (Port > 0)
+ {
+ ((struct sockaddr_in*) &m_HostAddr)->sin_port = htons((SHORT) Port);
+ }
+
+ return(true);
+}
+
+
+bool ppsocket::getHost(char* Host, int MaxLen, int* Port)
+{
+ char* host;
+
+ if (Host)
+ {
+ host = inet_ntoa(((struct sockaddr_in*) &m_HostAddr)->sin_addr);
+
+ if (!host)
+ {
+ m_LastError = lastErrorCode();
+ return(false);
+ }
+
+ strncpy(Host, host, MaxLen);
+ Host[MaxLen] = '\0';
+ }
+
+ if (Port)
+ {
+ *Port = ntohs(((struct sockaddr_in*) &m_HostAddr)->sin_port);
+ }
+ return(false);
+}
+
+DWORD ppsocket::lastErrorCode()
+{
+ return errno;
+}
+
+void ppsocket::setSocketInvalid()
+{
+ m_Socket = INVALID_SOCKET;
+}
diff --git a/lib/ppsocket.h b/lib/ppsocket.h
new file mode 100644
index 0000000..b93ee25
--- /dev/null
+++ b/lib/ppsocket.h
@@ -0,0 +1,117 @@
+#if !defined(AFX_ppsocket_H__5611BC0C_3E39_11D1_8E4B_00805F2AB205__INCLUDED_)
+#define AFX_ppsocket_H__5611BC0C_3E39_11D1_8E4B_00805F2AB205__INCLUDED_
+
+#if _MSC_VER >= 1000
+#pragma once
+#endif // _MSC_VER >= 1000
+
+#include <unistd.h>
+#include <netdb.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+
+#ifndef TRUE
+#define TRUE -1
+#define FALSE 0
+#endif
+#define DWORD unsigned int
+#define SOCKET int
+
+#ifndef INADDR_NONE
+#define INADDR_NONE (in_addr_t)-1
+#endif
+#define INVALID_SOCKET -1
+#define SOCKET_ERROR -1
+#define INFINITE 0
+
+extern int errno;
+
+#include "bool.h"
+class bufferStore;
+
+class ppsocket
+{
+
+public:
+ ppsocket();
+ virtual ~ppsocket();
+
+ virtual bool startup(void);
+
+ virtual bool connect(char* Peer, int PeerPort, char* Host = NULL, int HostPort = 0);
+ virtual bool reconnect();
+
+ virtual void printPeer();
+
+ virtual bool listen(char* Host, int Port);
+
+ ppsocket* accept(char* Peer, int MaxLen);
+
+ bool dataToGet() const;
+ int getBufferStore(bufferStore &a, bool wait = true);
+ bool sendBufferStore(const bufferStore &a);
+
+ int printf(const char* Format, ...);
+
+ int readEx(char* Data, int cTerm, int MaxLen);
+ bool puts(const char* Data);
+
+ char sgetc(void);
+ bool sputc(char c);
+
+ int read(void* Data, size_t Size, size_t NumObj);
+ virtual int write(const void* Data, size_t Size, size_t NumObj);
+
+ int recv(char* buf, int len, int flags);
+ int send(const char* buf, int len, int flags);
+
+ int readTimeout(char* buf, int len, int flags);
+ int writeTimeout(const char* buf, int len, int flags);
+
+ inline void timeout(DWORD t) { m_Timeout = t; }
+ inline DWORD timeout(void) { return(m_Timeout); }
+
+ bool closeSocket(void);
+ bool bindSocket(char* Host, int Port);
+ bool bindInRange(char* Host, int Low, int High, int Retries);
+ bool linger(bool LingerOn, int LingerTime = 0);
+
+ virtual bool createSocket(void);
+
+ bool setPeer(char* Peer, int Port);
+ bool getPeer(char* Peer, int MaxLen, int* Port);
+ bool setHost(char* Host, int Port);
+ bool getHost(char* Host, int MaxLen, int* Port);
+
+ DWORD getLastError(void) { return(m_LastError); }
+ inline SOCKET socket(void) const { return(m_Socket); }
+ DWORD lastErrorCode();
+
+ //set the current socket to invalid
+ //useful when deleting if the socket has been
+ //copied to another and should not be closed
+ //when this instance is destructed
+ void setSocketInvalid();
+
+protected:
+ ppsocket(const ppsocket&);
+
+ struct sockaddr* getPeerAddrStruct() { return &m_PeerAddr; }
+ struct sockaddr* getHostAddrStruct() { return &m_HostAddr; }
+ void setHostAddrStruct(struct sockaddr* pHostStruct) { m_HostAddr = *pHostStruct; }
+ void setSocket(SOCKET& sock) { m_Socket = sock; }
+ void setBound() { m_Bound = true;}
+ void updateLastError() {m_LastError = lastErrorCode(); }
+
+private:
+ SOCKET m_Socket;
+ struct sockaddr m_HostAddr, m_PeerAddr;
+ bool m_Bound;
+#ifdef WIN32
+ OVERLAPPED m_ReadOverlapped, m_WriteOverlapped;
+#endif
+ DWORD m_Timeout;
+ DWORD m_LastError;
+};
+
+#endif
diff --git a/plpnfsd/Makefile.am b/plpnfsd/Makefile.am
new file mode 100644
index 0000000..8ebc662
--- /dev/null
+++ b/plpnfsd/Makefile.am
@@ -0,0 +1,9 @@
+INCLUDES=-I../lib
+LIBS=../lib/libutils.a
+
+sbin_PROGRAMS = plpnfsd
+
+plpnfsd_SOURCES = mp_main.c mp_mount.c nfs_prot_svc.c nfs_prot_xdr.c \
+ mp_pfs_ops.c mp_inode.c rfsv32.cc main.cc
+
+EXTRA_plpnfsd_SOURCES = mount_aix.c
diff --git a/plpnfsd/main.cc b/plpnfsd/main.cc
new file mode 100644
index 0000000..6dc472b
--- /dev/null
+++ b/plpnfsd/main.cc
@@ -0,0 +1,215 @@
+//
+// PLP - An implementation of the PSION link protocol
+//
+// Copyright (C) 1999 Philip Proudman
+//
+// 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 2 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 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// e-mail philip.proudman@btinternet.com
+
+#include <stream.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "bool.h"
+#include "../defaults.h"
+#include "rfsv32.h"
+#include "bufferstore.h"
+#include "bufferarray.h"
+#include "ppsocket.h"
+extern "C" {
+#include "rfsv_api.h"
+}
+
+static rfsv32 *a;
+
+long rfsv_dir(const char *file, dentry **e) {
+ bufferArray entries;
+ dentry *tmp;
+ long ret = a->dir(&(*file), &entries);
+ psion_alive = (a->getStatus() == 0);
+ while (!entries.empty()) {
+ bufferStore s;
+ s = entries.popBuffer();
+ tmp = *e;
+ *e = (dentry *)malloc(sizeof(dentry));
+ if (!*e)
+ return -1;
+ (*e)->time = s.getDWord(0);
+ (*e)->size = s.getDWord(4);
+ (*e)->attr = s.getDWord(8);
+ (*e)->name = strdup(s.getString(12));
+ (*e)->next = tmp;
+ }
+ return ret;
+}
+
+long rfsv_dircount(const char *file, long *count) {
+ long ret = a->dircount(&(*file), &(*count));
+ psion_alive = (a->getStatus() == 0);
+ return ret;
+}
+
+long rfsv_rmdir(const char *name) {
+ long ret = a->rmdir(name);
+ psion_alive = (a->getStatus() == 0);
+ return ret;
+}
+
+long rfsv_mkdir(const char *file) {
+ long ret = a->mkdir(file);
+ psion_alive = (a->getStatus() == 0);
+ return ret;
+}
+
+long rfsv_remove(const char *file) {
+ long ret = a->remove(file);
+ psion_alive = (a->getStatus() == 0);
+ return ret;
+}
+
+long rfsv_fclose(long handle) {
+ long ret = a->fclose(handle);
+ psion_alive = (a->getStatus() == 0);
+ return ret;
+}
+
+long rfsv_fopen(long attr, const char *file, long *handle) {
+ long ph;
+ long ret = a->fopen(attr, file, ph);
+ *handle = ph;
+ psion_alive = (a->getStatus() == 0);
+ return ret;
+}
+
+long rfsv_fcreate(long attr, const char *file, long *handle) {
+ long ph;
+ long ret = a->fcreatefile(attr, file, ph);
+ *handle = ph;
+ psion_alive = (a->getStatus() == 0);
+ return ret;
+}
+
+long rfsv_read(char *buf, long offset, long len, long handle) {
+ long ret = a->fseek(handle, offset, rfsv32::PSEEK_SET);
+ if (ret >= 0)
+ ret = a->fread(handle, buf, len);
+ psion_alive = (a->getStatus() == 0);
+ return ret;
+}
+
+long rfsv_write(char *buf, long offset, long len, long handle) {
+ long ret = a->fseek(handle, offset, rfsv32::PSEEK_SET);
+ if (ret >= 0)
+ ret = a->fwrite(handle, buf, len);
+ psion_alive = (a->getStatus() == 0);
+ return ret;
+}
+
+long rfsv_setmtime(const char *name, long time) {
+ long ret = a->fsetmtime(name, time);
+ psion_alive = (a->getStatus() == 0);
+ return ret;
+}
+
+long rfsv_setsize(const char *name, long size) {
+ long ph;
+ long ret = a->fopen(0x200, name, ph);
+ if (!ret) {
+ ret = a->fsetsize(ph, size);
+ a->fclose(ph);
+ }
+ psion_alive = (a->getStatus() == 0);
+ return ret;
+}
+
+long rfsv_setattr(const char *name, long sattr, long dattr) {
+ long ret = a->fsetattr(name, dattr, sattr);
+ psion_alive = (a->getStatus() == 0);
+ return ret;
+}
+
+long rfsv_getattr(const char *name, long *attr, long *size, long *time) {
+ long ret = a->fgeteattr(&(*name), &(*attr), &(*size), &(*time));
+ psion_alive = (a->getStatus() == 0);
+ return ret;
+}
+
+long rfsv_statdev(char letter) {
+ long vfree, vtotal, vattr, vuniqueid;
+ int devnum = letter - 'A';
+ char *name;
+
+ name = a->devinfo(devnum, &vfree, &vtotal, &vattr, &vuniqueid);
+ psion_alive = (a->getStatus() == 0);
+ return (name == NULL);
+}
+
+long rfsv_rename(const char *oldname, const char *newname) {
+ long ret = a->rename(oldname, newname);
+ psion_alive = (a->getStatus() == 0);
+ return ret;
+}
+
+long rfsv_drivelist(int *cnt, device **dlist) {
+ *dlist = NULL;
+ long devbits;
+ long ret;
+ int i;
+
+ ret = a->devlist(&devbits);
+ if (ret == 0)
+ for (i = 0; i<26; i++) {
+ char *name;
+ long vtotal, vfree, vattr, vuniqueid;
+
+ if ((devbits & 1) &&
+ ((name = a->devinfo(i, &vfree, &vtotal, &vattr, &vuniqueid)))) {
+ device *next = *dlist;
+ *dlist = (device *)malloc(sizeof(device));
+ (*dlist)->next = next;
+ (*dlist)->name = name;
+ (*dlist)->total = vtotal;
+ (*dlist)->free = vfree;
+ (*dlist)->letter = 'A' + i;
+ (*dlist)->attrib = vattr;
+ (*cnt)++;
+ }
+ devbits >>= 1;
+ }
+ psion_alive = (a->getStatus() == 0);
+ return ret;
+}
+
+int main(int argc, char**argv) {
+ ppsocket *skt;
+ bool res;
+
+ // Command line parameter processing
+ int sockNum = DEFAULT_SOCKET;
+
+ skt = new ppsocket();
+ skt->startup();
+ res = skt->connect(NULL, sockNum);
+
+ a = new rfsv32(skt);
+
+ char *mp_args[] = { "mp_main", "-v", "-dir", "/mnt/psion", NULL };
+ mp_main(4, mp_args);
+
+ delete a;
+ return 0;
+}
diff --git a/plpnfsd/mount_aix.c b/plpnfsd/mount_aix.c
new file mode 100644
index 0000000..87d5ca3
--- /dev/null
+++ b/plpnfsd/mount_aix.c
@@ -0,0 +1,170 @@
+/*
+ * Copyright (c) 1990 Jan-Simon Pendry
+ * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jan-Simon Pendry at Imperial College, London.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * %W% (Berkeley) %G%
+ *
+ * $Id$
+ *
+ */
+
+
+/*
+ * AIX 3 Mount helper
+ */
+
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/vmount.h>
+#include <sys/errno.h>
+#include <fcntl.h>
+
+#include "misc-aix3.h"
+#include "os-aix3.h"
+
+typedef void * voidp;
+
+#undef DEBUG
+
+char hostname[MAXHOSTNAMELEN] = "localhost"; /* Hostname */
+
+static int aix3_mkvp(p, gfstype, flags, object, stub, host, info, info_size, args)
+char *p;
+int gfstype;
+int flags;
+char *object;
+char *stub;
+char *host;
+char *info;
+int info_size;
+char *args;
+{
+ struct vmount *vp = (struct vmount *) p;
+ bzero((voidp) vp, sizeof(*vp));
+ /*
+ * Fill in standard fields
+ */
+ vp->vmt_revision = VMT_REVISION;
+ vp->vmt_flags = flags;
+ vp->vmt_gfstype = gfstype;
+
+#define VMT_ROUNDUP(len) (4 * ((len + 3) / 4))
+#define VMT_ASSIGN(vp, idx, data, size) \
+ vp->vmt_data[idx].vmt_off = p - (char *) vp; \
+ vp->vmt_data[idx].vmt_size = size; \
+ bcopy(data, p, size); \
+ p += VMT_ROUNDUP(size);
+
+ /*
+ * Fill in all variable length data
+ */
+ p += sizeof(*vp);
+
+ VMT_ASSIGN(vp, VMT_OBJECT, object, strlen(object) + 1);
+ VMT_ASSIGN(vp, VMT_STUB, stub, strlen(stub) + 1);
+ VMT_ASSIGN(vp, VMT_HOST, host, strlen(host) + 1);
+ VMT_ASSIGN(vp, VMT_HOSTNAME, host, strlen(host) + 1);
+ VMT_ASSIGN(vp, VMT_INFO, info, info_size);
+ VMT_ASSIGN(vp, VMT_ARGS, args, strlen(args) + 1);
+
+#undef VMT_ASSIGN
+#undef VMT_ROUNDUP
+
+ /*
+ * Return length
+ */
+ return vp->vmt_length = p - (char *) vp;
+}
+
+/*
+ * Map from conventional mount arguments
+ * to AIX 3-style arguments.
+ */
+aix3_mount(fsname, dir, flags, type, data, args)
+char *fsname;
+char *dir;
+int flags;
+int type;
+void *data;
+char *args;
+{
+ char buf[4096];
+ int size;
+
+ for (size = 0; size < 4096; size++) buf[size] = 0;
+#ifdef DEBUG
+ printf("aix3_mount: fsname %s, dir %s, type %d\n", fsname, dir, type);
+#endif
+
+/* aix3_mkvp(p, gfstype, flags, object, stub, host, info, info_size, args) */
+
+ switch (type) {
+
+ case MOUNT_TYPE_NFS: {
+ char *host = strdup(fsname);
+ char *rfs = strchr(host, ':');
+ int free_rfs = 0;
+ if (rfs) {
+ *rfs++ = '\0';
+ } else {
+ rfs = host;
+ free_rfs = 1;
+ host = strdup(hostname);
+ }
+
+ size = aix3_mkvp(buf, type, flags, rfs, dir, host, data, sizeof(struct nfs_args), args);
+ if (free_rfs)
+ free((voidp) rfs);
+ free(host);
+
+ } break;
+
+ case MOUNT_TYPE_UFS:
+ /* Need to open block device and extract log device info from sblk. */
+ errno = EINVAL;
+ return -1;
+
+ default:
+ errno = EINVAL;
+ return -1;
+ }
+#ifdef DEBUG
+ printf("aix3_mkvp: flags %#x, size %d, args %s\n", flags, size, args);
+ printf("revision %d\n", ((struct vmount *)buf)->vmt_revision);
+#endif
+
+ return vmount(buf, size);
+}
diff --git a/plpnfsd/mp_inode.c b/plpnfsd/mp_inode.c
new file mode 100644
index 0000000..0f9051c
--- /dev/null
+++ b/plpnfsd/mp_inode.c
@@ -0,0 +1,325 @@
+#include <stdio.h>
+#include "nfs_prot.h"
+#include "mp.h"
+#include "rfsv_api.h"
+
+#if defined(__SVR4) || defined(__GLIBC__) || defined(__FreeBSD__)
+#include <string.h>
+#include <stdlib.h>
+#endif
+#ifdef __NeXT__
+#include <string.h>
+#include <objc/hashtable.h>
+#define strdup NXCopyStringBuffer
+#endif
+#define HASHSIZE 99
+
+static int nextinode = 6;
+static p_inode *numtab[HASHSIZE];
+static p_inode *namtab[HASHSIZE];
+
+/*
+ * Verrry simple hash :-)
+ */
+static unsigned
+hash(str)
+char *str;
+{
+ unsigned i = 0, hashval = 3 * HASHSIZE / 4;
+
+ while (*str) {
+ i = *str++;
+ hashval = (hashval << (i & 7)) + i;
+ }
+
+ return hashval % HASHSIZE;
+}
+
+/* Get struct with inode */
+p_inode *
+get_num(i)
+int i;
+{
+ p_inode *ptr;
+
+ for (ptr = numtab[i % HASHSIZE]; ptr; ptr = ptr->nextnum)
+ if (i == ptr->inode)
+ break;
+ if (!ptr) {
+ printf("Inode %d not found (aborting)\n", i);
+ abort();
+ }
+ return ptr;
+}
+
+static p_inode *
+newinode(name, inode)
+char *name;
+int inode;
+{
+ p_inode *ptr;
+ int idx = hash(name);
+
+ ptr = (p_inode *) malloc(sizeof(*ptr));
+ ptr->name = (char *) strdup(name);
+ ptr->inode = inode;
+
+/* insert into both hashtabs */
+ ptr->nextnam = namtab[idx];
+ namtab[idx] = ptr;
+
+ ptr->nextnum = numtab[inode % HASHSIZE];
+ numtab[inode % HASHSIZE] = ptr;
+
+ return ptr;
+}
+
+/* Get/create struct with name */
+p_inode *
+get_nam(name)
+char *name;
+{
+ p_inode *ptr;
+ int idx = hash(name);
+
+ for (ptr = namtab[idx]; ptr; ptr = ptr->nextnam)
+ if (!strcmp(name, ptr->name))
+ break;
+ if (!ptr)
+ ptr = newinode(name, nextinode++);
+ if (debug > 1)
+ printf("\tget_nam(``%s'') returns %08x->inode = %d\n",
+ name, (unsigned int) ptr, ptr->inode);
+ return ptr;
+}
+
+void
+inode2fh(inode, fh)
+int inode;
+char *fh;
+{
+ bzero(fh, NFS_FHSIZE);
+ bcopy((char *) &inode, fh, sizeof(inode));
+}
+
+int
+fh2inode(fh)
+char *fh;
+{
+ int inode;
+
+ bcopy(fh, (char *) &inode, sizeof(inode));
+ return inode;
+}
+
+
+
+/* Rename: the inode must be preserved */
+p_inode *
+re_nam(old, new)
+char *old, *new;
+{
+ p_inode *nptr, *optr, **nampp, **numpp;
+ int idx = hash(old);
+
+ if (debug)
+ printf("re_nam: %s->%s\n", old, new);
+ for (nampp = &namtab[idx]; *nampp; nampp = &(*nampp)->nextnam)
+ if (!strcmp(old, (*nampp)->name))
+ break;
+ if (!*nampp)
+ return get_nam(new);
+
+ optr = *nampp;
+ if (debug)
+ printf("re_nam: %d\n", optr->inode);
+ *nampp = optr->nextnam;
+
+ /* delete it from the other hashtab too */
+ idx = optr->inode % HASHSIZE;
+ for (numpp = &numtab[idx]; *numpp; numpp = &(*numpp)->nextnum)
+ if (optr == (*numpp))
+ break;
+ if (!*numpp) {
+ printf("Entry in one hashtab only (aborting)\n");
+ abort();
+ }
+ *numpp = optr->nextnum;
+
+ nptr = newinode(new, optr->inode);
+ if (debug)
+ printf("re_nam: new entry created\n");
+ free(optr->name);
+ free(optr);
+
+ return nptr;
+}
+
+/* Cache routines */
+struct cache *
+search_cache(root, inode)
+struct cache *root;
+unsigned inode;
+{
+ struct cache *cp;
+
+ if (debug)
+ printf("search_cache %d\n", inode);
+ for (cp = root; cp; cp = cp->next)
+ if (cp->inode == inode)
+ return cp;
+ return 0;
+}
+
+struct cache *
+add_cache(root, inode, fp)
+struct cache **root;
+unsigned inode;
+fattr *fp;
+{
+ struct cache *cp;
+
+ if (debug)
+ printf("add_cache %d\n", inode);
+ cp = (struct cache *) malloc(sizeof(*cp));
+ cp->inode = inode;
+ cp->attr = *fp;
+ cp->dcache = 0;
+ cp->actual_size = fp->size;
+ cp->next = *root;
+ *root = cp;
+ return cp;
+}
+
+struct dcache *
+add_dcache(cp, offset, len, data)
+struct cache *cp;
+unsigned offset, len;
+unsigned char *data;
+{
+ struct dcache *dcp;
+ dcp = (struct dcache *) malloc(sizeof(*dcp));
+ dcp->towrite = 1;
+ dcp->offset = offset;
+ dcp->data = 0;
+ dcp->len = len;
+ if (len) {
+ dcp->data = (unsigned char *) malloc(len);
+ bcopy(data, dcp->data, len);
+ }
+ dcp->next = cp->dcache;
+ cp->dcache = dcp;
+ return dcp;
+}
+
+void
+clean_dcache(cp)
+struct cache *cp;
+{
+ struct dcache *dcp, *dcpn;
+ for (dcp = cp->dcache; dcp; dcp = dcpn) {
+ dcpn = dcp->next;
+ if (dcp->len)
+ free(dcp->data);
+ free(dcp);
+ }
+ cp->dcache = 0;
+}
+
+struct dcache *
+search_dcache(cp, off, len)
+struct cache *cp;
+unsigned int off, len;
+{
+ struct dcache *dcp;
+ for (dcp = cp->dcache; dcp; dcp = dcp->next)
+ if (dcp->offset == off && dcp->len >= len)
+ return dcp;
+ return 0;
+}
+
+void
+rem_cache(root, inode)
+struct cache **root;
+unsigned inode;
+{
+ struct cache *cp, **cpp;
+
+ if (debug)
+ printf("rem_cache %d\n", inode);
+ for (cpp = root; (cp = *cpp); cpp = &cp->next)
+ if (cp->inode == inode)
+ break;
+ if (!cp)
+ return;
+ *cpp = cp->next;
+ clean_dcache(cp);
+ free(cp);
+}
+
+void
+clean_cache(root)
+struct cache **root;
+{
+ struct cache *cp, *cpn;
+
+ for (cp = *root; cp; cp = cpn) {
+ cpn = cp->next;
+ clean_dcache(cp);
+ free(cp);
+ }
+ *root = 0;
+}
+
+char *
+build_path(dir, file)
+char *dir, *file;
+{
+ static char namebuf[300];
+
+ if (!strcmp(dir, ""))
+ strcpy(namebuf, file);
+ else
+ sprintf(namebuf, "%s\\%s", dir, file);
+
+ return namebuf;
+}
+
+int
+getpinode(inode)
+p_inode *inode;
+{
+ char *p;
+ int i;
+
+ if (inode->inode == root_fattr.fileid) /* Root inode */
+ i = root_fattr.fileid - 1; /* RUDI !!! */
+ else if (!(p = (char *) rindex(inode->name, '\\'))) /* device inode */
+ i = root_fattr.fileid;
+ else {
+ *p = 0;
+ i = get_nam(inode->name)->inode;
+ *p = '\\';
+ }
+ return i;
+}
+
+char *
+dirname(dir)
+char *dir;
+{
+ static char namebuf[300];
+ sprintf(namebuf, "%s\\", dir);
+ return namebuf;
+}
+
+char *
+filname(dir)
+char *dir;
+{
+ char *p;
+ if ((p = (char *) rindex(dir, '\\')))
+ return p + 1;
+ else
+ return dir;
+}
diff --git a/plpnfsd/mp_main.c b/plpnfsd/mp_main.c
new file mode 100644
index 0000000..1bac5fe
--- /dev/null
+++ b/plpnfsd/mp_main.c
@@ -0,0 +1,147 @@
+#include <OSdefs.h>
+#include <stdio.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <pwd.h>
+#include "nfs_prot.h"
+#include "mp.h"
+#include "defs.h"
+#if defined (__SVR4) || defined(__sgi)
+#include <stdlib.h> /* getenv */
+#include <string.h> /* strcmp */
+#endif
+#include <unistd.h> /* getuid */
+
+#include <dirent.h>
+#if defined(__NeXT__)
+#include <sys/dir.h>
+#include <unistd.h>
+#define DIRENT struct direct
+#else
+#define DIRENT struct dirent
+#endif
+
+
+extern void nfs_program_2();
+
+static char
+*user, *dir = DDIR;
+
+int gmtoffset, debug, exiting, psion_alive, query_cache = 0;
+
+fattr root_fattr =
+{
+ NFDIR, 0040500, 1, 0, 0,
+ BLOCKSIZE, BLOCKSIZE, FID, 1, FID, 1,
+ {0, 0},
+ {0, 0},
+ {0, 0}
+};
+
+#if defined(hpux) || defined(__SVR4) || defined(__sgi)
+void
+usleep(usec)
+int usec;
+{
+ struct timeval t;
+
+ t.tv_sec = (long) (usec / 1000000);
+ t.tv_usec = (long) (usec % 1000000);
+ select(0, (fd_set *) 0, (fd_set *) 0, (fd_set *) 0, &t);
+}
+
+#endif /* hpux */
+
+int
+mp_main(ac, av)
+int ac;
+char *av[];
+{
+ struct passwd *pw;
+ struct timeval tv;
+ struct timezone tz;
+ p_inode *rp;
+ nfs_fh root_fh;
+ DIR *dirp;
+ DIRENT *diep;
+ int i;
+
+
+ if (!(user = (char *) getenv("USER")))
+ user = (char *) getenv("logname");
+
+ while (ac > 1) {
+ if (!strcmp(av[1], "-v")) {
+ debug++;
+ } else if (!strcmp(av[1], "-dir")) {
+ dir = av[2];
+ ac--;
+ av++;
+ } else if (!strcmp(av[1], "-user") || !strcmp(av[1], "-u")) {
+ user = av[2];
+ ac--;
+ av++;
+ } else {
+ printf("p3nfsd version %s\n", VERSION);
+ printf("Usage: p3nfsd [-dir directory] [-user username]\n");
+ printf(" [-wakeup] [-v] [-]\n");
+ printf("Defaults: -dir %s -user %s\n", dir, user);
+ return 1;
+ }
+ ac--;
+ av++;
+ }
+
+ if (user && *user) {
+ if (!(pw = getpwnam(user))) {
+ fprintf(stderr, "User %s not found.\n", user);
+ return 1;
+ }
+ } else if (!(pw = getpwuid(getuid()))) {
+ fprintf(stderr, "You don't exist, go away!\n");
+ return 1;
+ }
+ if (getuid() && pw->pw_uid != getuid()) {
+ fprintf(stderr, "%s? You must be kidding...\n", user);
+ return 1;
+ }
+ root_fattr.uid = pw->pw_uid;
+ root_fattr.gid = pw->pw_gid;
+ endpwent();
+
+ gettimeofday(&tv, &tz);
+#ifndef __SVR4
+ gmtoffset = -tz.tz_minuteswest * 60;
+#else
+ tzset();
+ gmtoffset = -timezone;
+#endif
+
+ printf("plpnfsd: version %s, mounting on %s\n", VERSION, dir);
+
+
+ /* Check if mountdir is empty (or else you can overmount e.g /etc)
+ It is done here, because exit hangs, if hardware flowcontrol is
+ not present. Bugreport Nov 28 1996 by Olaf Flebbe */
+ if (!(dirp = opendir(dir))) {
+ perror(dir);
+ return 1;
+ }
+ i = 0;
+ while ((diep = readdir(dirp)) != 0)
+ if (strcmp(diep->d_name, ".") && strcmp(diep->d_name, ".."))
+ i++;
+ closedir(dirp);
+ if (i) {
+ fprintf(stderr, "Sorry, directory %s is not empty, exiting.\n", dir);
+ return 1;
+ }
+ rp = get_nam("");
+ inode2fh(rp->inode, root_fh.data);
+ root_fattr.fileid = rp->inode;
+ root_fattr.atime.seconds = root_fattr.mtime.seconds =
+ root_fattr.ctime.seconds = tv.tv_sec;
+
+ mount_and_run(dir, nfs_program_2, &root_fh);
+ return 0;
+}
diff --git a/plpnfsd/mp_mount.c b/plpnfsd/mp_mount.c
new file mode 100644
index 0000000..d13dea5
--- /dev/null
+++ b/plpnfsd/mp_mount.c
@@ -0,0 +1,601 @@
+#if defined(__SVR4) || defined(__sgi) || defined(linux)
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h> /* strdup */
+#ifndef linux
+extern int inet_addr(char *);
+#endif
+#define PORTMAP /* I need svcudp_create in rpc/svc_soc.h, sol 2.4 */
+#endif
+
+#include <OSdefs.h>
+#include <stdio.h>
+#include <signal.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+
+
+#ifdef __sgi
+#include <bstring.h>
+#endif
+
+#if defined(__NetBSD__) || defined(__FreeBSD__)
+#include <sys/param.h> /* Needs NGROUPS for mount.h */
+#define umount(dir) unmount(dir, 1)
+#endif
+
+#if defined(__NeXT__)
+#include <libc.h>
+#include <unistd.h>
+#include <nfs/nfs_mount.h>
+#define umount(dir) unmount(dir)
+#endif
+
+#include "defs.h"
+
+static char nfshost[128];
+
+#define NFSCLIENT
+#ifdef __FreeBSD__
+#define NFS
+#endif /* __FreeBSD__ */
+#include <sys/mount.h>
+
+#ifdef __FreeBSD__
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <rpc/rpc.h>
+#include <nfs/rpcv2.h>
+#if __FreeBSD_version >= 300001
+#include <nfs/nfs.h>
+#endif
+#endif /* __FreeBSD__ */
+
+#include <rpc/rpc.h>
+#include "nfs_prot.h"
+
+#ifdef linux
+#ifndef __GLIBC__
+#include <linux/fs.h> /* struct nfs_mount_data */
+#endif
+#include <linux/nfs_mount.h> /* struct nfs_mount_data */
+#include <arpa/inet.h> /* inet_addr() */
+#endif
+#ifdef _IBMR2
+#include "os-aix3.h"
+#include "misc-aix3.h"
+#include <sys/vmount.h>
+#endif
+
+
+#ifndef DONT_UPDATE_MTAB
+#if defined(sun) && defined(__SVR4)
+#include <sys/mnttab.h>
+#else
+#include <mntent.h>
+#endif
+#endif
+
+#if defined(sun) && defined(__SVR4) /*gec */
+#include <nfs/mount.h>
+#include <sys/fstyp.h>
+#include <sys/fsid.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#define PORTMAP
+#endif
+
+#if defined(sun) && !defined(__SVR4)
+extern int _rpc_dtablesize();
+#define umount unmount
+#endif
+
+#include <sys/socket.h>
+#include <netdb.h>
+
+#include "mp.h"
+
+#ifdef __sgi
+#define vfork fork
+#define NFSMNT_NOCTO 0
+#endif
+
+#if defined(sun) && defined(__SVR4)
+#define setmntent fopen
+#define endmntent fclose
+#define addmntent putmntent
+#define mntent mnttab
+#endif
+
+
+static char *mntdir; /* where we mounted the psion */
+
+#ifdef __STDC__
+static void doexit(void);
+#endif
+
+static void
+usr1_handler SIGARG
+{
+ debug = (debug + 1) & 3;
+ printf("Set debug level to %d\n", debug);
+};
+
+static void
+hup_handler SIGARG
+{
+ if (debug > 1)
+ printf("Got HUP signal\n");
+ exiting = 5;
+};
+
+static void
+doexit()
+{
+#ifndef DONT_UPDATE_MTAB
+ FILE *fpin, *fpout;
+#if defined(sun) && defined(__SVR4)
+ struct mntent entr;
+#else
+ struct mntent *ent;
+#endif
+#endif
+#ifndef __FreeBSD__
+ struct stat statb;
+#endif
+
+ exiting--;
+
+ if (debug)
+ printf("Doing exit\n");
+
+#ifdef _IBMR2
+ if (stat(mntdir, &statb)) {
+ perror("stat");
+ return;
+ }
+ if (debug)
+ printf("Next call: uvmount(%d, 0)\n", statb.st_vfs);
+ if (uvmount(statb.st_vfs, 0)) {
+ perror("uvmount");
+ return;
+ }
+#else
+ if (umount(mntdir)) {
+ perror(mntdir);
+ return;
+ }
+#endif
+
+#ifndef DONT_UPDATE_MTAB
+ if (debug)
+ printf("unmount succeeded, trying to fix mtab.\n");
+
+ if (!(fpout = setmntent(MTAB_TMP, "w"))) {
+ perror(MTAB_TMP);
+ return;
+ }
+ if (!(fpin = setmntent(MTAB_PATH, "r"))) {
+ endmntent(fpout);
+ unlink(MTAB_TMP);
+ perror(MTAB_PATH);
+ exit(0);
+ }
+ if (fstat(fileno(fpin), &statb))
+ perror("fstat");
+ else
+ fchmod(fileno(fpout), statb.st_mode);
+
+#if defined(sun) && defined(__SVR4)
+ while (!getmntent(fpin, &entr))
+ if (strcmp(entr.mnt_special, nfshost) || strcmp(entr.mnt_mountp, mntdir))
+ putmntent(fpout, &entr);
+#else
+ while ((ent = getmntent(fpin)))
+ if (strcmp(ent->mnt_fsname, nfshost) || strcmp(ent->mnt_dir, mntdir))
+ addmntent(fpout, ent);
+#endif
+ endmntent(fpin);
+ endmntent(fpout);
+
+ if (rename(MTAB_TMP, MTAB_PATH)) {
+ perror(MTAB_PATH);
+ unlink(MTAB_TMP);
+ }
+#else
+ if (debug)
+ printf("no mtab fixing needed\n");
+#endif
+ fprintf(stderr, "plpnfsd: exiting.\n");
+
+ exit(0);
+}
+
+void
+mount_and_run(char *dir, void (*proc)(), nfs_fh *root_fh)
+{
+ int sock, port, pid, doclean;
+ struct sockaddr_in sain;
+ int isalive = 0, ret, dtbsize;
+ SVCXPRT *nfsxprt;
+ int bufsiz = 0xc000; /* room for a few biods */
+#ifdef linux
+ struct nfs_mount_data nfs_mount_data;
+ int mount_flags;
+ int ksock, kport;
+ struct sockaddr_in kaddr;
+#else
+ struct nfs_args nfs_args;
+#endif
+#ifdef __FreeBSD__
+ int mount_flags;
+#endif
+
+ sprintf(nfshost, "localhost:/psion");
+ bzero((char *) &sain, sizeof(struct sockaddr_in));
+#ifdef linux
+ bzero(&nfs_mount_data, sizeof(struct nfs_mount_data));
+#else
+ bzero((char *) &nfs_args, sizeof(struct nfs_args));
+#endif
+
+/*** First part: set up the rpc service */
+ /* Create udp socket */
+ sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+ if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char *) &bufsiz, sizeof(bufsiz)))
+ perror("setsockopt");
+
+ /* Bind it to a reserved port */
+ sain.sin_family = AF_INET;
+ sain.sin_addr.s_addr = inet_addr("127.0.0.1");
+ for (port = IPPORT_RESERVED - 1; port > IPPORT_RESERVED / 2; port--) {
+ sain.sin_port = htons(port);
+ if (bind(sock, (struct sockaddr *) &sain, sizeof(sain)) >= 0)
+ break;
+ }
+ if (port <= IPPORT_RESERVED / 2) {
+ perror("bind to reserved port");
+ exit(1);
+ }
+ if ((nfsxprt = svcudp_create(sock)) == 0) {
+ perror("svcudp_create");
+ exit(1);
+ }
+ if (!svc_register(nfsxprt, NFS_PROGRAM, NFS_VERSION, proc, 0)) {
+ perror("svc_register");
+ exit(1);
+ }
+ if (debug)
+ printf("created svc PROG=%d, VER=%d port=%d\n",
+ NFS_PROGRAM, NFS_VERSION, port);
+
+
+/*** Second part: mount the directory */
+#ifdef linux
+ /*
+ * Hold your hat! Another odd internet socket coming up. The linux
+ * kernel needs the socket to talk to the nfs daemon.
+ */
+ ksock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+ if (ksock < 0) {
+ perror("Cannot create kernel socket.");
+ exit(1);
+ }
+ kaddr.sin_family = AF_INET;
+ kaddr.sin_addr.s_addr = inet_addr("127.0.0.1");
+ for (kport = IPPORT_RESERVED - 1; kport > IPPORT_RESERVED / 2; kport--) {
+ kaddr.sin_port = htons(kport);
+ if (bind(ksock, (struct sockaddr *) &kaddr, sizeof(kaddr)) >= 0)
+ break;
+ }
+ if (kport <= IPPORT_RESERVED / 2) {
+ perror("bind to reserved port");
+ exit(1);
+ }
+ nfs_mount_data.version = NFS_MOUNT_VERSION;
+ nfs_mount_data.fd = ksock;
+ nfs_mount_data.root = *root_fh; /* structure copy */
+ nfs_mount_data.flags = NFS_MOUNT_INTR | NFS_MOUNT_NOCTO;
+ /* NFS_MOUNT_SECURE | NFS_MOUNT_POSIX | NFS_MOUNT_SOFT | NFS_MOUNT_NOAC */
+ nfs_mount_data.rsize = PBUFSIZE;
+ nfs_mount_data.wsize = PBUFSIZE;
+ nfs_mount_data.timeo = 600;
+ nfs_mount_data.retrans = 10; /* default 3 */
+ nfs_mount_data.acregmin = 3; /* default 3 seconds */
+ nfs_mount_data.acregmax = 60; /* default 60 seconds */
+ nfs_mount_data.acdirmin = 30; /* default 30 seconds */
+ nfs_mount_data.acdirmax = 60; /* default 60 seconds */
+ nfs_mount_data.addr = sain; /* structure copy */
+ strcpy(nfs_mount_data.hostname, PSIONHOSTNAME);
+
+ if (connect(ksock, (struct sockaddr *) &nfs_mount_data.addr, sizeof(nfs_mount_data.addr)) < 0) {
+ perror("Cannot connect to plpnfsd");
+ exit(1);
+ }
+ mount_flags = MS_MGC_VAL; /* | MS_SYNC | MS_RDONLY | MS_NOEXEC | MS_NODEV | MS_NOSUID */
+
+#endif
+
+#if defined(sun) && defined (__SVR4)
+ { /*gec */
+ struct netbuf myaddr;
+ struct stat stb;
+ struct knetconfig knc;
+ struct netconfig *nc = getnetconfigent("udp");
+ if (!nc) {
+ extern int errno;
+ fprintf(stderr, "getnetconfigent \"udp\": (errno %d) ", errno);
+ perror("");
+ exit(1);
+ }
+ knc.knc_semantics = nc->nc_semantics;
+ knc.knc_protofmly = strdup(nc->nc_protofmly);
+ knc.knc_proto = strdup(nc->nc_proto);
+
+ if (stat(nc->nc_device, &stb)) {
+ extern int errno;
+ fprintf(stderr, "stat \"%s\": (errno %d) ", nc->nc_device, errno);
+ perror("");
+ exit(1);
+ }
+ knc.knc_rdev = stb.st_rdev;
+
+ /*freenetconfigent(nc) has the struct been allocated, or is it static ?!? */
+
+ if (debug)
+ printf("%d,%s,%s,%lx (1,inet,udp,0x002c0029)\n", (int) knc.knc_semantics,
+ knc.knc_protofmly, knc.knc_proto, knc.knc_rdev);
+
+ myaddr.maxlen = myaddr.len = sizeof(sain);
+ myaddr.buf = (char *) &sain;
+
+ nfs_args.knconf = &knc;
+ nfs_args.wsize = PBUFSIZE;
+ nfs_args.rsize = PBUFSIZE;
+ nfs_args.addr = &myaddr;
+ nfs_args.fh = (char *) root_fh;
+ nfs_args.retrans = 10;
+ /* 1 minute timeout - see below */
+ nfs_args.timeo = 600;
+ nfs_args.hostname = PSIONHOSTNAME;
+ nfs_args.flags = NFSMNT_INT | NFSMNT_HOSTNAME | NFSMNT_NOCTO |
+ NFSMNT_RETRANS | NFSMNT_TIMEO | NFSMNT_WSIZE |
+ NFSMNT_RSIZE | NFSMNT_KNCONF /* | NFSMNT_NOAC */ ;
+ /* eventually drop knc-strings now (memory-leak) */
+ }
+#endif /* solaris */
+
+/* BSD Derived systems */
+#if (defined(sun) && !defined(__SVR4)) || defined(hpux) || defined(__sgi) || defined(__NeXT__)
+ nfs_args.addr = &sain;
+ nfs_args.fh = (void *) root_fh;
+ nfs_args.wsize = PBUFSIZE;
+ nfs_args.rsize = PBUFSIZE;
+ nfs_args.retrans = 10;
+ /* 1 minute timeout - means that we receive double requests in worst case,
+ if the file is longer than 100k. So long for the theory. Since SunOS uses
+ dynamic retransmission (hardwired), nfs_args.timeo is only a hint. :-( */
+ nfs_args.timeo = 600;
+ nfs_args.hostname = PSIONHOSTNAME;
+ nfs_args.flags = NFSMNT_INT | NFSMNT_HOSTNAME | NFSMNT_NOCTO |
+ NFSMNT_RETRANS | NFSMNT_TIMEO | NFSMNT_WSIZE | NFSMNT_RSIZE;
+#endif
+
+#ifdef __FreeBSD__
+#if __FreeBSD_version >= 300001
+ nfs_args.version = NFS_ARGSVERSION;
+#endif
+ nfs_args.addr = (struct sockaddr *) &sain;
+ nfs_args.addrlen = sizeof(sain);
+ nfs_args.sotype = SOCK_DGRAM;
+ nfs_args.fh = (void *) root_fh;
+ nfs_args.fhsize = sizeof(*root_fh);
+ nfs_args.wsize = PBUFSIZE;
+ nfs_args.rsize = PBUFSIZE;
+ nfs_args.retrans = 10;
+ /* 1 minute timeout - see below */
+ nfs_args.timeo = 600;
+ nfs_args.hostname = PSIONHOSTNAME;
+ nfs_args.flags =
+ NFSMNT_INT |
+ NFSMNT_SOFT |
+ NFSMNT_RETRANS |
+ NFSMNT_TIMEO |
+ NFSMNT_WSIZE |
+ NFSMNT_RSIZE;
+ mount_flags = MNT_NOSUID | MNT_NODEV | MNT_NOEXEC | MNT_NOATIME;
+#endif
+
+#ifdef __NetBSD__
+ nfs_args.addrlen = sizeof(sain);
+ nfs_args.sotype = SOCK_DGRAM;
+ nfs_args.maxgrouplist = NGROUPS;
+ nfs_args.readahead = 1;
+ nfs_args.addr = (struct sockaddr *) &sain;
+ nfs_args.fh = (void *) root_fh;
+ nfs_args.wsize = PBUFSIZE;
+ nfs_args.rsize = PBUFSIZE;
+ nfs_args.retrans = 10;
+ nfs_args.timeo = 600;
+ nfs_args.hostname = PSIONHOSTNAME;
+ nfs_args.flags = NFSMNT_INT | NFSMNT_RETRANS | NFSMNT_TIMEO
+ | NFSMNT_NOCONN | NFSMNT_DUMBTIMR | NFSMNT_MYWRITE
+ | NFSMNT_WSIZE | NFSMNT_RSIZE;
+#endif
+
+#if defined(_IBMR2)
+ nfs_args.addr = sain;
+ nfs_args.fh = *(fhandle_t *) root_fh;
+ nfs_args.wsize = PBUFSIZE;
+ nfs_args.rsize = PBUFSIZE;
+ nfs_args.retrans = 0; /* Shouldn't need bigger retrans since there is
+ only one biod. Somebody prove it ? Nice feature. */
+ nfs_args.biods = 1;
+ nfs_args.timeo = 150;
+ nfs_args.hostname = PSIONHOSTNAME;
+ nfs_args.flags = NFSMNT_INT | NFSMNT_HOSTNAME | NFSMNT_BIODS |
+ NFSMNT_RETRANS | NFSMNT_TIMEO | NFSMNT_WSIZE | NFSMNT_RSIZE;
+#endif
+
+ mntdir = dir;
+ switch (pid = fork()) {
+ case 0:
+ break;
+ case -1:
+ perror("fork");
+ exit(1);
+ default:
+ if (debug)
+ printf("Going to mount...\n");
+
+#if defined(__sgi) || (defined(sun) && defined(__SVR4))
+ if (mount("", dir, MS_DATA, "nfs", &nfs_args, sizeof(nfs_args)))
+#endif
+#if defined(__NetBSD__) || defined(__NeXT__)
+ if (mount(MOUNT_NFS, dir, 0, (caddr_t) & nfs_args))
+#endif
+#ifdef hpux
+ if (vfsmount(MOUNT_NFS, dir, 0, &nfs_args))
+#endif
+#if defined(sun) && !defined(__SVR4)
+ if (mount("nfs", dir, M_NEWTYPE, (caddr_t) & nfs_args))
+#endif
+#ifdef linux
+ if (mount("nfs", dir, "nfs", mount_flags, &nfs_mount_data))
+#endif
+#ifdef _IBMR2
+ if (aix3_mount("psion:loc", dir, 0, MOUNT_TYPE_NFS, &nfs_args, "plpnfsd"))
+#endif
+
+#ifdef __FreeBSD__
+#if __FreeBSD_version >= 300001
+ if (mount("nfs", dir, mount_flags, &nfs_args))
+#else
+ if (mount(MOUNT_NFS, dir, mount_flags, &nfs_args))
+#endif
+#endif
+
+ {
+ extern int errno;
+
+ fprintf(stderr, "nfs mount %s: (errno %d) ", dir, errno);
+ perror("");
+ kill(pid, SIGTERM);
+ exit(0);
+ } else {
+#ifndef DONT_UPDATE_MTAB
+ FILE *mfp;
+ struct mntent mnt;
+#if defined(sun) && defined(__SVR4) /*gec */
+ char tim[32];
+#endif
+
+ if (debug)
+ printf("Mount succeded, making mtab entry.\n");
+
+#if defined(sun) && defined(__SVR4) /*gec */
+ mnt.mnt_special = nfshost;
+ mnt.mnt_mountp = mntdir;
+ mnt.mnt_fstype = "nfs";
+ mnt.mnt_mntopts = "hard,intr"; /* dev=??? */
+ sprintf(tim, "%ld", time(NULL)); /* umount crashes! without this */
+ mnt.mnt_time = tim;
+#else
+ mnt.mnt_fsname = nfshost;
+ mnt.mnt_dir = mntdir;
+ mnt.mnt_type = "nfs";
+ mnt.mnt_opts = "hard,intr";
+ mnt.mnt_freq = mnt.mnt_passno = 0;
+#endif
+
+ if ((mfp = setmntent(MTAB_PATH, "a")))
+ addmntent(mfp, &mnt);
+ else
+ perror(MTAB_PATH);
+ endmntent(mfp);
+#endif /* !DONT_UPDATE_MTAB */
+ }
+ exit(0);
+ }
+
+/*** Third part: let's go */
+ printf("plpnfsd: to stop the server do \"ls %s/exit\". (pid %d)\n",
+ mntdir, (int) getpid());
+
+#if defined(sun) && !defined(__SVR4)
+ dtbsize = _rpc_dtablesize();
+#else
+ dtbsize = FD_SETSIZE;
+#endif
+
+ /*
+ * Signal handling, etc. should only happen in one process, so let's
+ * make it this one (the other one might well go away). We really
+ * ought to block off the other signals, but that's OK...
+ */
+ signal(SIGUSR1, usr1_handler);
+ signal(SIGHUP, hup_handler);
+
+ for (;;) {
+ fd_set readfd;
+ struct timeval tv;
+ struct cache *cp;
+ struct dcache *dcp;
+
+ readfd = svc_fdset;
+ tv.tv_sec = 2;
+ tv.tv_usec = 0;
+
+ ret = select(dtbsize, &readfd, 0, 0, &tv);
+ if (ret > 0)
+ svc_getreqset(&readfd);
+ if (ret != 0)
+ continue;
+
+ /* Do some housekeeping */
+
+ if (exiting)
+ doexit();
+
+ /*
+ * Solaris sends blocks in a way which is not very pleasent
+ * for us. It sends blocks 0,1,2,3,4,5,6, then 9,10,11 and
+ * do on. A little bit later block 7 and 8 arrives. This "bit"
+ * is more that 2 seconds, it is about 6 seconds. It occurs,
+ * if we're rewriting a file. We set MAXWRITE to 15, meaning
+ * that we are waiting for 30 seconds to receive the missing
+ * blocks.
+ */
+
+#define MAXWRITE 15
+ doclean = 1;
+ for (cp = attrcache; cp; cp = cp->next)
+ for (dcp = cp->dcache; dcp; dcp = dcp->next)
+ if (dcp->towrite) {
+ if (debug)
+ printf("\twaiting for block %d in %s to write (%d)\n",
+ dcp->offset, get_num(cp->inode)->name, dcp->towrite);
+ if (++dcp->towrite <= MAXWRITE)
+ doclean = 0; /* Wait with cleaning */
+ }
+ if (doclean) {
+ for (cp = attrcache; cp; cp = cp->next)
+ for (dcp = cp->dcache; dcp; dcp = dcp->next)
+ if (dcp->towrite)
+ printf("PLPNFSD WARNING: file %s block at %d not written\n",
+ get_num(cp->inode)->name, dcp->offset);
+ clean_cache(&attrcache);
+ query_cache = 0; /* clear the GETDENTS "cache". */
+ }
+ ret = 1 /* FRITZ fd_is_still_alive(psionfd, 0) */ ;
+ if (isalive && !ret) {
+ if (debug)
+ printf("Disconnected...\n");
+ } else if (!isalive && ret) {
+ if (debug)
+ printf("Connected...\n");
+ }
+ isalive = ret;
+ }
+}
diff --git a/plpnfsd/mp_pfs_ops.c b/plpnfsd/mp_pfs_ops.c
new file mode 100644
index 0000000..9b4d6f5
--- /dev/null
+++ b/plpnfsd/mp_pfs_ops.c
@@ -0,0 +1,1040 @@
+#include "OSdefs.h"
+#include <stdio.h>
+#include <ctype.h>
+#if defined(__SVR4) || defined(__GLIBC__)
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#endif
+#include "nfs_prot.h"
+#include "mp.h"
+#include "rfsv_api.h"
+
+static device *devices;
+struct cache *attrcache;
+
+/*
+ * Nfsd returned NFSERR_STALE if the psion wasn't present, but I didn't like
+ * it because the kernel returns the same when the nfsd itself is absent
+ */
+
+#define NO_PSION NFSERR_NXIO
+
+/* FIXME: Send create attributes */
+static struct diropres *
+create_it(createargs *ca, int isdir)
+{
+ static struct diropres res;
+ p_inode *dirinode = get_num(fh2inode(ca->where.dir.data));
+ char *name = dirinode->name;
+ fattr *fp;
+ p_inode *inode;
+ long phandle;
+ int rfsv_ret;
+
+ if (debug)
+ printf("\tcreate: in %s %s (%#o, %d)\n",
+ name, ca->where.name, ca->attributes.mode, isdir);
+
+ name = build_path(name, ca->where.name);
+
+ if (isdir)
+ rfsv_ret = rfsv_mkdir(name);
+ else {
+ rfsv_ret = rfsv_fcreate(0x200, name, &phandle);
+ if (rfsv_ret == 0)
+ rfsv_ret = rfsv_fclose(phandle);
+ }
+ if (rfsv_ret) {
+ res.status = psion_alive ? NFSERR_NAMETOOLONG : NO_PSION;
+ return &res;
+ }
+ inode = get_nam(name);
+ inode2fh(inode->inode, res.diropres_u.diropres.file.data);
+
+ fp = &res.diropres_u.diropres.attributes;
+ bzero((char *) fp, sizeof(fp));
+ if (isdir) {
+ fp->type = NFDIR;
+ fp->mode = NFSMODE_DIR | 0700;
+ fp->nlink = 2;
+ } else {
+ fp->type = NFREG;
+ fp->mode = NFSMODE_REG | 0600;
+ fp->nlink = 1;
+ }
+
+ fp->uid = root_fattr.uid;
+ fp->gid = root_fattr.gid;
+ fp->blocksize = BLOCKSIZE;
+ fp->fileid = inode->inode;
+ fp->atime.seconds = fp->mtime.seconds = fp->ctime.seconds = time((time_t *) 0);
+
+ res.status = NFS_OK;
+
+ rem_cache(&attrcache, dirinode->inode);
+ rem_cache(&attrcache, inode->inode);
+ add_cache(&attrcache, inode->inode, fp);
+ return &res;
+}
+
+struct diropres *
+nfsproc_create_2(createargs *ca)
+{
+ return create_it(ca, 0);
+}
+
+struct diropres *
+nfsproc_mkdir_2(createargs *ca)
+{
+ return create_it(ca, 1);
+}
+
+static void
+attr2pattr(long oattr, long nattr, long *psisattr, long *psidattr)
+{
+ /*
+ * Following flags have to be set in order to let backups
+ * work properly
+ */
+ *psisattr = *psidattr = 0;
+ if ((oattr & 0200) != (nattr & 0200)) {
+ if (nattr & 0200) /* readonly */
+ *psidattr |= 0x01;
+ else
+ *psisattr |= 0x01;
+ }
+ if ((oattr & 0020) != (nattr & 0020)) {
+ if (nattr & 0020) /* group-write -> archive */
+ *psisattr |= 0x20;
+ else
+ *psidattr |= 0x20;
+ }
+ if ((oattr & 0004) != (nattr & 0004)) {
+ if (nattr & 0004) /* Not world-read -> hidden */
+ *psidattr |= 0x02;
+ else
+ *psisattr |= 0x02;
+ }
+ if ((oattr & 0002) != (nattr & 0002)) {
+ if (nattr & 0002) /* world-write -> system */
+ *psisattr |= 0x04;
+ else
+ *psidattr |= 0x04;
+ }
+}
+
+static void
+dpattr2attr(long psiattr, long size, long ftime, fattr *fp, int inode)
+{
+ bzero((char *) fp, sizeof(*fp));
+
+ if (psiattr & 0x10) {
+ fp->type = NFDIR;
+ fp->mode = NFSMODE_DIR | 0700;
+ /*
+ * Damned filesystem.
+ * We have to count the number of subdirectories
+ * on the psion.
+ */
+ fp->nlink = 0;
+ fp->size = BLOCKSIZE;
+ fp->blocks = 1;
+ } else {
+ fp->type = NFREG;
+ fp->mode = NFSMODE_REG;
+ fp->nlink = 1;
+ fp->size = size;
+ fp->blocks = (fp->size + BLOCKSIZE - 1) / BLOCKSIZE;
+
+ /*
+ * Following flags have to be set in order to let backups
+ * work properly
+ */
+ fp->mode |= 0400; /* File readable (?) */
+ if (!(psiattr & 0x01))
+ fp->mode |= 0200; /* File writeable */
+ /* fp->mode |= 0100; File executable */
+ if (!(psiattr & 0x02))
+ fp->mode |= 0004; /* Not Hidden <-> world read */
+ if (psiattr & 0x04)
+ fp->mode |= 0002; /* System <-> world write */
+ if (psiattr & 0x40)
+ fp->mode |= 0001; /* Volume <-> world exec */
+ if (psiattr & 0x20)
+ fp->mode |= 0020; /* Modified <-> group write */
+ /* fp->mode |= 0040; Byte <-> group read */
+ /* fp->mode |= 0010; Text <-> group exec */
+ }
+
+ fp->uid = root_fattr.uid;
+ fp->gid = root_fattr.gid;
+ fp->blocksize = BLOCKSIZE;
+ fp->fileid = inode;
+ fp->rdev = fp->fsid = FID;
+ fp->atime.seconds = ftime;
+ fp->mtime.seconds = fp->ctime.seconds = fp->atime.seconds;
+}
+
+static void
+pattr2attr(long psiattr, long size, long ftime, fattr *fp, unsigned char *fh)
+{
+ bzero((char *) fp, sizeof(*fp));
+
+ if (psiattr & 0x10) {
+ fp->type = NFDIR;
+ fp->mode = NFSMODE_DIR | 0700;
+ /*
+ * Damned filesystem.
+ * We have to count the number of subdirectories
+ * on the psion.
+ */
+ fp->nlink = 0;
+ fp->size = BLOCKSIZE;
+ fp->blocks = 1;
+ } else {
+ fp->type = NFREG;
+ fp->mode = NFSMODE_REG;
+ fp->nlink = 1;
+ fp->size = size;
+ fp->blocks = (fp->size + BLOCKSIZE - 1) / BLOCKSIZE;
+
+ /*
+ * Following flags have to be set in order to let backups
+ * work properly
+ */
+ fp->mode |= 0400; /* File readable (?) */
+ if (!(psiattr & 0x01))
+ fp->mode |= 0200; /* File writeable */
+ /* fp->mode |= 0100; File executable */
+ if (!(psiattr & 0x02))
+ fp->mode |= 0004; /* Not Hidden <-> world read */
+ if (psiattr & 0x04)
+ fp->mode |= 0002; /* System <-> world write */
+ if (psiattr & 0x40)
+ fp->mode |= 0001; /* Volume <-> world exec */
+ if (psiattr & 0x20)
+ fp->mode |= 0020; /* Modified <-> group write */
+ /* fp->mode |= 0040; Byte <-> group read */
+ /* fp->mode |= 0010; Text <-> group exec */
+ }
+
+ fp->uid = root_fattr.uid;
+ fp->gid = root_fattr.gid;
+ fp->blocksize = BLOCKSIZE;
+ fp->fileid = fh2inode((char *) fh);
+ fp->rdev = fp->fsid = FID;
+ fp->atime.seconds = ftime;
+ fp->mtime.seconds = fp->ctime.seconds = fp->atime.seconds;
+}
+
+static int
+query_devices()
+{
+ device *dp, *np;
+ int link_count = 2; /* set the root link count */
+
+ if (query_cache)
+ return 0;
+ query_cache = 1;
+ for (dp = devices; dp; dp = np) {
+ np = dp->next;
+ free(dp->name);
+ free(dp);
+ }
+ devices = 0;
+ if (rfsv_drivelist(&link_count, &devices))
+ return 1;
+ root_fattr.nlink = link_count;
+ return 0;
+}
+
+static int
+mp_dircount(p_inode *inode, long *count)
+{
+ dentry *e = NULL;
+ long ret;
+
+ *count = 0;
+ if (debug)
+ printf("\tdircount: dir\n");
+ if ((ret = rfsv_dir(dirname(inode->name), &e)))
+ return ret;
+ while (e) {
+ fattr fp;
+ char *bp;
+ dentry *o;
+ int ni;
+
+ bp = filname(e->name);
+ ni = get_nam(build_path(inode->name, bp))->inode;
+ free(e->name);
+ if (!search_cache(attrcache, ni)) {
+ dpattr2attr(e->attr, e->size, e->time, &fp, ni);
+ add_cache(&attrcache, ni, &fp);
+ }
+ o = e;
+ e = e->next;
+ free(o);
+ (*count)++;
+ }
+ return 0;
+}
+
+struct attrstat *
+nfsproc_getattr_2(struct nfs_fh *fh)
+{
+ static struct attrstat res;
+ p_inode *inode = get_num(fh2inode(fh->data));
+ fattr *fp = &res.attrstat_u.attributes;
+ struct cache *cp;
+ long pattr;
+ long psize;
+ long ptime;
+ long dcount;
+ int l;
+
+ if (debug)
+ printf("\tgetattr:'%s',%d\n", inode->name, inode->inode);
+ res.status = NFS_OK;
+
+ if ((cp = search_cache(attrcache, inode->inode))) {
+ if (debug)
+ printf("\t\tgetattr: cache hit\n");
+ *fp = cp->attr; /* gotcha */
+ if (fp->type == NFDIR) {
+ if (mp_dircount(inode, &dcount)) {
+ res.status = psion_alive ? NFSERR_NOENT : NO_PSION;
+ return &res;
+ }
+ if (fp->nlink != (dcount + 2))
+ fp->mtime.seconds = time(0);
+ fp->nlink = dcount + 2;
+ cp->attr = *fp;
+ }
+ return &res;
+ }
+ l = strlen(inode->name);
+
+ if (inode->inode == root_fattr.fileid) {
+ /* It's the root inode */
+ if (debug)
+ printf("\t\tgetattr:root inode (%#o)\n", root_fattr.mode);
+
+ if (query_devices()) /* root inode is always there */
+ root_fattr.nlink = 2;
+ *fp = root_fattr;
+ } else if (l == 2 && inode->name[1] == ':') {
+ if (debug)
+ printf("\tgetattr:device\n");
+ res.status = NO_PSION;
+ if (!query_devices()) {
+ device *dp;
+
+ for (dp = devices; dp; dp = dp->next) {
+ if (debug)
+ printf("\tcmp '%c', '%s'\n", dp->letter,
+ inode->name);
+ if (dp->letter == inode->name[0])
+ break;
+ }
+ if (debug)
+ printf("\tdevice: %s exists\n", (dp)?"":"not");
+ if (dp) {
+ res.status = NFS_OK;
+ *fp = root_fattr;
+ /* If it's writeable... */
+ if (dp->attrib != 7)
+ fp->mode |= 0200;
+ fp->fileid = inode->inode;
+ if (mp_dircount(inode, &dcount)) {
+ res.status = psion_alive ? NFSERR_NOENT : NO_PSION;
+ return &res;
+ }
+ if (fp->nlink != (dcount + 2))
+ fp->mtime.seconds = time(0);
+ fp->nlink = dcount + 2;
+ }
+ }
+ } else {
+ if (debug)
+ printf("\tgetattr:fileordir\n");
+ /* It's a normal file/dir */
+ if (rfsv_getattr(inode->name, &pattr, &psize, &ptime)) {
+ res.status = psion_alive ? NFSERR_NOENT : NO_PSION;
+ return &res;
+ }
+ pattr2attr(pattr, psize, ptime, fp, (unsigned char *) fh->data);
+ if (fp->type == NFDIR) {
+ if (mp_dircount(inode, &dcount)) {
+ res.status = psion_alive ? NFSERR_NOENT : NO_PSION;
+ return &res;
+ }
+ if (fp->nlink != (dcount + 2))
+ fp->mtime.seconds = time(0);
+ fp->nlink = dcount + 2;
+ }
+ }
+ add_cache(&attrcache, inode->inode, fp);
+ return &res;
+}
+
+struct diropres *
+nfsproc_lookup_2(diropargs *da)
+{
+ static struct diropres res;
+ struct attrstat *gres;
+ p_inode *inode = get_num(fh2inode(da->dir.data));
+ char *fp = res.diropres_u.diropres.file.data;
+
+ if (!inode) {
+ if (debug)
+ printf("lookup: stale fh\n");
+ res.status = NO_PSION;
+ return &res;
+ }
+ if (debug)
+ printf("\tlookup: in '%s'(%d) searching '%s'\n",
+ inode->name, inode->inode, da->name);
+
+ if (inode->inode == root_fattr.fileid && !strcmp(da->name, "exit")) {
+ exiting = 5; /* Lets try it 5 times (10 sec) */
+ res.status = NFSERR_EXIST;
+ return &res;
+ }
+ if (inode->inode == root_fattr.fileid && !strcmp(da->name, "debug")) {
+ debug = (debug + 1) & 3; /* debug level of 0,1,2 & 3 */
+ printf("Set debug level to %d\n", debug);
+ res.status = NFSERR_EXIST;
+ return &res;
+ }
+ if (!strcmp(da->name, "."))
+ inode2fh(fh2inode(da->dir.data), fp);
+ else if (!strcmp(da->name, ".."))
+ inode2fh(getpinode(inode), fp);
+ else
+ inode2fh(get_nam(build_path(inode->name, da->name))->inode, fp);
+
+ gres = nfsproc_getattr_2((struct nfs_fh *) fp);
+
+ res.status = gres->status;
+ res.diropres_u.diropres.attributes = gres->attrstat_u.attributes;
+ return &res;
+}
+
+#define RA_MAXCOUNT ~0
+
+static void
+addentry(readdirargs *ra, entry ***where, int *searchi, int inode, char *name)
+{
+ int l, rndup;
+
+ if (*searchi) {
+ if (*searchi == inode)
+ *searchi = 0;
+ return;
+ }
+ if (ra->count == RA_MAXCOUNT)
+ return;
+
+ /*
+ * From ddan@au.stratus.com Wed Feb 8 04:14 MET 1995
+ * Modifed in pl7.a by Dan Danz to fix problem of missing files in readdir
+ *
+ * In a shotgun attempt at fixing this, I surmised that perhaps addentry
+ * was putting one too many entries in the result, so I increased
+ * the number of bytes for each entry by +8 ... my reasoning was that
+ * you need to account for the filename pointer and for the cookie int ...
+ * but in retrospect, I'm not sure about this reasoning. HOWEVER, it appears
+ * that this fixes the problem.
+ * FIXED: See next comment (Rudi)
+ */
+
+ /*
+ * Count the bytes needed for the xdr encoded data. Xdr is trickier than
+ * one (me :-) might think: Xdr converts a string into
+ * length (4 bytes) + data (rounded up to 4 bytes).
+ */
+#define XDR_UNIT 4
+ l = strlen(name);
+ if ((rndup = l % XDR_UNIT) > 0)
+ l += XDR_UNIT - rndup;
+ l += XDR_UNIT; /* Length of name */
+ l += sizeof(entry);
+
+ if (l > ra->count) {
+ ra->count = RA_MAXCOUNT;
+ return;
+ }
+ ra->count -= l;
+
+ **where = (entry *) malloc(sizeof(entry));
+ (**where)->fileid = inode;
+ (**where)->name = (char *) strdup(name);
+ *(int *) (**where)->cookie = inode;
+ (**where)->nextentry = 0;
+ *where = &(**where)->nextentry;
+}
+
+struct readdirres *
+nfsproc_readdir_2(readdirargs *ra)
+{
+ static readdirres res;
+ p_inode *inode = get_num(fh2inode(ra->dir.data));
+ entry *centry, *fentry, **cp;
+ char *bp;
+ int searchinode;
+
+ if (!inode) {
+ if (debug)
+ printf("readdir: stale fh\n");
+ res.status = NO_PSION;
+ return &res;
+ }
+ cp = &res.readdirres_u.reply.entries;
+ for (fentry = *cp; fentry; fentry = centry) {
+ centry = fentry->nextentry;
+ free(fentry->name);
+ free(fentry);
+ }
+ *cp = 0;
+ searchinode = *(int *) ra->cookie;
+
+ if (debug)
+ printf("\treaddir: %s, cookie:%x, count:%d\n",
+ inode->name, searchinode, ra->count);
+
+/* . & .. */
+ addentry(ra, &cp, &searchinode, inode->inode, ".");
+ addentry(ra, &cp, &searchinode, getpinode(inode), "..");
+
+ if (inode->inode == root_fattr.fileid) { /* Root directory */
+ device *dp;
+
+ if (query_devices()) {
+ res.status = NO_PSION;
+ return &res;
+ }
+ for (dp = devices; dp; dp = dp->next) {
+ char n[3];
+ sprintf(n, "%c:", dp->letter);
+ addentry(ra, &cp, &searchinode, get_nam(dp->name)->inode, n);
+ }
+ } else {
+ dentry *e = NULL;
+ if (debug)
+ printf("\tnfsdir: dir\n");
+ if (rfsv_dir(dirname(inode->name), &e)) {
+ res.status = psion_alive ? NFSERR_NOENT : NO_PSION;
+ return &res;
+ }
+ while (e) {
+ fattr fp;
+ dentry *o;
+ int ni;
+
+ bp = filname(e->name);
+ ni = get_nam(build_path(inode->name, bp))->inode;
+ addentry(ra, &cp, &searchinode, ni, (char *) bp);
+ free(e->name);
+ dpattr2attr(e->attr, e->size, e->time, &fp, ni);
+ add_cache(&attrcache, ni, &fp);
+ o = e;
+ e = e->next;
+ free(o);
+ }
+ }
+
+ res.readdirres_u.reply.eof = ra->count == RA_MAXCOUNT ? 0 : 1;
+ res.status = NFS_OK;
+ return &res;
+}
+
+struct attrstat *
+nfsproc_setattr_2(sattrargs *sa)
+{
+ static struct attrstat res;
+ p_inode *inode = get_num(fh2inode(sa->file.data));
+ fattr *fp;
+
+ if (!inode) {
+ if (debug)
+ printf("setattr: stale fh\n");
+ res.status = NO_PSION;
+ return &res;
+ }
+ if (debug)
+ printf("\tsetattr %s called\n", inode->name);
+ res = *nfsproc_getattr_2(&sa->file);
+ if (res.status != NFS_OK)
+ return &res;
+ fp = &res.attrstat_u.attributes;
+
+ if ((fp->type == NFREG) &&
+ (sa->attributes.size != -1) &&
+ (sa->attributes.size != fp->size)) {
+ if (debug)
+ printf("\t\tsetattr truncating to %d bytes\n", sa->attributes.size);
+ if (rfsv_setsize(inode->name, sa->attributes.size) != 0) {
+ res.status = psion_alive ? NFSERR_ROFS : NO_PSION;
+ return &res;
+ }
+ fp->size = sa->attributes.size;
+ rem_cache(&attrcache, inode->inode);
+ add_cache(&attrcache, inode->inode, fp);
+ }
+ if ((sa->attributes.mtime.seconds != fp->mtime.seconds) &&
+ (sa->attributes.mtime.seconds != -1)) {
+ if (rfsv_setmtime(inode->name, sa->attributes.mtime.seconds)) {
+ res.status = (psion_alive) ? NFSERR_ACCES : NO_PSION;
+ return &res;
+ }
+ fp->mtime.seconds = fp->atime.seconds = sa->attributes.mtime.seconds;
+ rem_cache(&attrcache, inode->inode);
+ add_cache(&attrcache, inode->inode, fp);
+ }
+ if ((sa->attributes.mode != fp->mode) &&
+ (sa->attributes.mode != -1)) {
+ long psisattr, psidattr;
+ attr2pattr(sa->attributes.mode, fp->mode, &psisattr, &psidattr);
+ if (rfsv_setattr(inode->name, psisattr, psidattr)) {
+ res.status = (psion_alive) ? NFSERR_ACCES : NO_PSION;
+ return &res;
+ }
+ fp->mode = sa->attributes.mode;
+ rem_cache(&attrcache, inode->inode);
+ add_cache(&attrcache, inode->inode, fp);
+ }
+ res.status = NFS_OK;
+ return &res;
+}
+
+static nfsstat *
+remove_it(diropargs *da, int isdir)
+{
+ static nfsstat res;
+ p_inode *inode = get_num(fh2inode(da->dir.data));
+ long rfsv_res;
+
+ if (!inode) {
+ if (debug)
+ printf("setattr: stale fh\n");
+ res = NO_PSION;
+ return &res;
+ }
+ if (debug)
+ printf("\tremove_it: in %s: %s (%d)\n", inode->name, da->name, isdir);
+
+ if (isdir)
+ rfsv_res = rfsv_rmdir(build_path(inode->name, da->name));
+ else
+ rfsv_res = rfsv_remove(build_path(inode->name, da->name));
+ if (rfsv_res != 0) {
+ res = psion_alive ? NFSERR_ACCES : NO_PSION;
+ return &res;
+ }
+ rem_cache(&attrcache, inode->inode);
+ res = NFS_OK;
+ return &res;
+}
+
+nfsstat *
+nfsproc_remove_2(diropargs *da)
+{
+ return remove_it(da, 0);
+}
+
+nfsstat *
+nfsproc_rmdir_2(diropargs *da)
+{
+ return remove_it(da, 1);
+}
+
+nfsstat *
+nfsproc_rename_2(renameargs *ra)
+{
+ static nfsstat res;
+ p_inode *from = get_num(fh2inode(ra->from.dir.data));
+ p_inode *to = get_num(fh2inode(ra->to.dir.data));
+ char ldata[300], *old, c;
+
+ if (!from || !to) {
+ if (debug)
+ printf("rename: stale fh\n");
+ res = NO_PSION;
+ return &res;
+ }
+ strcpy(ldata + 1, build_path(to->name, ra->to.name));
+ *ldata = strlen(ldata + 1);
+ c = *ldata + 1;
+ old = build_path(from->name, ra->from.name);
+
+ if (debug)
+ printf("\tRename: %s -> %s\n", old, ldata + 1);
+ res = NFS_OK;
+ if (rfsv_rename(old, ldata + 1)) {
+ res = (psion_alive) ? NFSERR_ACCES : NO_PSION;
+ return &res;
+ }
+ if (res == NFS_OK) {
+ /* Preserve inode */
+ strcpy((char *) ldata, build_path(to->name, ra->to.name));
+ (void) re_nam(build_path(from->name, ra->from.name), ldata);
+ }
+ rem_cache(&attrcache, from->inode);
+ rem_cache(&attrcache, to->inode);
+ return &res;
+}
+
+/* ARGSUSED */
+struct statfsres *
+nfsproc_statfs_2(struct nfs_fh *fh)
+{
+ static statfsres res;
+ statfsokres *rp;
+ device *dp;
+
+ if (debug)
+ printf("\tstatfs..\n");
+
+ rp = &res.statfsres_u.reply;
+ rp->tsize = PBUFSIZE;
+ rp->bsize = BLOCKSIZE;
+ rp->blocks = rp->bfree = 0;
+ res.status = NFS_OK;
+
+ if (query_devices()) {
+ /* Allow to mount it whithout the psion attached */
+ if (psion_alive)
+ return &res; /* res.status = NO_PSION; Hmm */
+ }
+ for (dp = devices; dp; dp = dp->next) {
+ rp->blocks += (dp->total + BLOCKSIZE - 1) / BLOCKSIZE;
+ rp->bfree += (dp->free + BLOCKSIZE - 1) / BLOCKSIZE;
+ }
+ rp->bavail = rp->bfree;
+
+ return &res;
+}
+
+/*
+ * Problem:
+ * Since we are slow (Max 2Kbyte/s) and the biods are very impatient,
+ * we receive each request (number of biods + 1 for the kernel itself)
+ * times, this number can be lower for the last block. :-(
+ * Solution: (not the best, probably)
+ * Cache the read data. This cache will be invalidated if there are
+ * no more requests in the queue for at least XXX seconds.
+ * See also write :-(
+ */
+struct readres *
+nfsproc_read_2(struct readargs *ra)
+{
+ static struct readres res;
+ static unsigned char rop[NFS_MAXDATA];
+ p_inode *inode = get_num(fh2inode(ra->file.data));
+ fattr *fp;
+ struct cache *cp;
+ struct dcache *dcp;
+ long phandle;
+ long pattr;
+ long psize;
+ long ptime;
+ int len;
+
+ if (!inode) {
+ if (debug)
+ printf("read: stale fh\n");
+ res.status = NO_PSION;
+ return &res;
+ }
+ if (debug)
+ printf("\tread: %s off:%d count:%d\n", inode->name, ra->offset, ra->count);
+
+ cp = search_cache(attrcache, inode->inode);
+ if (cp && (dcp = search_dcache(cp, ra->offset, ra->count))) {
+ if (debug)
+ printf("\tread: dcache hit\n");
+ res.readres_u.reply.attributes = cp->attr;
+ bcopy(dcp->data, res.readres_u.reply.data.data_val, ra->count);
+ res.readres_u.reply.data.data_len = ra->count;
+
+ res.status = NFS_OK;
+ return &res;
+ }
+ if (rfsv_fopen(1, inode->name, &phandle) != 0) {
+ res.status = psion_alive ? NFSERR_NOENT : NO_PSION;
+ return &res;
+ }
+ if (rfsv_read(rop, ra->offset,
+ ra->count, phandle) < 0) {
+ rfsv_fclose(phandle);
+ res.status = NO_PSION;
+ return &res;
+ }
+ rfsv_fclose(phandle);
+ rfsv_getattr(inode->name, &pattr, &psize, &ptime);
+ fp = &res.readres_u.reply.attributes;
+ pattr2attr(pattr, psize, ptime, fp, (unsigned char *) ra->file.data);
+ if (cp == 0)
+ cp = add_cache(&attrcache, inode->inode, fp);
+
+ len = fp->size - ra->offset;
+ if (len > ra->count)
+ len = ra->count;
+ if (fp->size < ra->offset)
+ len = 0;
+ if (debug > 1)
+ printf("Read: filesize %d read %d @ %d\n", fp->size, len, ra->offset);
+ res.readres_u.reply.data.data_len = len;
+ res.readres_u.reply.data.data_val = (char *) rop;
+
+ if (len) {
+ dcp = add_dcache(cp, ra->offset, ra->count, rop);
+ dcp->towrite = 0; /* don't write it back */
+ }
+ res.status = NFS_OK;
+ return &res;
+}
+
+
+/*
+ * Returns cachepointer on full hit, 0 on partial or no hit,
+ * see below solaris comment
+ */
+
+static int
+addwritecache(struct cache *cp, int doff, int dlen, unsigned char *dp)
+{
+ struct dcache *dcp;
+ int len, changed, os, oe;
+ unsigned char *pd, *pc;
+
+ /*
+ * do the cachesearch: we are interested in partial hits, as we don't
+ * want to write anything twice (flash ram)
+ */
+ for (dcp = cp->dcache; dcp; dcp = dcp->next)
+ if (doff < dcp->offset + dcp->len && doff + dlen > dcp->offset)
+ break;
+
+ if (!dcp) {
+ /* phew, nothing fancy to do */
+ add_dcache(cp, doff, dlen, dp);
+ return 0;
+ }
+ os = doff > dcp->offset ? doff : dcp->offset;
+ oe = doff + dlen < dcp->offset + dcp->len ? doff + dlen : dcp->offset + dcp->len;
+ pd = dp + os - doff;
+ pc = dcp->data + os - dcp->offset;
+ len = oe - os;
+
+ changed = 0;
+ if (bcmp(pd, pc, len)) {
+ bcopy(pd, pc, len);
+ dcp->towrite = 1;
+ changed = 1;
+ }
+ if (doff >= dcp->offset && doff + dlen <= dcp->offset + dcp->len) {
+ if (debug)
+ printf("\twrite: full cache hit\n");
+ return !changed;
+ }
+ if (debug)
+ printf("\twrite: partial cache hit (off %d len %d)\n", dcp->offset, dcp->len);
+
+ /* Do we have some data below the cached area... */
+ if (doff < dcp->offset)
+ (void) addwritecache(cp, doff, dcp->offset - doff, dp);
+
+ /* ...or some above? */
+ len = (doff + dlen) - (dcp->offset + dcp->len);
+ if (len > 0)
+ (void) addwritecache(cp, dcp->offset + dcp->len, len, dp + dlen - len);
+
+ return 0;
+}
+
+
+
+/*
+ * The same problem here as above: we receive numerous requests,
+ * not even in a specified order. The only good thing is that each request
+ * up to the last is exactly the same size.
+ * A new problem:
+ * Since I dunno how to seek to a point beyond the end of the file (psion),
+ * I can't sopport the exact semantics of write. Such files will never be
+ * written completely. :-(
+ *
+ * Another dumb solaris (sysv?) problem: if the client is writing 512 byte
+ * blocks we receive following write requests:
+ * off 0 len 512, off 0 len 1024, off 0 len 1536, ... so on till len 4096,
+ * that means 4 times as much data as actually needed.
+ * We should check if the block was partially written, and write only the
+ * difference
+ */
+struct attrstat *
+nfsproc_write_2(writeargs *wa)
+{
+ static struct attrstat res;
+ p_inode *inode = get_num(fh2inode(wa->file.data));
+ struct cache *cp;
+ struct dcache *dcp;
+ fattr *fp;
+ struct attrstat *gres;
+ long phandle;
+ int len, dlen, doff;
+
+ if (!inode) {
+ if (debug)
+ printf("write: stale fh\n");
+ res.status = NO_PSION;
+ return &res;
+ }
+ if (debug)
+ printf("\twrite:%s off:%d l:%d\n", inode->name, wa->offset, wa->data.data_len);
+
+ dlen = wa->data.data_len;
+ doff = wa->offset;
+
+ /* fetch attributes */
+ if ((cp = search_cache(attrcache, inode->inode)) == 0) {
+ gres = nfsproc_getattr_2((struct nfs_fh *) wa->file.data);
+ if (gres->status != NFS_OK) {
+ res.status = gres->status;
+ return &res;
+ }
+ cp = search_cache(attrcache, inode->inode);
+ if (!cp)
+ abort();
+ }
+ fp = &cp->attr;
+ if (fp->size < doff + dlen)
+ fp->size = doff + dlen;
+ fp->blocks = (fp->size + (BLOCKSIZE - 1)) / BLOCKSIZE;
+ fp->atime.seconds = fp->mtime.seconds = fp->ctime.seconds = time(0);
+
+ res.attrstat_u.attributes = *fp;
+
+ if (addwritecache(cp, doff, dlen, (unsigned char *) wa->data.data_val)) {
+ res.status = NFS_OK;
+ return &res;
+ }
+/* Write out as many blocks from the cache as we can */
+ for (;;) {
+ if (debug > 2)
+ for (dcp = cp->dcache; dcp; dcp = dcp->next)
+ printf("\t\tCheck: %d=%d,%d,%d>=%d\n",
+ inode->inode, cp->inode, dcp->towrite,
+ cp->actual_size, dcp->offset);
+ for (dcp = cp->dcache; dcp; dcp = dcp->next)
+ if (dcp->towrite && cp->actual_size >= dcp->offset)
+ break;
+ if (!dcp) /* Can't write any blocks */
+ break;
+
+ if (debug)
+ printf("\twriting off: %d, len: %d, act: %d\n",
+ dcp->offset, dcp->len, cp->actual_size);
+
+ if (rfsv_fopen(0x200, inode->name, &phandle) != 0) {
+ if (debug)
+ printf("write: open failed\n");
+ res.status = psion_alive ? NFSERR_NOSPC : NO_PSION;
+ return &res;
+ }
+ if (rfsv_write(dcp->data, dcp->offset, dcp->len, phandle) != dcp->len) {
+ rfsv_fclose(phandle);
+ if (debug)
+ printf("write: dump failed\n");
+ res.status = psion_alive ? NFSERR_NOSPC : NO_PSION;
+ return &res;
+ }
+ rfsv_fclose(phandle);
+ dcp->towrite = 0;
+ len = dcp->offset + dcp->len;
+ if (len > cp->actual_size)
+ cp->actual_size = len;
+ if (debug)
+ printf("\twritten: new length: %d\n", cp->actual_size);
+ }
+
+ if (debug)
+ printf("\twrite -> ISOK (%d, %d %d)\n",
+ res.attrstat_u.attributes.size,
+ res.attrstat_u.attributes.fileid,
+ res.attrstat_u.attributes.fsid);
+ res.status = NFS_OK;
+ return &res;
+}
+
+/* Dummy routines */
+void *
+nfsproc_writecache_2()
+{
+ static char res;
+ if (debug)
+ printf("writecache???\n");
+ res = (char) NFSERR_FBIG;
+ return (void *) &res;
+}
+
+void *
+nfsproc_null_2()
+{
+ static char res;
+ if (debug)
+ printf("null.\n");
+ res = (char) NFSERR_FBIG;
+ return (void *) &res;
+}
+
+void *
+nfsproc_root_2()
+{
+ static char res;
+ if (debug)
+ printf("root????\n");
+ res = (char) NFSERR_FBIG;
+ return (void *) &res;
+}
+
+/*
+ * Links and symlinks are not supported on Psion
+ */
+
+/* ARGSUSED */
+nfsstat *
+nfsproc_link_2(linkargs *la)
+{
+ static nfsstat res;
+
+ if (debug)
+ printf("link..\n");
+ res = NFSERR_ACCES;
+ return &res;
+}
+
+/* ARGSUSED */
+struct readlinkres *
+nfsproc_readlink_2(struct nfs_fh *fh)
+{
+ static readlinkres res;
+
+ if (debug)
+ printf("readlink...\n");
+ res.status = NFSERR_ACCES;
+ return &res;
+}
+
+/* ARGSUSED */
+nfsstat *
+nfsproc_symlink_2(symlinkargs *sa)
+{
+ static nfsstat res;
+
+ if (debug)
+ printf("symlink..\n");
+ res = NFSERR_ACCES;
+ return &res;
+}
diff --git a/plpnfsd/mtab_aix.c b/plpnfsd/mtab_aix.c
new file mode 100644
index 0000000..46ed3c6
--- /dev/null
+++ b/plpnfsd/mtab_aix.c
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) 1990 Jan-Simon Pendry
+ * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jan-Simon Pendry at Imperial College, London.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * %W% (Berkeley) %G%
+ *
+ * $Id$
+ *
+ */
+
+
+#ifdef READ_MTAB_AIX3_STYLE
+
+#include <sys/mntctl.h>
+#include <sys/vmount.h>
+
+static struct mntent *mnt_dup(mp)
+struct vmount *mp;
+{
+ struct mntent *new_mp = ALLOC(mntent);
+
+ char *ty;
+ char *fsname = strdup(vmt2dataptr(mp, VMT_OBJECT));
+ new_mp->mnt_dir = strdup(vmt2dataptr(mp, VMT_STUB));
+ new_mp->mnt_opts = strdup(vmt2dataptr(mp, VMT_ARGS));
+ switch (mp->vmt_gfstype) {
+ case MNT_JFS:
+ ty = MTAB_TYPE_UFS;
+ new_mp->mnt_fsname = strdup(fsname);
+ break;
+
+ case MNT_NFS:
+ ty = MTAB_TYPE_NFS;
+ new_mp->mnt_fsname = str3cat((char *) 0,
+ vmt2dataptr(mp, VMT_HOSTNAME), ":", fsname);
+ break;
+
+ default:
+ ty = "unknown";
+ new_mp->mnt_fsname = strdup(fsname);
+ break;
+ }
+ new_mp->mnt_type = strdup(ty);
+ new_mp->mnt_passno = mp->vmt_vfsnumber;
+ new_mp->mnt_freq = 0;
+
+ free(fsname);
+
+ return new_mp;
+}
+
+/*
+ * Read a mount table into memory
+ */
+mntlist *read_mtab(fs)
+char *fs;
+{
+ mntlist **mpp, *mhp;
+
+ int i;
+ char *mntinfo = 0, *cp;
+ struct vmount *vp;
+ int ret;
+
+ /*
+ * First figure out size of mount table
+ * and allocate space for a copy...
+ * Then get mount table for real.
+ */
+ ret = mntctl(MCTL_QUERY, sizeof(i), &i);
+ if (ret == 0) {
+ mntinfo = xmalloc(i);
+ ret = mntctl(MCTL_QUERY, i, mntinfo);
+ }
+
+ if (ret <= 0) {
+ plog(XLOG_ERROR, "mntctl: %m");
+ goto out;
+ }
+#ifdef DEBUG
+ /*dlog("mntctl returns %d structures", ret);*/
+#endif /* DEBUG */
+
+ mpp = &mhp;
+ for (i = 0, cp = mntinfo; i < ret; i++, cp += vp->vmt_length) {
+ vp = (struct vmount *) cp;
+
+ /*
+ * Allocate a new slot
+ */
+ *mpp = ALLOC(mntlist);
+
+ /*
+ * Copy the data returned by mntctl
+ */
+ (*mpp)->mnt = mnt_dup(vp);
+
+ /*
+ * Move to next pointer
+ */
+ mpp = &(*mpp)->mnext;
+ }
+
+ *mpp = 0;
+
+out:
+ if (mntinfo)
+ free(mntinfo);
+ return mhp;
+}
+
+#endif /* READ_MTAB_AIX3_STYLE */
diff --git a/plpnfsd/nfs_prot_svc.c b/plpnfsd/nfs_prot_svc.c
new file mode 100644
index 0000000..f373e74
--- /dev/null
+++ b/plpnfsd/nfs_prot_svc.c
@@ -0,0 +1,231 @@
+/*
+ * Please do not edit this file.
+ * It was generated using rpcgen.
+ * And tuned by me (Rudi)
+ */
+
+#include "OSdefs.h"
+
+#define PORTMAP
+#ifdef __SVR4
+#include <unistd.h>
+#include <stdlib.h>
+#endif
+#include <stdio.h>
+#include <rpc/rpc.h>
+#include "nfs_prot.h"
+#include "mp.h"
+#ifdef __GLIBC__
+#include <string.h>
+#endif
+
+#if 0
+static void nfs_program_2();
+
+main()
+{
+ register SVCXPRT *transp;
+
+ (void) pmap_unset(NFS_PROGRAM, NFS_VERSION);
+
+ transp = svcudp_create(RPC_ANYSOCK);
+ if (transp == NULL) {
+ fprintf(stderr, "cannot create udp service.");
+ exit(1);
+ }
+ if (!svc_register(transp, NFS_PROGRAM, NFS_VERSION, nfs_program_2, IPPROTO_UDP)) {
+ fprintf(stderr, "unable to register (NFS_PROGRAM, NFS_VERSION, udp).");
+ exit(1);
+ }
+
+ transp = svctcp_create(RPC_ANYSOCK, 0, 0);
+ if (transp == NULL) {
+ fprintf(stderr, "cannot create tcp service.");
+ exit(1);
+ }
+ if (!svc_register(transp, NFS_PROGRAM, NFS_VERSION, nfs_program_2, IPPROTO_TCP)) {
+ fprintf(stderr, "unable to register (NFS_PROGRAM, NFS_VERSION, tcp).");
+ exit(1);
+ }
+
+ svc_run();
+ fprintf(stderr, "svc_run returned");
+ exit(1);
+ /* NOTREACHED */
+}
+#endif
+
+void
+nfs_program_2(rqstp, transp)
+ struct svc_req *rqstp;
+ register SVCXPRT *transp;
+{
+ union {
+ nfs_fh nfsproc_getattr_2_arg;
+ sattrargs nfsproc_setattr_2_arg;
+ diropargs nfsproc_lookup_2_arg;
+ nfs_fh nfsproc_readlink_2_arg;
+ readargs nfsproc_read_2_arg;
+ writeargs nfsproc_write_2_arg;
+ createargs nfsproc_create_2_arg;
+ diropargs nfsproc_remove_2_arg;
+ renameargs nfsproc_rename_2_arg;
+ linkargs nfsproc_link_2_arg;
+ symlinkargs nfsproc_symlink_2_arg;
+ createargs nfsproc_mkdir_2_arg;
+ diropargs nfsproc_rmdir_2_arg;
+ readdirargs nfsproc_readdir_2_arg;
+ nfs_fh nfsproc_statfs_2_arg;
+ } argument;
+ char *result;
+ bool_t (*xdr_argument)(), (*xdr_result)();
+ char *(*local)();
+
+ switch (rqstp->rq_proc) {
+ case NFSPROC_NULL:
+ xdr_argument = xdr_void;
+ xdr_result = xdr_void;
+ local = (char *(*)()) nfsproc_null_2;
+ break;
+
+ case NFSPROC_GETATTR:
+ xdr_argument = xdr_nfs_fh;
+ xdr_result = xdr_attrstat;
+ local = (char *(*)()) nfsproc_getattr_2;
+ break;
+
+ case NFSPROC_SETATTR:
+ xdr_argument = xdr_sattrargs;
+ xdr_result = xdr_attrstat;
+ local = (char *(*)()) nfsproc_setattr_2;
+ break;
+
+ case NFSPROC_ROOT:
+ xdr_argument = xdr_void;
+ xdr_result = xdr_void;
+ local = (char *(*)()) nfsproc_root_2;
+ break;
+
+ case NFSPROC_LOOKUP:
+ xdr_argument = xdr_diropargs;
+ xdr_result = xdr_diropres;
+ local = (char *(*)()) nfsproc_lookup_2;
+ break;
+
+ case NFSPROC_READLINK:
+ xdr_argument = xdr_nfs_fh;
+ xdr_result = xdr_readlinkres;
+ local = (char *(*)()) nfsproc_readlink_2;
+ break;
+
+ case NFSPROC_READ:
+ xdr_argument = xdr_readargs;
+ xdr_result = xdr_readres;
+ local = (char *(*)()) nfsproc_read_2;
+ break;
+
+ case NFSPROC_WRITECACHE:
+ xdr_argument = xdr_void;
+ xdr_result = xdr_void;
+ local = (char *(*)()) nfsproc_writecache_2;
+ break;
+
+ case NFSPROC_WRITE:
+ xdr_argument = xdr_writeargs;
+ xdr_result = xdr_attrstat;
+ local = (char *(*)()) nfsproc_write_2;
+ break;
+
+ case NFSPROC_CREATE:
+ xdr_argument = xdr_createargs;
+ xdr_result = xdr_diropres;
+ local = (char *(*)()) nfsproc_create_2;
+ break;
+
+ case NFSPROC_REMOVE:
+ xdr_argument = xdr_diropargs;
+ xdr_result = xdr_nfsstat;
+ local = (char *(*)()) nfsproc_remove_2;
+ break;
+
+ case NFSPROC_RENAME:
+ xdr_argument = xdr_renameargs;
+ xdr_result = xdr_nfsstat;
+ local = (char *(*)()) nfsproc_rename_2;
+ break;
+
+ case NFSPROC_LINK:
+ xdr_argument = xdr_linkargs;
+ xdr_result = xdr_nfsstat;
+ local = (char *(*)()) nfsproc_link_2;
+ break;
+
+ case NFSPROC_SYMLINK:
+ xdr_argument = xdr_symlinkargs;
+ xdr_result = xdr_nfsstat;
+ local = (char *(*)()) nfsproc_symlink_2;
+ break;
+
+ case NFSPROC_MKDIR:
+ xdr_argument = xdr_createargs;
+ xdr_result = xdr_diropres;
+ local = (char *(*)()) nfsproc_mkdir_2;
+ break;
+
+ case NFSPROC_RMDIR:
+ xdr_argument = xdr_diropargs;
+ xdr_result = xdr_nfsstat;
+ local = (char *(*)()) nfsproc_rmdir_2;
+ break;
+
+ case NFSPROC_READDIR:
+ xdr_argument = xdr_readdirargs;
+ xdr_result = xdr_readdirres;
+ local = (char *(*)()) nfsproc_readdir_2;
+ break;
+
+ case NFSPROC_STATFS:
+ xdr_argument = xdr_nfs_fh;
+ xdr_result = xdr_statfsres;
+ local = (char *(*)()) nfsproc_statfs_2;
+ break;
+
+ default:
+ svcerr_noproc(transp);
+ return;
+ }
+ memset((char *)&argument, 0, sizeof(argument));
+#if !defined(__SVR4) && !defined(__FreeBSD__)
+#ifdef __GLIBC__
+ if (!svc_getargs(transp, (xdrproc_t)xdr_argument, (caddr_t)&argument)) {
+#else
+ if (!svc_getargs(transp, xdr_argument, &argument)) {
+#endif
+#else
+ if (!svc_getargs(transp, xdr_argument, (char *)&argument)) {
+#endif
+ svcerr_decode(transp);
+ return;
+ }
+ result = (*local)(&argument, rqstp);
+#ifdef linux
+ if (result != NULL && !svc_sendreply(transp, (xdrproc_t) xdr_result, result)) {
+#else
+ if (result != NULL && !svc_sendreply(transp, xdr_result, result)) {
+#endif
+ svcerr_systemerr(transp);
+ }
+#if !defined(__SVR4) && !defined(__FreeBSD__)
+#ifdef __GLIBC__
+ if (!svc_freeargs(transp, (xdrproc_t)xdr_argument,(caddr_t)&argument)) {
+#else
+ if (!svc_freeargs(transp, xdr_argument, &argument)) {
+#endif
+#else
+ if (!svc_freeargs(transp, xdr_argument, (char *)&argument)) {
+#endif
+ fprintf(stderr, "unable to free arguments");
+ exit(1);
+ }
+ return;
+}
diff --git a/plpnfsd/nfs_prot_xdr.c b/plpnfsd/nfs_prot_xdr.c
new file mode 100644
index 0000000..acef303
--- /dev/null
+++ b/plpnfsd/nfs_prot_xdr.c
@@ -0,0 +1,518 @@
+/*
+ * Please do not edit this file.
+ * It was generated using rpcgen.
+ */
+
+#define PORTMAP
+#include <rpc/rpc.h>
+#include "nfs_prot.h"
+
+bool_t
+xdr_nfsstat(xdrs, objp)
+ XDR *xdrs;
+ nfsstat *objp;
+{
+ if (!xdr_enum(xdrs, (enum_t *)objp)) {
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+bool_t
+xdr_ftype(xdrs, objp)
+ XDR *xdrs;
+ ftype *objp;
+{
+ if (!xdr_enum(xdrs, (enum_t *)objp)) {
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+bool_t
+xdr_nfs_fh(xdrs, objp)
+ XDR *xdrs;
+ nfs_fh *objp;
+{
+ if (!xdr_opaque(xdrs, objp->data, NFS_FHSIZE)) {
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+bool_t
+xdr_nfstime(xdrs, objp)
+ XDR *xdrs;
+ nfstime *objp;
+{
+ if (!xdr_u_int(xdrs, &objp->seconds)) {
+ return (FALSE);
+ }
+ if (!xdr_u_int(xdrs, &objp->useconds)) {
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+bool_t
+xdr_fattr(xdrs, objp)
+ XDR *xdrs;
+ fattr *objp;
+{
+ if (!xdr_ftype(xdrs, &objp->type)) {
+ return (FALSE);
+ }
+ if (!xdr_u_int(xdrs, &objp->mode)) {
+ return (FALSE);
+ }
+ if (!xdr_u_int(xdrs, &objp->nlink)) {
+ return (FALSE);
+ }
+ if (!xdr_u_int(xdrs, &objp->uid)) {
+ return (FALSE);
+ }
+ if (!xdr_u_int(xdrs, &objp->gid)) {
+ return (FALSE);
+ }
+ if (!xdr_u_int(xdrs, &objp->size)) {
+ return (FALSE);
+ }
+ if (!xdr_u_int(xdrs, &objp->blocksize)) {
+ return (FALSE);
+ }
+ if (!xdr_u_int(xdrs, &objp->rdev)) {
+ return (FALSE);
+ }
+ if (!xdr_u_int(xdrs, &objp->blocks)) {
+ return (FALSE);
+ }
+ if (!xdr_u_int(xdrs, &objp->fsid)) {
+ return (FALSE);
+ }
+ if (!xdr_u_int(xdrs, &objp->fileid)) {
+ return (FALSE);
+ }
+ if (!xdr_nfstime(xdrs, &objp->atime)) {
+ return (FALSE);
+ }
+ if (!xdr_nfstime(xdrs, &objp->mtime)) {
+ return (FALSE);
+ }
+ if (!xdr_nfstime(xdrs, &objp->ctime)) {
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+bool_t
+xdr_sattr(xdrs, objp)
+ XDR *xdrs;
+ sattr *objp;
+{
+ if (!xdr_u_int(xdrs, &objp->mode)) {
+ return (FALSE);
+ }
+ if (!xdr_u_int(xdrs, &objp->uid)) {
+ return (FALSE);
+ }
+ if (!xdr_u_int(xdrs, &objp->gid)) {
+ return (FALSE);
+ }
+ if (!xdr_u_int(xdrs, &objp->size)) {
+ return (FALSE);
+ }
+ if (!xdr_nfstime(xdrs, &objp->atime)) {
+ return (FALSE);
+ }
+ if (!xdr_nfstime(xdrs, &objp->mtime)) {
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+bool_t
+xdr_filename(xdrs, objp)
+ XDR *xdrs;
+ filename *objp;
+{
+ if (!xdr_string(xdrs, objp, NFS_MAXNAMLEN)) {
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+bool_t
+xdr_nfspath(xdrs, objp)
+ XDR *xdrs;
+ nfspath *objp;
+{
+ if (!xdr_string(xdrs, objp, NFS_MAXPATHLEN)) {
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+bool_t
+xdr_attrstat(xdrs, objp)
+ XDR *xdrs;
+ attrstat *objp;
+{
+ if (!xdr_nfsstat(xdrs, &objp->status)) {
+ return (FALSE);
+ }
+ switch (objp->status) {
+ case NFS_OK:
+ if (!xdr_fattr(xdrs, &objp->attrstat_u.attributes)) {
+ return (FALSE);
+ }
+ default:
+ break;
+ }
+ return (TRUE);
+}
+
+bool_t
+xdr_sattrargs(xdrs, objp)
+ XDR *xdrs;
+ sattrargs *objp;
+{
+ if (!xdr_nfs_fh(xdrs, &objp->file)) {
+ return (FALSE);
+ }
+ if (!xdr_sattr(xdrs, &objp->attributes)) {
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+bool_t
+xdr_diropargs(xdrs, objp)
+ XDR *xdrs;
+ diropargs *objp;
+{
+ if (!xdr_nfs_fh(xdrs, &objp->dir)) {
+ return (FALSE);
+ }
+ if (!xdr_filename(xdrs, &objp->name)) {
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+bool_t
+xdr_diropokres(xdrs, objp)
+ XDR *xdrs;
+ diropokres *objp;
+{
+ if (!xdr_nfs_fh(xdrs, &objp->file)) {
+ return (FALSE);
+ }
+ if (!xdr_fattr(xdrs, &objp->attributes)) {
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+bool_t
+xdr_diropres(xdrs, objp)
+ XDR *xdrs;
+ diropres *objp;
+{
+ if (!xdr_nfsstat(xdrs, &objp->status)) {
+ return (FALSE);
+ }
+ switch (objp->status) {
+ case NFS_OK:
+ if (!xdr_diropokres(xdrs, &objp->diropres_u.diropres)) {
+ return (FALSE);
+ }
+ default:
+ break;
+ }
+ return (TRUE);
+}
+
+bool_t
+xdr_readlinkres(xdrs, objp)
+ XDR *xdrs;
+ readlinkres *objp;
+{
+ if (!xdr_nfsstat(xdrs, &objp->status)) {
+ return (FALSE);
+ }
+ switch (objp->status) {
+ case NFS_OK:
+ if (!xdr_nfspath(xdrs, &objp->readlinkres_u.data)) {
+ return (FALSE);
+ }
+ default:
+ break;
+ }
+ return (TRUE);
+}
+
+bool_t
+xdr_readargs(xdrs, objp)
+ XDR *xdrs;
+ readargs *objp;
+{
+ if (!xdr_nfs_fh(xdrs, &objp->file)) {
+ return (FALSE);
+ }
+ if (!xdr_u_int(xdrs, &objp->offset)) {
+ return (FALSE);
+ }
+ if (!xdr_u_int(xdrs, &objp->count)) {
+ return (FALSE);
+ }
+ if (!xdr_u_int(xdrs, &objp->totalcount)) {
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+bool_t
+xdr_readokres(xdrs, objp)
+ XDR *xdrs;
+ readokres *objp;
+{
+ if (!xdr_fattr(xdrs, &objp->attributes)) {
+ return (FALSE);
+ }
+ if (!xdr_bytes(xdrs, (char **)&objp->data.data_val, (u_int *)&objp->data.data_len, NFS_MAXDATA)) {
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+bool_t
+xdr_readres(xdrs, objp)
+ XDR *xdrs;
+ readres *objp;
+{
+ if (!xdr_nfsstat(xdrs, &objp->status)) {
+ return (FALSE);
+ }
+ switch (objp->status) {
+ case NFS_OK:
+ if (!xdr_readokres(xdrs, &objp->readres_u.reply)) {
+ return (FALSE);
+ }
+ default:
+ break;
+ }
+ return (TRUE);
+}
+
+bool_t
+xdr_writeargs(xdrs, objp)
+ XDR *xdrs;
+ writeargs *objp;
+{
+ if (!xdr_nfs_fh(xdrs, &objp->file)) {
+ return (FALSE);
+ }
+ if (!xdr_u_int(xdrs, &objp->beginoffset)) {
+ return (FALSE);
+ }
+ if (!xdr_u_int(xdrs, &objp->offset)) {
+ return (FALSE);
+ }
+ if (!xdr_u_int(xdrs, &objp->totalcount)) {
+ return (FALSE);
+ }
+ if (!xdr_bytes(xdrs, (char **)&objp->data.data_val, (u_int *)&objp->data.data_len, NFS_MAXDATA)) {
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+bool_t
+xdr_createargs(xdrs, objp)
+ XDR *xdrs;
+ createargs *objp;
+{
+ if (!xdr_diropargs(xdrs, &objp->where)) {
+ return (FALSE);
+ }
+ if (!xdr_sattr(xdrs, &objp->attributes)) {
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+bool_t
+xdr_renameargs(xdrs, objp)
+ XDR *xdrs;
+ renameargs *objp;
+{
+ if (!xdr_diropargs(xdrs, &objp->from)) {
+ return (FALSE);
+ }
+ if (!xdr_diropargs(xdrs, &objp->to)) {
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+bool_t
+xdr_linkargs(xdrs, objp)
+ XDR *xdrs;
+ linkargs *objp;
+{
+ if (!xdr_nfs_fh(xdrs, &objp->from)) {
+ return (FALSE);
+ }
+ if (!xdr_diropargs(xdrs, &objp->to)) {
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+bool_t
+xdr_symlinkargs(xdrs, objp)
+ XDR *xdrs;
+ symlinkargs *objp;
+{
+ if (!xdr_diropargs(xdrs, &objp->from)) {
+ return (FALSE);
+ }
+ if (!xdr_nfspath(xdrs, &objp->to)) {
+ return (FALSE);
+ }
+ if (!xdr_sattr(xdrs, &objp->attributes)) {
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+bool_t
+xdr_nfscookie(xdrs, objp)
+ XDR *xdrs;
+ nfscookie objp;
+{
+ if (!xdr_opaque(xdrs, objp, NFS_COOKIESIZE)) {
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+bool_t
+xdr_readdirargs(xdrs, objp)
+ XDR *xdrs;
+ readdirargs *objp;
+{
+ if (!xdr_nfs_fh(xdrs, &objp->dir)) {
+ return (FALSE);
+ }
+ if (!xdr_nfscookie(xdrs, objp->cookie)) {
+ return (FALSE);
+ }
+ if (!xdr_u_int(xdrs, &objp->count)) {
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+bool_t
+xdr_entry(xdrs, objp)
+ XDR *xdrs;
+ entry *objp;
+{
+ if (!xdr_u_int(xdrs, &objp->fileid)) {
+ return (FALSE);
+ }
+ if (!xdr_filename(xdrs, &objp->name)) {
+ return (FALSE);
+ }
+ if (!xdr_nfscookie(xdrs, objp->cookie)) {
+ return (FALSE);
+ }
+#ifdef linux
+ if (!xdr_pointer(xdrs, (char **)&objp->nextentry, sizeof(entry), (xdrproc_t)xdr_entry)) {
+#else
+ if (!xdr_pointer(xdrs, (char **)&objp->nextentry, sizeof(entry), xdr_entry)) {
+#endif
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+bool_t
+xdr_dirlist(xdrs, objp)
+ XDR *xdrs;
+ dirlist *objp;
+{
+#ifdef linux
+ if (!xdr_pointer(xdrs, (char **)&objp->entries, sizeof(entry), (xdrproc_t)xdr_entry)) {
+#else
+ if (!xdr_pointer(xdrs, (char **)&objp->entries, sizeof(entry), xdr_entry)) {
+#endif
+ return (FALSE);
+ }
+ if (!xdr_bool(xdrs, &objp->eof)) {
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+bool_t
+xdr_readdirres(xdrs, objp)
+ XDR *xdrs;
+ readdirres *objp;
+{
+ if (!xdr_nfsstat(xdrs, &objp->status)) {
+ return (FALSE);
+ }
+ switch (objp->status) {
+ case NFS_OK:
+ if (!xdr_dirlist(xdrs, &objp->readdirres_u.reply)) {
+ return (FALSE);
+ }
+ default:
+ break;
+ }
+ return (TRUE);
+}
+
+bool_t
+xdr_statfsokres(xdrs, objp)
+ XDR *xdrs;
+ statfsokres *objp;
+{
+ if (!xdr_u_int(xdrs, &objp->tsize)) {
+ return (FALSE);
+ }
+ if (!xdr_u_int(xdrs, &objp->bsize)) {
+ return (FALSE);
+ }
+ if (!xdr_u_int(xdrs, &objp->blocks)) {
+ return (FALSE);
+ }
+ if (!xdr_u_int(xdrs, &objp->bfree)) {
+ return (FALSE);
+ }
+ if (!xdr_u_int(xdrs, &objp->bavail)) {
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+bool_t
+xdr_statfsres(xdrs, objp)
+ XDR *xdrs;
+ statfsres *objp;
+{
+ if (!xdr_nfsstat(xdrs, &objp->status)) {
+ return (FALSE);
+ }
+ switch (objp->status) {
+ case NFS_OK:
+ if (!xdr_statfsokres(xdrs, &objp->statfsres_u.reply)) {
+ return (FALSE);
+ }
+ default:
+ break;
+ }
+ return (TRUE);
+}
diff --git a/plpnfsd/rfsv32.cc b/plpnfsd/rfsv32.cc
new file mode 100644
index 0000000..b6105c5
--- /dev/null
+++ b/plpnfsd/rfsv32.cc
@@ -0,0 +1,889 @@
+//
+// PLP - An implementation of the PSION link protocol
+//
+// Copyright (C) 1999 Philip Proudman
+//
+// 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 2 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 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// e-mail philip.proudman@btinternet.com
+
+#include <stream.h>
+#include <stdlib.h>
+#include <fstream.h>
+#include <iomanip.h>
+#include <time.h>
+#include <string.h>
+
+#include "bool.h"
+#include "bool.h"
+#include "rfsv32.h"
+#include "bufferstore.h"
+#include "ppsocket.h"
+#include "../defaults.h"
+#include "bufferarray.h"
+
+rfsv32::rfsv32(ppsocket * _skt) : serNum(0)
+{
+ skt = _skt;
+ bufferStore a;
+ status = DISCONNECTED;
+ a.addStringT(getConnectName());
+ if (skt->sendBufferStore(a)) {
+ if (skt->getBufferStore(a) == 1) {
+ if (strcmp(a.getString(0), "Ok"))
+ cerr << "Not got ok over socket\n";
+ else
+ status = NONE;
+ }
+ }
+}
+
+rfsv32::~rfsv32()
+{
+ bufferStore a;
+ a.addStringT("Close");
+ if (status == NONE)
+ skt->sendBufferStore(a);
+ skt->closeSocket();
+}
+
+long rfsv32::
+getStatus()
+{
+ return status;
+}
+
+const char *rfsv32::
+getConnectName()
+{
+ return "SYS$RFSV.*";
+}
+
+void rfsv32::
+convertSlash(const char *name)
+{
+ for (char *p = (char *)name; *p; p++)
+ if (*p == '/')
+ *p = '\\';
+}
+
+long rfsv32::
+fopen(long attr, const char *name, long &handle)
+{
+ bufferStore a;
+ a.addDWord(attr);
+ convertSlash(name);
+ a.addWord(strlen(name));
+ a.addString(name);
+ sendCommand(OPEN_FILE, a);
+
+ long res = getResponse(a);
+ if (!res && a.getLen() == 4) {
+ handle = a.getDWord(0);
+ return 0;
+ }
+ return res;
+}
+
+long rfsv32::
+mktemp(long *handle, char *tmpname)
+{
+ bufferStore a;
+ sendCommand(TEMP_FILE, a);
+ long res = getResponse(a);
+ if (res == 0) {
+ *handle = a.getDWord(0);
+ strcpy(tmpname, a.getString(6));
+ }
+ return res;
+}
+
+long rfsv32::
+fcreatefile(long attr, const char *name, long &handle)
+{
+ bufferStore a;
+ a.addDWord(attr);
+ convertSlash(name);
+ a.addWord(strlen(name));
+ a.addString(name);
+ sendCommand(CREATE_FILE, a);
+ long res = getResponse(a);
+ if (!res && a.getLen() == 4)
+ handle = a.getDWord(0);
+ return res;
+}
+
+long rfsv32::
+freplacefile(long attr, const char *name, long &handle)
+{
+ bufferStore a;
+ convertSlash(name);
+ a.addDWord(attr);
+ a.addWord(strlen(name));
+ a.addString(name);
+ sendCommand(REPLACE_FILE, a);
+ long res = getResponse(a);
+ if (!res && a.getLen() == 4)
+ handle = a.getDWord(0);
+ return res;
+}
+
+long rfsv32::
+fopendir(long attr, const char *name, long &handle)
+{
+ bufferStore a;
+ convertSlash(name);
+ a.addDWord(attr);
+ a.addWord(strlen(name));
+ a.addString(name);
+ sendCommand(OPEN_DIR, a);
+ long res = getResponse(a);
+ if (!res && a.getLen() == 4)
+ handle = a.getDWord(0);
+ return res;
+}
+
+long rfsv32::
+fclose(long handle)
+{
+ bufferStore a;
+ a.addDWord(handle);
+ sendCommand(CLOSE_HANDLE, a);
+ return getResponse(a);
+}
+
+/* Microseconds since 1.1.1980 00:00:00 */
+#define PSI_EPOCH_SECS8 0x0e8c52f4
+#define EPOCH_2H 7200
+#define EPOCH_DIFF_SECS (3652 * 24 * 60 * 60)
+
+unsigned long rfsv32::
+micro2time(unsigned long microHi, unsigned long microLo)
+{
+ unsigned long long micro = microHi;
+ unsigned long long pes = PSI_EPOCH_SECS8;
+ pes <<= 8;
+ micro <<= 32;
+ micro += microLo;
+ micro /= 1000000;
+ micro -= pes;
+ micro += EPOCH_DIFF_SECS;
+ micro -= EPOCH_2H;
+ return (long) micro;
+}
+
+void rfsv32::
+time2micro(unsigned long time, unsigned long &microHi, unsigned long &microLo)
+{
+ unsigned long long micro = (unsigned long long)time;
+ unsigned long long pes = PSI_EPOCH_SECS8;
+ pes <<= 8;
+ micro += pes;
+ micro -= EPOCH_DIFF_SECS;
+ micro += EPOCH_2H;
+ micro *= (unsigned long long)1000000;
+ microLo = (micro & (unsigned long long)0x0FFFFFFFF);
+ micro >>= 32;
+ microHi = (micro & (unsigned long long)0x0FFFFFFFF);
+}
+
+long rfsv32::
+dir(const char *name, bufferArray * files)
+{
+ long handle;
+ long res = fopendir(HIDDEN | SYSTEM | DIRECTORY, name, handle);
+ if (res != 0)
+ return res;
+
+ while (1) {
+ bufferStore a;
+ a.addDWord(handle);
+ sendCommand(READ_DIR, a);
+ res = getResponse(a);
+ if (res)
+ break;
+ while (a.getLen() > 16) {
+ long shortLen = a.getDWord(0);
+ long attributes = a.getDWord(4);
+ long size = a.getDWord(8);
+ unsigned long modLow = a.getDWord(12);
+ unsigned long modHi = a.getDWord(16);
+ // long uid1 = a.getDWord(20);
+ // long uid2 = a.getDWord(24);
+ // long uid3 = a.getDWord(28);
+ long longLen = a.getDWord(32);
+
+ long date = micro2time(modHi, modLow);
+
+ bufferStore s;
+ if (!files) {
+ char dateBuff[100];
+ struct tm *t;
+ t = localtime(&date);
+ strftime(dateBuff, 100, "%c", t);
+ cout << ((attributes & DIRECTORY) ? "d" : "-");
+ cout << ((attributes & READ_ONLY) ? "-" : "w");
+ cout << ((attributes & HIDDEN) ? "h" : "-");
+ cout << ((attributes & SYSTEM) ? "s" : "-");
+ cout << ((attributes & ARCHIVE) ? "a" : "-");
+ cout << ((attributes & VOLUME) ? "v" : "-");
+ cout << ((attributes & NORMAL) ? "n" : "-");
+ cout << ((attributes & TEMPORARY) ? "t" : "-");
+ cout << ((attributes & COMPRESSED) ? "c" : "-");
+ cout << " " << dec << setw(10) << setfill(' ') << size;
+ cout << " " << dateBuff;
+ } else {
+ s.addDWord(date);
+ s.addDWord(size);
+ s.addDWord(attributes);
+ }
+ int d = 36;
+ for (int i = 0; i < longLen; i++, d++)
+ s.addByte(a.getByte(d));
+ s.addByte(0);
+ while (d % 4)
+ d++;
+ if (!files)
+ cout << " " << s.getString() << endl;
+ else /* if ((attributes & DIRECTORY) == 0) */
+ files->pushBuffer(s);
+ d += shortLen;
+ while (d % 4)
+ d++;
+ a.discardFirstBytes(d);
+ }
+ }
+ if (res == EoF)
+ res = 0;
+ fclose(handle);
+ return res;
+}
+
+long rfsv32::
+fgetmtime(const char *name, long *mtime)
+{
+ bufferStore a;
+ convertSlash(name);
+ a.addWord(strlen(name));
+ a.addString(name);
+ sendCommand(MODIFIED, a);
+ long res = getResponse(a);
+ if (res != 0)
+ return res;
+ *mtime = micro2time(a.getDWord(4), a.getDWord(0));
+ return 0;
+}
+
+long rfsv32::
+fsetmtime(const char *name, long mtime)
+{
+ bufferStore a;
+ unsigned long microLo, microHi;
+ time2micro(mtime, microHi, microLo);
+ convertSlash(name);
+ a.addDWord(microLo);
+ a.addDWord(microHi);
+ a.addWord(strlen(name));
+ a.addString(name);
+ sendCommand(SET_MODIFIED, a);
+ long res = getResponse(a);
+ if (res != 0)
+ return res;
+ return 0;
+}
+
+long rfsv32::
+fgetattr(const char *name, long *attr)
+{
+ bufferStore a;
+ convertSlash(name);
+ a.addWord(strlen(name));
+ a.addString(name);
+ sendCommand(ATT, a);
+ long res = getResponse(a);
+ if (res != 0)
+ return res;
+ *attr = a.getDWord(0);
+ return 0;
+}
+
+long rfsv32::
+fgeteattr(const char *name, long *attr, long *size, long *time)
+{
+ bufferStore a;
+ convertSlash(name);
+ a.addWord(strlen(name));
+ a.addString(name);
+ sendCommand(REMOTE_ENTRY, a);
+ long res = getResponse(a);
+ if (res != 0)
+ return res;
+ // long shortLen = a.getDWord(0);
+ *attr = a.getDWord(4);
+ *size = a.getDWord(8);
+ unsigned long modLow = a.getDWord(12);
+ unsigned long modHi = a.getDWord(16);
+ // long uid1 = a.getDWord(20);
+ // long uid2 = a.getDWord(24);
+ // long uid3 = a.getDWord(28);
+ // long longLen = a.getDWord(32);
+ *time = micro2time(modHi, modLow);
+ return 0;
+}
+
+long rfsv32::
+fsetattr(const char *name, long seta, long unseta)
+{
+ bufferStore a;
+ convertSlash(name);
+ a.addDWord(seta);
+ a.addDWord(unseta);
+ a.addWord(strlen(name));
+ a.addString(name);
+ sendCommand(SET_ATT, a);
+ return getResponse(a);
+}
+
+long rfsv32::
+dircount(const char *name, long *count)
+{
+ long handle;
+ convertSlash(name);
+ long res = fopendir(HIDDEN | SYSTEM | DIRECTORY, name, handle);
+ *count = 0;
+ if (res != 0)
+ return res;
+
+ while (1) {
+ bufferStore a;
+ a.addDWord(handle);
+ sendCommand(READ_DIR, a);
+ res = getResponse(a);
+ if (res)
+ break;
+ while (a.getLen() > 16) {
+ int d = 36 + a.getDWord(32);
+ while (d % 4)
+ d++;
+ d += a.getDWord(0);
+ while (d % 4)
+ d++;
+ a.discardFirstBytes(d);
+ (*count)++;
+ }
+ }
+ fclose(handle);
+ if (res == EoF)
+ res = 0;
+ return res;
+}
+
+long rfsv32::
+devlist(long *devbits)
+{
+ bufferStore a;
+ long res;
+
+ sendCommand(GET_DRIVE_LIST, a);
+ res = getResponse(a);
+ *devbits = 0;
+ if ((res == 0) && (a.getLen() == 26)) {
+ for (int i = 25; i >= 0; i--) {
+ *devbits <<= 1;
+ if (a.getByte(i) != 0)
+ *devbits |= 1;
+ }
+ }
+ return res;
+}
+
+char *rfsv32::
+devinfo(int devnum, long *vfree, long *vtotal, long *vattr,
+ long *vuniqueid)
+{
+ bufferStore a;
+ long res;
+
+ a.addDWord(devnum);
+ sendCommand(DRIVE_INFO, a);
+ res = getResponse(a);
+ if (res == 0) {
+ *vattr = a.getDWord(0);
+ *vuniqueid = a.getDWord(16);
+ *vtotal = a.getDWord(20);
+ *vfree = a.getDWord(28);
+ // vnamelen = a.getDWord(36);
+ a.addByte(0);
+ return (strdup(a.getString(40)));
+ }
+ return NULL;
+}
+
+bool rfsv32::
+sendCommand(enum commands cc, bufferStore & data)
+{
+ bufferStore a;
+ a.addWord(cc);
+ a.addWord(serNum);
+ if (serNum < 0xffff)
+ serNum++;
+ else
+ serNum = 0;
+ a.addBuff(data);
+ return skt->sendBufferStore(a);
+}
+
+long rfsv32::
+getResponse(bufferStore & data)
+{
+ if (skt->getBufferStore(data) == 1 &&
+ data.getWord(0) == 0x11) {
+ long ret = data.getDWord(4);
+ data.discardFirstBytes(8);
+ return ret;
+ } else
+ status = DISCONNECTED;
+ return (enum errs) GENERAL;
+}
+
+char * rfsv32::
+opErr(long status)
+{
+ enum errs e = (enum errs) status;
+ switch (e) {
+ case NONE:
+ return "";
+ case NOT_FOUND:
+ return "NOT_FOUND";
+ case GENERAL:
+ return "GENERAL";
+ break;
+ case CANCEL:
+ return "CANCEL";
+ break;
+ case NO_MEMORY:
+ return "NO_MEMORY";
+ break;
+ case NOT_SUPPORTED:
+ return "NOT_SUPPORTED";
+ break;
+ case ARGUMENT:
+ return "ARGUMENT";
+ break;
+ case TOTAL_LOSS_OF_PRECISION:
+ return "TOTAL_LOSS_OF_PRECISION";
+ break;
+ case BAD_HANDLE:
+ return "BAD_HANDLE";
+ break;
+ case OVERFLOW:
+ return "OVERFLOW";
+ break;
+ case UNDERFLOW:
+ return "UNDERFLOW";
+ break;
+ case ALREADY_EXISTS:
+ return "ALREADY_EXISTS";
+ break;
+ case PATH_NOT_FOUND:
+ return "PATH_NOT_FOUND";
+ break;
+ case DIED:
+ return "DIED";
+ break;
+ case IN_USE:
+ return "IN_USE";
+ break;
+ case SERVER_TERMINATED:
+ return "SERVER_TERMINATED";
+ break;
+ case SERVER_BUSY:
+ return "SERVER_BUSY";
+ break;
+ case COMPLETION:
+ return "COMPLETION";
+ break;
+ case NOT_READY:
+ return "NOT_READY";
+ break;
+ case UNKNOWN:
+ return "UNKNOWN";
+ break;
+ case CORRUPT:
+ return "CORRUPT";
+ break;
+ case ACCESS_DENIED:
+ return "ACCESS_DENIED";
+ break;
+ case LOCKED:
+ return "LOCKED";
+ break;
+ case WRITE:
+ return "WRITE";
+ break;
+ case DISMOUNTED:
+ return "DISMOUNTED";
+ break;
+ case EoF:
+ return "EOF";
+ break;
+ case DISK_FULL:
+ return "DISK_FULL";
+ break;
+ case BAD_DRIVER:
+ return "BAD_DRIVER";
+ break;
+ case BAD_NAME:
+ return "BAD_NAME";
+ break;
+ case COMMS_LINE_FAIL:
+ return "COMMS_LINE_FAIL";
+ break;
+ case COMMS_FRAME:
+ return "COMMS_FRAME";
+ break;
+ case COMMS_OVERRUN:
+ return "COMMS_OVERRUN";
+ break;
+ case COMMS_PARITY:
+ return "COMMS_PARITY";
+ break;
+ case PSI_TIMEOUT:
+ return "TIMEOUT";
+ break;
+ case COULD_NOT_CONNECT:
+ return "COULD_NOT_CONNECT";
+ break;
+ case COULD_NOT_DISCONNECT:
+ return "COULD_NOT_DISCONNECT";
+ break;
+ case DISCONNECTED:
+ return "DISCONNECTED";
+ break;
+ case BAD_LIBRARY_ENTRY_POINT:
+ return "BAD_LIBRARY_ENTRY_POINT";
+ break;
+ case BAD_DESCRIPTOR:
+ return "BAD_DESCRIPTOR";
+ break;
+ case ABORT:
+ return "ABORT";
+ break;
+ case TOO_BIG:
+ return "TOO_BIG";
+ break;
+ case DIVIDE_BY_ZERO:
+ return "DIVIDE_BY_ZERO";
+ break;
+ case BAD_POWER:
+ return "BAD_POWER";
+ break;
+ case DIR_FULL:
+ return "DIR_FULL";
+ break;
+ default:
+ return "Unknown error";
+ break;
+ }
+}
+
+long rfsv32::
+fread(long handle, char *buf, long len)
+{
+ long res;
+ long count = 0;
+
+ do {
+ bufferStore a;
+ a.addDWord(handle);
+ a.addDWord(((len-count) > 2000)?2000:(len-count));
+ sendCommand(READ_FILE, a);
+ if ((res = getResponse(a)) != 0)
+ return res;
+ res = a.getLen();
+ if (res > 0) {
+ memcpy(buf, a.getString(), res);
+ count += res;
+ buf += res;
+ }
+ } while ((count < len) && (res > 0));
+ return (res < 0)?res:count;
+}
+
+long rfsv32::
+fwrite(long handle, char *buf, long len)
+{
+ long res;
+ long total = 0;
+ long count;
+
+ do {
+ count = ((len - total) > 2000)?2000:(len - total);
+ bufferStore a;
+ bufferStore tmp((unsigned char *)buf, count);
+ a.addDWord(handle);
+ a.addBuff(tmp);
+ sendCommand(WRITE_FILE, a);
+ if ((res = getResponse(a)) != 0)
+ return res;
+ total += count;
+ buf += count;
+ } while ((total < len) && (count > 0));
+ return total;
+}
+
+long rfsv32::
+copyFromPsion(const char *from, const char *to)
+{
+ long handle;
+ long res;
+ long len;
+
+ if ((res = fopen(SHARE_READERS | BINARY, from, handle)) != 0)
+ return res;
+ ofstream op(to);
+ if (!op) {
+ fclose(handle);
+ return -1;
+ }
+ do {
+ char buf[2000];
+ if ((len = fread(handle, buf, sizeof(buf))) > 0)
+ op.write(buf, len);
+ } while (len > 0);
+
+ fclose(handle);
+ op.close();
+ return len;
+}
+
+long rfsv32::
+copyToPsion(const char *from, const char *to)
+{
+ long handle;
+ long res;
+
+ ifstream ip(from);
+ if (!ip)
+ return NOT_FOUND;
+ res = fcreatefile(BINARY | SHARE_EXCLUSIVE | READ_WRITE, to, handle);
+ if (res != 0) {
+ res = freplacefile(BINARY | SHARE_EXCLUSIVE | READ_WRITE, to, handle);
+ if (res != 0) {
+ opErr(res);
+ cerr << endl;
+ return res;
+ }
+ }
+ unsigned char *buff = new unsigned char[RFSV_SENDLEN];
+ int total = 0;
+ while (ip && !ip.eof()) {
+ ip.read(buff, RFSV_SENDLEN);
+ bufferStore tmp(buff, ip.gcount());
+ total += tmp.getLen();
+ if (tmp.getLen() == 0)
+ break;
+ bufferStore a;
+ a.addDWord(handle);
+ a.addBuff(tmp);
+ sendCommand(WRITE_FILE, a);
+ res = getResponse(a);
+ if (res) {
+ cerr << "Unknown response to fwrite - ";
+ opErr(res);
+ cerr << " " << a << endl;
+ fclose(handle);
+ return res;
+ }
+ }
+ fclose(handle);
+ ip.close();
+ delete[]buff;
+ return 0;
+}
+
+long rfsv32::
+fsetsize(long handle, long size)
+{
+ bufferStore a;
+ a.addDWord(handle);
+ a.addDWord(size);
+ sendCommand(SET_SIZE, a);
+ return getResponse(a);
+}
+
+/*
+ * Unix-like implementation off fseek with one
+ * exception: If seeking beyond eof, the gap
+ * contains garbage instead of zeroes.
+ */
+long rfsv32::
+fseek(long handle, long pos, long mode)
+{
+ bufferStore a;
+ long res;
+ long savpos = 0;
+ long realpos;
+ long calcpos = 0;
+
+/*
+ seek-parameter for psion:
+ dword position
+ dword handle
+ dword mode
+ 1 = from start
+ 2 = from current pos
+ 3 = from end
+ ??no more?? 4 = sense recpos
+ ??no more?? 5 = set recpos
+ ??no more?? 6 = text-rewind
+ */
+
+ if ((mode < PSEEK_SET) || (mode > PSEEK_END))
+ return ARGUMENT;
+
+ if ((mode == PSEEK_CUR) && (pos >= 0)) {
+ /* get and save current position */
+ a.addDWord(0);
+ a.addDWord(handle);
+ a.addDWord(PSEEK_CUR);
+ sendCommand(SEEK_FILE, a);
+ if ((res = getResponse(a)) != 0)
+ return res;
+ savpos = a.getDWord(0);
+ if (pos == 0)
+ return savpos;
+ a.init();
+ }
+ if ((mode == PSEEK_END) && (pos >= 0)) {
+ /* get and save end position */
+ a.addDWord(0);
+ a.addDWord(handle);
+ a.addDWord(PSEEK_END);
+ sendCommand(SEEK_FILE, a);
+ if ((res = getResponse(a)) != 0)
+ return res;
+ savpos = a.getDWord(0);
+ if (pos == 0)
+ return savpos;
+ /* Expand file */
+ a.init();
+ a.addDWord(handle);
+ a.addDWord(savpos + pos);
+ sendCommand(SET_SIZE, a);
+ if ((res = getResponse(a)) != 0)
+ return res;
+ pos = 0;
+ a.init();
+ }
+ /* Now the real seek */
+ a.addDWord(pos);
+ a.addDWord(handle);
+ a.addDWord(mode);
+ sendCommand(SEEK_FILE, a);
+ if ((res = getResponse(a)) != 0) {
+cout << "seekRES(" << handle << ")=" << res << endl;
+ return res;
+}
+ realpos = a.getDWord(0);
+cout << "seekPOS=" << realpos << endl;
+ switch (mode) {
+ case PSEEK_SET:
+ calcpos = pos;
+ break;
+ case PSEEK_CUR:
+ calcpos = savpos + pos;
+ break;
+ case PSEEK_END:
+ return realpos;
+ break;
+ }
+ if (calcpos > realpos) {
+ /* Beyond end of file */
+ a.init();
+ a.addDWord(handle);
+ a.addDWord(calcpos);
+ sendCommand(SET_SIZE, a);
+ if ((res = getResponse(a)) != 0)
+ return res;
+ a.addDWord(calcpos);
+ a.addDWord(handle);
+ a.addDWord(PSEEK_SET);
+ sendCommand(SEEK_FILE, a);
+ if ((res = getResponse(a)) != 0)
+ return res;
+ realpos = a.getDWord(0);
+ }
+ return realpos;
+}
+
+long rfsv32::
+mkdir(const char *name)
+{
+ bufferStore a;
+ convertSlash(name);
+ if (strlen(name) && (name[strlen(name) - 1] != '\\')) {
+ a.addWord(strlen(name) + 1);
+ a.addString(name);
+ a.addByte('\\');
+ } else {
+ a.addWord(strlen(name));
+ a.addString(name);
+ }
+ sendCommand(MK_DIR_ALL, a);
+ return getResponse(a);
+}
+
+long rfsv32::
+rmdir(const char *name)
+{
+ bufferStore a;
+ convertSlash(name);
+ if (strlen(name) && (name[strlen(name) - 1] != '\\')) {
+ a.addWord(strlen(name) + 1);
+ a.addString(name);
+ a.addByte('\\');
+ } else {
+ a.addWord(strlen(name));
+ a.addString(name);
+ }
+ sendCommand(RM_DIR, a);
+ return getResponse(a);
+}
+
+long rfsv32::
+rename(const char *oldname, const char *newname)
+{
+ bufferStore a;
+ convertSlash(oldname);
+ convertSlash(newname);
+ a.addWord(strlen(oldname));
+ a.addString(oldname);
+ a.addWord(strlen(newname));
+ a.addString(newname);
+ sendCommand(RENAME, a);
+ return getResponse(a);
+}
+
+long rfsv32::
+remove(const char *name)
+{
+ bufferStore a;
+ convertSlash(name);
+ a.addWord(strlen(name));
+ a.addString(name);
+ sendCommand(DELETE, a);
+ return getResponse(a);
+}
diff --git a/plpnfsd/rfsv32.h b/plpnfsd/rfsv32.h
new file mode 100644
index 0000000..083bd3d
--- /dev/null
+++ b/plpnfsd/rfsv32.h
@@ -0,0 +1,172 @@
+#ifndef _rfsv32_h_
+#define _rfsv32_h_
+
+class ppsocket;
+class bufferStore;
+class bufferArray;
+
+class rfsv32 {
+ public:
+ rfsv32(ppsocket * skt);
+ ~rfsv32();
+
+ long dir(const char *name, bufferArray * files);
+ long dircount(const char *name, long *count);
+ long copyFromPsion(const char *from, const char *to);
+ long copyToPsion(const char *from, const char *to);
+ long mkdir(const char *name);
+ long rmdir(const char *name);
+ long remove(const char *name);
+ long rename(const char *oldname, const char *newname);
+ long mktemp(long *handle, char *tmpname);
+ long fgeteattr(const char *name, long *attr, long *size, long *time);
+ long fgetattr(const char *name, long *attr);
+ long fsetattr(const char *name, long seta, long unseta);
+ long fgetmtime(const char *name, long *mtime);
+ long fsetmtime(const char *name, long mtime);
+ long fopendir(long attr, const char *name, long &handle);
+ long fopen(long attr, const char *name, long &handle);
+ long fcreatefile(long attr, const char *name, long &handle);
+ long freplacefile(long attr, const char *name, long &handle);
+ long fseek(long handle, long pos, long mode);
+ long fread(long handle, char *buf, long len);
+ long fwrite(long handle, char *buf, long len);
+ long fsetsize(long handle, long size);
+ long fclose(long handle);
+
+ long devlist(long *devbits);
+ char *devinfo(int devnum, long *vfree, long *vtotal, long *vattr, long *vuiqueid);
+ long getStatus();
+ char *opErr(long status);
+
+ enum seek_mode {
+ PSEEK_SET = 1,
+ PSEEK_CUR = 2,
+ PSEEK_END = 3
+ };
+
+ private:
+ enum commands {
+ CLOSE_HANDLE = 0x01,
+ OPEN_DIR = 0x10,
+ READ_DIR = 0x12,
+ GET_DRIVE_LIST = 0x13,
+ DRIVE_INFO = 0x14,
+ SET_VOLUME_LABEL = 0x15,
+ OPEN_FILE = 0x16,
+ TEMP_FILE = 0x17,
+ READ_FILE = 0x18,
+ WRITE_FILE = 0x19,
+ SEEK_FILE = 0x1a,
+ DELETE = 0x1b,
+ REMOTE_ENTRY = 0x1c,
+ FLUSH = 0x1d,
+ SET_SIZE = 0x1e,
+ RENAME = 0x1f,
+ MK_DIR_ALL = 0x20,
+ RM_DIR = 0x21,
+ SET_ATT = 0x22,
+ ATT = 0x23,
+ SET_MODIFIED = 0x24,
+ MODIFIED = 0x25,
+ SET_SESSION_PATH = 0x26,
+ SESSION_PATH = 0x27,
+ READ_WRITE_FILE = 0x28,
+ CREATE_FILE = 0x29,
+ REPLACE_FILE = 0x2a,
+ PATH_TEST = 0x2b,
+ LOCK = 0x2d,
+ UNLOCK = 0x2e,
+ OPEN_DIR_UID = 0x2f,
+ DRIVE_NAME = 0x30,
+ SET_DRIVE_NAME = 0x31,
+ REPLACE = 0x32
+ };
+
+ enum file_attrib {
+ READ_ONLY = 0x0001,
+ HIDDEN = 0x0002,
+ SYSTEM = 0x0004,
+ DIRECTORY = 0x0010,
+ ARCHIVE = 0x0020,
+ VOLUME = 0x0040,
+ NORMAL = 0x0080,
+ TEMPORARY = 0x0100,
+ COMPRESSED = 0x0800
+ };
+
+ enum open_mode {
+ SHARE_EXCLUSIVE = 0x0000,
+ SHARE_READERS = 0x0001,
+ SHARE_ANY = 0x0002,
+ BINARY = 0x0000,
+ TEXT = 0x0020,
+ READ_WRITE = 0x0200
+ };
+
+ enum errs {
+ NONE = 0,
+ NOT_FOUND = -1,
+ GENERAL = -2,
+ CANCEL = -3,
+ NO_MEMORY = -4,
+ NOT_SUPPORTED = -5,
+ ARGUMENT = -6,
+ TOTAL_LOSS_OF_PRECISION = -7,
+ BAD_HANDLE = -8,
+ OVERFLOW = -9,
+ UNDERFLOW = -10,
+ ALREADY_EXISTS = -11,
+ PATH_NOT_FOUND = -12,
+ DIED = -13,
+ IN_USE = -14,
+ SERVER_TERMINATED = -15,
+ SERVER_BUSY = -16,
+ COMPLETION = -17,
+ NOT_READY = -18,
+ UNKNOWN = -19,
+ CORRUPT = -20,
+ ACCESS_DENIED = -21,
+ LOCKED = -22,
+ WRITE = -23,
+ DISMOUNTED = -24,
+ EoF = -25,
+ DISK_FULL = -26,
+ BAD_DRIVER = -27,
+ BAD_NAME = -28,
+ COMMS_LINE_FAIL = -29,
+ COMMS_FRAME = -30,
+ COMMS_OVERRUN = -31,
+ COMMS_PARITY = -32,
+ PSI_TIMEOUT = -33,
+ COULD_NOT_CONNECT = -34,
+ COULD_NOT_DISCONNECT = -35,
+ DISCONNECTED = -36,
+ BAD_LIBRARY_ENTRY_POINT = -37,
+ BAD_DESCRIPTOR = -38,
+ ABORT = -39,
+ TOO_BIG = -40,
+ DIVIDE_BY_ZERO = -41,
+ BAD_POWER = -42,
+ DIR_FULL = -43
+ };
+
+ const char *getConnectName();
+
+ // Communication
+ bool sendCommand(enum commands c, bufferStore & data);
+ long getResponse(bufferStore & data);
+ void convertSlash(const char *name);
+
+ // time-conversion
+ unsigned long micro2time(unsigned long microHi, unsigned long microLo);
+ void time2micro(unsigned long mtime, unsigned long &microHi, unsigned long &microLo);
+
+ // Vars
+ ppsocket *skt;
+ int serNum;
+ long status;
+ int tDiff;
+};
+
+#endif
diff --git a/plpnfsd/rfsv_api.h b/plpnfsd/rfsv_api.h
new file mode 100644
index 0000000..18bd496
--- /dev/null
+++ b/plpnfsd/rfsv_api.h
@@ -0,0 +1,29 @@
+/* $Id$/
+ *
+ * C API for rfsv
+ *
+ */
+#ifndef _rfsv_api_h_
+#define _rfsv_api_h_
+
+#include "mp.h"
+
+extern long rfsv_dir(const char *name, dentry **e);
+extern long rfsv_mkdir(const char *name);
+extern long rfsv_rmdir(const char *name);
+extern long rfsv_remove(const char *name);
+extern long rfsv_rename(const char *oldname, const char *newname);
+extern long rfsv_fclose(long handle);
+extern long rfsv_fopen(long attr, const char *name, long *handle);
+extern long rfsv_fcreate(long attr, const char *name, long *handle);
+extern long rfsv_read(char *buf, long offset, long len, long handle);
+extern long rfsv_write(char *buf, long offset, long len, long handle);
+extern long rfsv_getattr(const char *name, long *attr, long *size, long *time);
+extern long rfsv_setattr(const char *name, long sattr, long dattr);
+extern long rfsv_setsize(const char *name, long size);
+extern long rfsv_setmtime(const char *name, long time);
+extern long rfsv_drivelist(int *cnt, device **devlist);
+extern long rfsv_dircount(const char *name, long *count);
+extern long rfsv_statdev(char letter);
+
+#endif