diff options
author | Fritz Elfert <felfert@to.com> | 1999-06-28 08:56:01 +0000 |
---|---|---|
committer | Fritz Elfert <felfert@to.com> | 1999-06-28 08:56:01 +0000 |
commit | 34b70b0b46e34a73308a4034cc9b1c70209b9eb4 (patch) | |
tree | 7abe8be40fde08828d3606e13c41435b2fc9a26c | |
parent | 3d3be141551bb4622da1cb610e4f6f798dd1715e (diff) | |
download | plptools-34b70b0b46e34a73308a4034cc9b1c70209b9eb4.tar.gz plptools-34b70b0b46e34a73308a4034cc9b1c70209b9eb4.tar.bz2 plptools-34b70b0b46e34a73308a4034cc9b1c70209b9eb4.zip |
First import.
-rw-r--r-- | acconfig.h | 6 | ||||
-rw-r--r-- | acinclude.m4 | 200 | ||||
-rw-r--r-- | lib/Makefile.am | 3 | ||||
-rw-r--r-- | lib/bool.h | 20 | ||||
-rw-r--r-- | lib/bufferarray.cc | 68 | ||||
-rw-r--r-- | lib/bufferarray.h | 25 | ||||
-rw-r--r-- | lib/bufferstore.cc | 166 | ||||
-rw-r--r-- | lib/bufferstore.h | 50 | ||||
-rw-r--r-- | lib/iowatch.cc | 77 | ||||
-rw-r--r-- | lib/iowatch.h | 21 | ||||
-rw-r--r-- | lib/ppsocket.cc | 863 | ||||
-rw-r--r-- | lib/ppsocket.h | 117 | ||||
-rw-r--r-- | plpnfsd/Makefile.am | 9 | ||||
-rw-r--r-- | plpnfsd/main.cc | 215 | ||||
-rw-r--r-- | plpnfsd/mount_aix.c | 170 | ||||
-rw-r--r-- | plpnfsd/mp_inode.c | 325 | ||||
-rw-r--r-- | plpnfsd/mp_main.c | 147 | ||||
-rw-r--r-- | plpnfsd/mp_mount.c | 601 | ||||
-rw-r--r-- | plpnfsd/mp_pfs_ops.c | 1040 | ||||
-rw-r--r-- | plpnfsd/mtab_aix.c | 145 | ||||
-rw-r--r-- | plpnfsd/nfs_prot_svc.c | 231 | ||||
-rw-r--r-- | plpnfsd/nfs_prot_xdr.c | 518 | ||||
-rw-r--r-- | plpnfsd/rfsv32.cc | 889 | ||||
-rw-r--r-- | plpnfsd/rfsv32.h | 172 | ||||
-rw-r--r-- | plpnfsd/rfsv_api.h | 29 |
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 µHi, unsigned long µLo) +{ + 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 µHi, unsigned long µLo); + + // 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 |