From 7fb94ed43a814788cda019c1e77314abc1626339 Mon Sep 17 00:00:00 2001 From: Fritz Elfert Date: Mon, 31 Jul 2000 03:12:38 +0000 Subject: Applied mjg-0.6 patch. Started adding kdoc compliant documentation comments. Added PsiTime --- .cvsignore | 1 + README | 4 +- README.0.6-mjg | 62 ++++++ configure.in | 13 +- etc/psion.in | 8 + include/defs.h.in | 6 +- include/linux-misc.h | 52 +++++ include/nfs_prot.h | 18 +- lib/Makefile.am | 6 +- lib/bufferarray.cc | 22 +-- lib/bufferarray.h | 137 ++++++++++--- lib/bufferstore.cc | 46 +++-- lib/bufferstore.h | 223 +++++++++++++++++---- lib/ppsocket.cc | 4 + lib/psitime.cc | 117 +++++++++++ lib/psitime.h | 198 +++++++++++++++++++ lib/rfsv.h | 64 +++++- lib/rfsv16.cc | 432 +++++++++++++++++++++++++++++------------ lib/rfsv16.h | 3 + lib/rfsv32.cc | 102 +++++++++- lib/rfsv32.h | 3 + lib/rpcs.cc | 138 ++++++++----- lib/rpcs.h | 306 +++++++++++++++++++++++++++-- lib/rpcs16.cc | 2 +- lib/rpcs16.h | 2 +- lib/rpcs32.cc | 125 ++++++++++-- lib/rpcs32.h | 8 +- lib/rpcsfactory.cc | 9 +- lib/rpcsfactory.h | 28 ++- ncpd/link.cc | 6 +- ncpd/linkchan.cc | 6 +- ncpd/main.cc | 10 +- ncpd/mp_serial.c | 2 +- ncpd/ncp.cc | 2 +- ncpd/packet.cc | 28 ++- ncpd/packet.h | 1 + patches/README | 16 ++ patches/mgetty-1.1.21-plp.diff | 40 ++++ plpftp/ftp.cc | 131 +++++++++++-- plpnfsd/main.cc | 18 +- plpnfsd/mp_mount.c | 3 +- plpnfsd/mp_pfs_ops.c | 48 +++-- plpnfsd/rfsv_api.h | 15 ++ 43 files changed, 2046 insertions(+), 419 deletions(-) create mode 100644 README.0.6-mjg create mode 100644 include/linux-misc.h create mode 100644 lib/psitime.cc create mode 100644 lib/psitime.h create mode 100644 patches/README create mode 100644 patches/mgetty-1.1.21-plp.diff diff --git a/.cvsignore b/.cvsignore index 3d7dae3..b850d61 100644 --- a/.cvsignore +++ b/.cvsignore @@ -7,3 +7,4 @@ config.status config.cache config.log plptools-*.tar.gz +.vimsession diff --git a/README b/README index 2fd2b77..6ebbe3c 100644 --- a/README +++ b/README @@ -88,7 +88,9 @@ basic PLP/NCP services for the other two programs. It auto- connects to the psion, even after unplugging/switching off therefore it can run always in background (if you have a - spare serial-device) + spare serial-device). If supplied, the -e option will cause ncpd to + automatically exit when the connection to the Psion is lost. This is useful + when used with a patch to mgetty (see the patches directory). plpftp is a FTP-like program for manipulating files on the Psion. diff --git a/README.0.6-mjg b/README.0.6-mjg new file mode 100644 index 0000000..7e5c737 --- /dev/null +++ b/README.0.6-mjg @@ -0,0 +1,62 @@ +Patches to plptools-0.6, collected by Matt Gumbley +-------------------------------------------------- + +1) Compilation patches to enable builds on Solaris. ftp.cc and ppsocket.cc +2) Christof Meerwald's patches so that ncpd can autoterminate (-e option), and + patch for mgetty PLP autodetection (in the new patches directory), also a + patch to make the connection more stable. +3) Peter Cherriman's patch which fixes the "one hour out" bug, which "...is that + a file timestamp is sometimes different when you do a "ls -l" on a mounted + psion, than the timestamp listed by the properties box on the psion. + + My previous fix, no longer worked when the daylight saving changed. Linux + stores timestamps internally as the number of seconds since the EPOC in + UTC(GMT). However the psion seems stores timestamps as the number of seconds + since the EPOC. However the EPOC in defined relative to the currently set + timezone on the psion. + + My new fix takes into account the timezone and DST status provided by the + linux system, it now works in by GMT(UTC+0) and BST(UTC+0+DST), but I + haven't tested it very much in other timezones, but I think it works. + + It provides the correct timestamps apart from files created within a hour + of a DST change, however this can't be helped due to the strange way the + psion stores timestamps and handles timezone and DST." +4) Added --with-mountdir option to configure to allow the plpnfsd mount point + to be specified at build time. Default is /mnt/psion. +5) Added /dev/psion at the start of the serial ports probed for. +6) Peter Cherriman's patch that fixes compilation of ftp.cc on some platforms. +7) Jim Hague's patches for SIBO, and later Linux Kernels, from Feb 2000. + My apologies to Jim for not merging these sooner. He says: + + "I've been doing a little work on getting plptools working with my 3a. ... + I have plpftp working for file transfer and plpnsfd also working, at least + sufficiently to back up my 3a. + + I have also modified the include files required for the Linux build so + that it works with a 2.2 series kernels with the NFSv3 patch applied; + actually, all I've done is copy the relevant bits of the old NFSv2 headers. + + It all seems to work with my 3a, though compared to p3nfsd plpnsfd seems + very slow at listing directories - when time permits I shall take a + closer look. + + In addition to my English 3a (v3.22F) I have also tried it on an Italian 3a + (v3.40F). The latter exhibits some curious behaviour - if you start ncpd, + run up plpftp and quit plpftp, the 3a closes its serial port down (drops + CTS and DSR) and seems to need a reset before it will re-open the serial + port. Again, when time permits I shall see if it does this when using + PsiWin." + + Other parts of Jim's patch: + "Which reminds me - 0.6 doesn't seem to have working copyFromPsion and + copyToPsion. I've fixed it up and tidied up the retrieval of Owner + Infomation a little - 3as anyway send lots of \0\0\0\0\0, each of which + was being displayed in plpftp as a blank line. " + + Jim's patch removes lots of diagnostics in the rfsv16 code, and looks like + it fixes lots of stuff I hadn't got round to . + Splendid. + +Last patch update: 18/07/00. + diff --git a/configure.in b/configure.in index 19e8ed4..1d7c53e 100644 --- a/configure.in +++ b/configure.in @@ -61,7 +61,7 @@ AC_ARG_WITH(serial, AC_MSG_RESULT(Overriding serial line: $DDEV) ], [ AC_MSG_CHECKING(for default serial line) - AC_FIND_CDEV(/dev/tty0p0 /dev/tty00 /dev/ttyS0 /dev/term/a /dev/ttyfa /dev/ttya /dev/tty0 /dev/ttyf1 /dev/cuaa1, DDEV) + AC_FIND_CDEV(/dev/psion /dev/tty0p0 /dev/tty00 /dev/ttyS0 /dev/term/a /dev/ttyfa /dev/ttya /dev/tty0 /dev/ttyf1 /dev/cuaa1, DDEV) AC_MSG_RESULT($DDEV) test "$DDEV" = "NO" && AC_MSG_ERROR(NO serial lines. Use --with-serial.) ] @@ -108,6 +108,17 @@ AC_ARG_WITH(basedir, ) AC_SUBST(DBASEDIR) +AC_ARG_WITH(mountdir, + [ --with-mountdir=DDIR override default mount point [/mnt/psion]], + [ DDIR="$withval" + AC_MSG_RESULT(Overriding mount point: $DDIR) ], + [ DDIR="/mnt/psion" + AC_MSG_RESULT(Using default mount point: $DDIR) + ] +) +AC_SUBST(DDIR) + + AC_OUTPUT( Makefile lib/Makefile diff --git a/etc/psion.in b/etc/psion.in index 558828f..8985d40 100755 --- a/etc/psion.in +++ b/etc/psion.in @@ -11,9 +11,17 @@ [ -f @prefix@/sbin/ncpd ] || exit 0 [ -f @prefix@/sbin/plpnfsd ] || exit 0 +MGETTY_HASPLP=false +if grep -qs ^/PLP/ /etc/mgetty+sendfax/login.config ; then + MGETTY_HASPLP=true +fi + # See how we were called. case "$1" in start) + if $MGETTY_HASPLP ; then + echo "NOT Starting ncpd because mgetty configured for PLP" + fi echo -n "Starting Psion support: " daemon @prefix@/sbin/ncpd daemon @prefix@/sbin/plpnfsd diff --git a/include/defs.h.in b/include/defs.h.in index ce5f68d..012852e 100644 --- a/include/defs.h.in +++ b/include/defs.h.in @@ -17,10 +17,6 @@ #define DUSER "root" -#ifndef DDIR -# define DDIR "/mnt/psion" -#endif - #ifndef PSIONHOSTNAME # define PSIONHOSTNAME "localhost" #endif @@ -38,6 +34,8 @@ #define DPORT @DPORT@ #define DDRIVE "@DDRIVE@" #define DBASEDIR "@DBASEDIR@" +#define DDIR "@DDIR@" + /* Debugging */ diff --git a/include/linux-misc.h b/include/linux-misc.h new file mode 100644 index 0000000..afe1895 --- /dev/null +++ b/include/linux-misc.h @@ -0,0 +1,52 @@ +/* + * Linux nfs_mount_data version 3 (as expected by mp_mount.c). + * + * We extract it here to avoid some rather nasty fiddling necessary + * to compile with v3 and v4 (the latter as found in the NFS v3 stuff). + */ + +#ifndef LINUX_MISC_H +#define LINUX_MISC_H + +/* + * WARNING! Do not delete or change the order of these fields. If + * a new field is required then add it to the end. The version field + * tracks which fields are present. This will ensure some measure of + * mount-to-kernel version compatibility. Some of these aren't used yet + * but here they are anyway. + */ +#define NFS_MOUNT_VERSION 3 + +struct nfs_mount_data { + int version; /* 1 */ + int fd; /* 1 */ + struct nfs_fh root; /* 1 */ + int flags; /* 1 */ + int rsize; /* 1 */ + int wsize; /* 1 */ + int timeo; /* 1 */ + int retrans; /* 1 */ + int acregmin; /* 1 */ + int acregmax; /* 1 */ + int acdirmin; /* 1 */ + int acdirmax; /* 1 */ + struct sockaddr_in addr; /* 1 */ + char hostname[256]; /* 1 */ + int namlen; /* 2 */ + unsigned int bsize; /* 3 */ +}; + +/* bits in the flags field */ + +#define NFS_MOUNT_SOFT 0x0001 /* 1 */ +#define NFS_MOUNT_INTR 0x0002 /* 1 */ +#define NFS_MOUNT_SECURE 0x0004 /* 1 */ +#define NFS_MOUNT_POSIX 0x0008 /* 1 */ +#define NFS_MOUNT_NOCTO 0x0010 /* 1 */ +#define NFS_MOUNT_NOAC 0x0020 /* 1 */ +#define NFS_MOUNT_TCP 0x0040 /* 2 */ +#define NFS_MOUNT_VER3 0x0080 /* 3 */ +#define NFS_MOUNT_KERBEROS 0x0100 /* 3 */ +#define NFS_MOUNT_NONLM 0x0200 /* 3 */ + +#endif diff --git a/include/nfs_prot.h b/include/nfs_prot.h index 16cc31f..8bc490f 100644 --- a/include/nfs_prot.h +++ b/include/nfs_prot.h @@ -9,7 +9,6 @@ #endif #ifdef linux # include -# include #endif #ifdef __sgi # include @@ -42,7 +41,7 @@ #define NFSMODE_SOCK 0140000 #define NFSMODE_FIFO 0010000 -#if !defined(hpux) && !defined(linux) && !defined(__sgi) +#if !defined(hpux) && !defined(__sgi) enum nfsstat { NFS_OK = 0, NFSERR_PERM = 1, @@ -63,16 +62,12 @@ enum nfsstat { NFSERR_STALE = 70, NFSERR_WFLUSH = 99 }; -#endif /* !hpux, linux */ +#endif /* !hpux, sgi */ -#ifdef linux -typedef enum nfs_stat nfsstat; -#else typedef enum nfsstat nfsstat; -#endif bool_t xdr_nfsstat(); -#if !defined(hpux) && !defined(linux) && !defined(__sgi) +#if !defined(hpux) && !defined(__sgi) enum ftype { NFNON = 0, NFREG = 1, @@ -85,7 +80,7 @@ enum ftype { NFFIFO = 8 }; typedef enum ftype ftype; -#endif /* !linux, hpux */ +#endif /* !hpux, sgi */ #ifdef __sgi typedef enum nfsftype ftype; @@ -94,17 +89,12 @@ typedef enum nfsftype ftype; #ifdef hpux typedef enum nfsftype ftype; #endif -#ifdef linux -typedef enum nfs_ftype ftype; -#endif bool_t xdr_ftype(); -#ifndef linux struct nfs_fh { char data[NFS_FHSIZE]; }; -#endif typedef struct nfs_fh nfs_fh; bool_t xdr_nfs_fh(); diff --git a/lib/Makefile.am b/lib/Makefile.am index 08df502..ec7a840 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -1,9 +1,9 @@ lib_LTLIBRARIES = libplp.la -libplp_la_LDFLAGS = --debug -version-info 1:0:0 +libplp_la_LDFLAGS = --debug -version-info 1:1:0 libplp_la_SOURCES = bufferarray.cc bufferstore.cc iowatch.cc ppsocket.cc \ rfsv16.cc rfsv32.cc rfsvfactory.cc log.cc rfsv.cc rpcs32.cc rpcs16.cc \ - rpcs.cc rpcsfactory.cc + rpcs.cc rpcsfactory.cc psitime.cc EXTRA_DIST = bool.h bufferarray.h bufferstore.h iowatch.h ppsocket.h \ rfsv.h rfsv16.h rfsv32.h rfsvfactory.h log.h rpcs32.h rpcs16.h rpcs.h \ - rpcsfactory.h + rpcsfactory.h psitime.h diff --git a/lib/bufferarray.cc b/lib/bufferarray.cc index 4e922ed..77a08c6 100644 --- a/lib/bufferarray.cc +++ b/lib/bufferarray.cc @@ -45,11 +45,11 @@ bufferArray::bufferArray(const bufferArray & a) bufferArray::~bufferArray() { - delete[]buff; + delete []buff; } bufferStore bufferArray:: -popBuffer() +pop() { bufferStore ret; if (len > 0) { @@ -63,7 +63,7 @@ popBuffer() } void bufferArray:: -pushBuffer(const bufferStore & b) +append(const bufferStore & b) { if (len == lenAllocd) { lenAllocd += ALLOC_MIN; @@ -71,7 +71,7 @@ pushBuffer(const bufferStore & b) for (long i = 0; i < len; i++) { nb[i] = buff[i]; } - delete[]buff; + delete []buff; buff = nb; } buff[len++] = b; @@ -84,7 +84,7 @@ push(const bufferStore & b) lenAllocd += ALLOC_MIN; bufferStore *nb = new bufferStore[lenAllocd]; for (long i = len; i > 0; i--) { - nb[i] = buff[i-1]; + nb[i] = buff[i - 1]; } nb[0] = b; delete[]buff; @@ -92,18 +92,6 @@ push(const bufferStore & b) len++; } -bufferStore bufferArray:: -pop() -{ - return popBuffer(); -} - -void bufferArray:: -append(const bufferStore & b) -{ - pushBuffer(b); -} - long bufferArray:: length(void) { diff --git a/lib/bufferarray.h b/lib/bufferarray.h index fbf26f1..7389ab6 100644 --- a/lib/bufferarray.h +++ b/lib/bufferarray.h @@ -4,35 +4,120 @@ #include "bool.h" class bufferStore; +/** + * An array of bufferStores + */ class bufferArray { - public: - bufferArray(); - bufferArray(const bufferArray &a); - ~bufferArray(); - bufferArray &operator =(const bufferArray &a); - bool empty() const; - - // this is NOT a real push as with a FIFO but - // appends the bufferStore. - void pushBuffer(const bufferStore& b); - bufferStore popBuffer(void); - - // new API (push() now behaves like a FIFO, more operators - bufferStore &operator [](const unsigned long index); - bufferArray &operator +(const bufferStore &); // append - bufferArray &operator +(const bufferArray &); // append - bufferArray &operator +=(const bufferStore &b); // append - bufferStore pop(void); - void push(const bufferStore& b); - void append(const bufferStore& b); - long length(void); - void clear(void); +public: + /** + * constructs a new bufferArray. + * A minimum of @ref ALLOC_MIN + * elements is allocated. + */ + bufferArray(); + + /** + * Constructs a new bufferArray. + * + * @param a The initial contents for this array. + */ + bufferArray(const bufferArray &a); + + /** + * Destroys the bufferArray. + */ + ~bufferArray(); + + /** + * Copys the bufferArray. + */ + bufferArray &operator =(const bufferArray &a); + + /** + * Checks if this bufferArray is empty. + * + * @return true if the bufferArray is empty. + */ + bool empty() const; + + /** + * Retrieves the bufferStore at given index. + * + * @return The bufferStore at index. + */ + bufferStore &operator [](const unsigned long index); + + /** + * Appends a bufferStore. + */ + bufferArray &operator +(const bufferStore &); + + /** + * Concatenates two bufferArrays. + */ + bufferArray &operator +(const bufferArray &); + + /** + * Appends a bufferStore. + */ + bufferArray &operator +=(const bufferStore &b); + + /** + * Removes the first bufferStore. + * + * @return The removed bufferStore. + */ + bufferStore pop(void); + + /** + * Inserts a bufferStore at index 0. + * + * @param b The bufferStore to be inserted. + */ + void push(const bufferStore& b); + + /** + * Appends a bufferStore. + * + * @param b The bufferStore to be appended. + */ + void append(const bufferStore& b); + + /** + * Evaluates the current length. + * + * @return The current number of bufferStores + */ + long length(void); + + /** + * Empties the bufferArray. + */ + void clear(void); private: - static const long ALLOC_MIN = 5; - long len; - long lenAllocd; - bufferStore* buff; + /** + * Minimum number of bufferStores to + * allocate. + */ + static const long ALLOC_MIN = 5; + + /** + * The current number of bufferStores in + * this bufferArray. + */ + long len; + + /** + * The current number of bufferStores + * allocated. + */ + long lenAllocd; + + /** + * The content. + */ + bufferStore* buff; }; inline bool bufferArray::empty() const { return len == 0; } diff --git a/lib/bufferstore.cc b/lib/bufferstore.cc index 842e666..7f2b49d 100644 --- a/lib/bufferstore.cc +++ b/lib/bufferstore.cc @@ -22,28 +22,30 @@ #include // That should be iostream.h, but it won't build on Sun WorkShop C++ 5.0 #include +#include #include +#include #include "bufferstore.h" bufferStore::bufferStore() { lenAllocd = 0; - buff = NULL; + buff = 0L; len = 0; start = 0; } bufferStore::bufferStore(const bufferStore &a) { lenAllocd = (a.getLen() > MIN_LEN) ? a.getLen() : MIN_LEN; - buff = new unsigned char [lenAllocd]; + buff = (unsigned char *)malloc(lenAllocd); len = a.getLen(); memcpy(buff, a.getString(0), len); start = 0; } -bufferStore::bufferStore(const unsigned char*_buff, long _len) { +bufferStore::bufferStore(const unsigned char *_buff, long _len) { lenAllocd = (_len > MIN_LEN) ? _len : MIN_LEN; - buff = new unsigned char [lenAllocd]; + buff = (unsigned char *)malloc(lenAllocd); len = _len; memcpy(buff, _buff, len); start = 0; @@ -54,6 +56,7 @@ bufferStore &bufferStore::operator =(const bufferStore &a) { len = a.getLen(); memcpy(buff, a.getString(0), len); start = 0; + return *this; } void bufferStore::init() { @@ -69,7 +72,8 @@ void bufferStore::init(const unsigned char*_buff, long _len) { } bufferStore::~bufferStore() { - delete [] buff; + if (buff != 0L) + free(buff); } unsigned long bufferStore::getLen() const { @@ -92,23 +96,26 @@ unsigned int bufferStore::getDWord(long pos) const { } const char* bufferStore::getString(long pos) const { - return (const char*)buff+pos+start; + return (const char*)buff + pos + start; } ostream &operator<<(ostream &s, const bufferStore &m) { - { - for (int i = m.start; i < m.len; i++) + // save stream flags + ostream::fmtflags old = s.flags(); + + for (int i = m.start; i < m.len; i++) s << hex << setw(2) << setfill('0') << (int)m.buff[i] << " "; - } + + // restore stream flags + s.flags(old); s << "("; - { - for (int i = m.start; i < m.len; i++) { - unsigned char c = m.buff[i]; - if (c>=' ' && c <= 'z') s << c; - } + + for (int i = m.start; i < m.len; i++) { + unsigned char c = m.buff[i]; + s << (unsigned char)(isprint(c) ? c : '.'); } - s<< ")" << dec << setw(0); - return s; + + return s << ")"; } void bufferStore::discardFirstBytes(int n) { @@ -119,12 +126,9 @@ void bufferStore::discardFirstBytes(int n) { void bufferStore::checkAllocd(long newLen) { if (newLen >= lenAllocd) { do { - lenAllocd = (lenAllocd < MIN_LEN)?MIN_LEN:(lenAllocd*2); + lenAllocd = (lenAllocd < MIN_LEN) ? MIN_LEN : (lenAllocd * 2); } while (newLen >= lenAllocd); - unsigned char* newBuff = new unsigned char [lenAllocd]; - memcpy(&newBuff[start], &buff[start], len - start); - delete [] buff; - buff = newBuff; + buff = (unsigned char *)realloc(buff, lenAllocd); } } diff --git a/lib/bufferstore.h b/lib/bufferstore.h index df216c0..cad32fa 100644 --- a/lib/bufferstore.h +++ b/lib/bufferstore.h @@ -4,48 +4,205 @@ #include "bool.h" class ostream; +/** + * A generic container for an array of bytes. + * + * bufferStore provides an array of bytes which + * can be accessed using various types. + */ class bufferStore { public: - bufferStore(); - bufferStore(const unsigned char *, long); - ~bufferStore(); - bufferStore(const bufferStore &); - bufferStore &operator =(const bufferStore &); - - // 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); - friend ostream &operator<<(ostream &, const bufferStore &); - bool empty() const; - - // Writing utils - void init(); - void init(const unsigned char*, long); - void addByte(unsigned char); - void addWord(int); - void addDWord(long); - void addString(const char*); - void addStringT(const char*); - void addBytes(const unsigned char*, int); - void addBuff(const bufferStore &, long maxLen=-1); + /** + * Constructs a new bufferStore. + */ + bufferStore(); + + /** + * Constructs a new bufferStore and + * initializes its content. + * + * @param buf Pointer to data for initialization. + * @param len Length of data for initialization. + */ + bufferStore(const unsigned char *, long); + + /** + * Destroys a bufferStore instance. + */ + ~bufferStore(); + + /** + * Constructs a new bufferStore and + * initializes its content. + * + * @param b A bufferStore, whose content is + * used for initialization. + */ + bufferStore(const bufferStore &); + + /** + * Copies a bufferStore. + */ + bufferStore &operator =(const bufferStore &); + + /** + * Retrieves the length of a bufferStore. + * + * @returns The current length of the contents + * in bytes. + */ + unsigned long getLen() const; + + /** + * Retrieves the byte at index pos. + * + * @param pos The index of the byte to retrieve. + * + * @returns The value of the byte at index pos + */ + unsigned char getByte(long pos) const; + + /** + * Retrieves the word at index pos. + * + * @param pos The index of the word to retrieve. + * + * @returns The value of the word at index pos + */ + unsigned int getWord(long pos) const; + + /** + * Retrieves the dword at index pos. + * + * @param pos The index of the dword to retrieve. + * + * @returns The value of the dword at index pos + */ + unsigned int getDWord(long pos) const; + + /** + * Retrieves the characters at index pos. + * + * @param pos The index of the characters to retrieve. + * + * @returns A pointer to characters at index pos + */ + const char* getString(long pos=0) const; + + /** + * Removes bytes from the start of the buffer. + * + * @param len Number of bytes to remove. + */ + void discardFirstBytes(int); + + /** + * Prints a dump of the content. + * + * Mainly used for debugging purposes. + * + * @param s The stream to write to. + * @param b The bufferStore do be dumped. + * + * @returns The stream. + */ + friend ostream &operator<<(ostream &, const bufferStore &); + + /** + * Tests if the bufferStore is empty. + * + * @returns true, if the bufferStore is empty. + * false, if it contains data. + */ + bool empty() const; + + /** + * Initializes the bufferStore. + * + * All data is removed, the length is + * reset to 0. + */ + void init(); + + /** + * Initializes the bufferStore with + * a given data. + * + * @param buf Pointer to data to initialize from. + * @param len Length of data. + */ + void init(const unsigned char*, long); + + /** + * Appends a byte to the content of this instance. + * + * @param c The byte to append. + */ + void addByte(unsigned char); + + /** + * Appends a word to the content of this instance. + * + * @param w The word to append. + */ + void addWord(int); + + /** + * Appends a dword to the content of this instance. + * + * @param dw The dword to append. + */ + void addDWord(long); + + /** + * Appends a string to the content of this instance. + * + * The trailing zero byte is not copied + * to the content. + * + * @param s The string to append. + */ + void addString(const char*); + + /** + * Appends a string to the content of this instance. + * + * The trailing zero byte is copied + * to the content. + * + * @param s The string to append. + */ + void addStringT(const char*); + + /** + * Appends data to the content of this instance. + * + * @param buf The data to append. + * @param len Length of data. + */ + void addBytes(const unsigned char*, int); + + /** + * Appends data to the content of this instance. + * + * @param b The bufferStore whose content to append. + * @param maxLen Length of content. + */ + void addBuff(const bufferStore &, long maxLen=-1); private: - void checkAllocd(long newLen); + void checkAllocd(long newLen); - long len; - long lenAllocd; - long start; - unsigned char* buff; + long len; + long lenAllocd; + long start; + unsigned char* buff; - enum c { MIN_LEN = 300 }; + enum c { MIN_LEN = 300 }; }; inline bool bufferStore::empty() const { - return (len-start) == 0; + return (len-start) == 0; } #endif diff --git a/lib/ppsocket.cc b/lib/ppsocket.cc index cb04919..1249f18 100644 --- a/lib/ppsocket.cc +++ b/lib/ppsocket.cc @@ -181,7 +181,11 @@ listen(char *Host, int Port) ppsocket *ppsocket:: accept(char *Peer, int MaxLen) { +#ifdef sun + int len; +#else socklen_t len; +#endif ppsocket *accepted; char *peer; diff --git a/lib/psitime.cc b/lib/psitime.cc new file mode 100644 index 0000000..95ba6da --- /dev/null +++ b/lib/psitime.cc @@ -0,0 +1,117 @@ + +#include "psitime.h" +#include + +PsiTime::PsiTime(psi_timeval *_ptv, psi_timezone *_ptz) { + if (_ptv != 0L) + ptv = *_ptv; + if (_ptz != 0L) { + ptz = *_ptz; + ptzValid = true; + } else + ptzValid = false; + /* get our own timezone */ + gettimeofday(NULL, &utz); + psi2unix(); +} + +PsiTime::~PsiTime() { +} + +void PsiTime::setUnixTime(struct timeval *_utv) { + if (_utv != 0L) + utv = *_utv; + unix2psi(); +} + +void PsiTime::setUnixNow(void) { + gettimeofday(&utv, &utz); + unix2psi(); +} + + +void PsiTime::setPsiTime(psi_timeval *_ptv) { + if (_ptv != 0L) + ptv = *_ptv; + psi2unix(); +} + +void PsiTime::setPsiZone(psi_timezone *_ptz) { + if (_ptz != 0L) { + ptz = *_ptz; + ptzValid = true; + } + psi2unix(); +} + +struct timeval &PsiTime::getTimeval(void) { + return utv; +} + +time_t PsiTime::getTime(void) { + return utv.tv_sec; +} + +psi_timeval &PsiTime::getPsiTimeval(void) { + return ptv; +} + +ostream &operator<<(ostream &s, const PsiTime &t) { + const char *fmt = "%c"; + char buf[100]; + strftime(buf, sizeof(buf), fmt, localtime(&t.utv.tv_sec)); + s << buf; + return s; +} + +/** + * The difference between + * EPOC epoch (01.01.0001 00:00:00) + * and Unix epoch (01.01.1970 00:00:00) + * in microseconds. + */ +#define EPOCH_DIFF 0x00dcddb30f2f8000ULL + +static unsigned long long +evalOffset(psi_timezone ptz, bool valid) { + unsigned long long offset = 0; + + if (valid) { + offset = ptz.utc_offset; + if ((ptz.dst_zones & 0x40000000) || (ptz.dst_zones & ptz.home_zone)) + offset += 3600; + } else { + const char *offstr = getenv("PSI_TZ"); + if (offstr != 0L) { + char *err = 0L; + offset = strtoul(offstr, &err, 0); + if (err != 0L) + offset = 0; + } + } + offset *= 1000000; + return offset; +} + +void PsiTime::psi2unix(void) { + unsigned long long micro = ptv.tv_high; + micro = (micro << 32) | ptv.tv_low; + + /* Substract Psion's idea of UTC offset */ + micro -= evalOffset(ptz, ptzValid); + micro -= EPOCH_DIFF; + + utv.tv_sec = micro / 1000000; + utv.tv_usec = micro % 1000000; +} + +void PsiTime::unix2psi(void) { + unsigned long long micro = utv.tv_sec * 1000000 + utv.tv_usec; + + /* Add Psion's idea of UTC offset */ + micro += EPOCH_DIFF; + micro += evalOffset(ptz, ptzValid); + + ptv.tv_low = micro & 0x0ffffffff; + ptv.tv_high = (micro >> 32) & 0x0ffffffff; +} diff --git a/lib/psitime.h b/lib/psitime.h new file mode 100644 index 0000000..6946fc1 --- /dev/null +++ b/lib/psitime.h @@ -0,0 +1,198 @@ +#ifndef _PSITIME_H_ +#define _PSITIME_H_ + +#include +#include + +#include + +/** + * Holds a Psion time value. + * Psion time values are 64 bit + * integers describing the time + * since 01.01.0001 in microseconds. + */ +typedef struct psi_timeval_t { + /** + * Prints a psi_timeval in human readable format. + */ + friend ostream &operator<<(ostream &o, const psi_timeval_t &ptv) { + ostream::fmtflags old = o.flags(); + unsigned long long micro = ptv.tv_high; + micro = (micro << 32) | ptv.tv_low; + micro /= 1000000; + int s = micro % 60; + micro /= 60; + int m = micro % 60; + micro /= 60; + int h = micro % 24; + micro /= 24; + int d = micro % 365; + micro /= 365; + int y = micro; + o << dec; + if (y > 0) + o << y << " year" << ((y > 1) ? "s " : " "); + if (d > 0) + o << d << " day" << ((d > 1) ? "s " : " "); + if (h > 0) + o << h << " hour" << ((h != 1) ? "s " : " "); + if (m > 0) + o << m << " minute" << ((m != 1) ? "s " : " "); + o << s << " second" << ((s != 1) ? "s" : ""); + o.flags(old); + return o; + } + /** + * The lower 32 bits + */ + unsigned long tv_low; + /** + * The upper 32 bits + */ + unsigned long tv_high; +} psi_timeval; + +/** + * holds a Psion time zone description. + */ +typedef struct psi_timezone_t { + friend ostream &operator<<(ostream &s, const psi_timezone_t &ptz) { + ostream::fmtflags old = s.flags(); + int h = ptz.utc_offset / 3600; + int m = ptz.utc_offset % 3600; + s << "offs: " << dec << h << "h"; + if (m != 0) + s << ", " << m << "m"; + s.flags(old); + return s; + } + unsigned long utc_offset; + unsigned long dst_zones; + unsigned long home_zone; +} psi_timezone; + +/** + * Psion time related utility class. + * + * PsiTime provides easy access to the time format, used + * when communicating with a Psion. Internally, the time + * is always normalized to GMT. The time value can be set + * and retrieved in both Unix and Psion formats. This + * allows easy conversion between both formats. + * NOTE: For proper conversion, the current timezone of + * the Psion has to be set. For EPOC devices, the + * timezone can be evaluated using + * @ref rpcs::getMachineInfo. For SIBO devices, + * unfortunately there is no known method of retrieving + * this information. Therefore, if the timezone is + * not set, a fallback using the environment + * variable PSI_TZ is provided. Users should + * set this variable to the offset of their time zone + * in seconds. + */ +class PsiTime { +public: + /** + * Contructs a new instance. + * + * @param _ptv A Psion time value for initialization. + * @param _ptz A Psion timezone for initialization. + */ + PsiTime(psi_timeval *_ptv = 0L, psi_timezone *_ptz = 0L); + + /** + * Constructs a new instance. + * + * @param _utv A Unix time value for initialization. + * @param _utz A Unix timezone for initialization. + */ + PsiTime(struct timeval *_utv = 0L, struct timezone *_utz = 0L); + + /** + * Destroys the instance. + */ + ~PsiTime(); + + /** + * Modifies the value of this instance. + * + * @param _ptv The new Psion time representation. + */ + void setPsiTime(psi_timeval *_ptv); + + /** + * Sets the Psion time zone of this instance. + * + * @param _ptz The new Psion time zone. + */ + void setPsiZone(psi_timezone *_ptz); + + /** + * Sets the value of this instance. + * + * @param _utv The new Unix time representation. + */ + void setUnixTime(struct timeval *_utv); + + /** + * Sets the value of this instance to the + * current time of the Unix machine. + */ + void setUnixNow(void); + + /** + * Retrieves the instance's current value + * in Unix time format. + * + * @returns The instance's current time as Unix struct timeval. + */ + struct timeval &getTimeval(void); + + /** + * Retrieves the instance's current value + * in Unix time format. + * + * @returns The instance's current time as Unix time_t. + */ + time_t getTime(void); + + /** + * Retrieves the instance's current value + * in Psion time format. + * + * @returns The instance's current time a Psion struct psi_timeval_t. + */ + psi_timeval &getPsiTimeval(void); + + /** + * Prints the instance's value in human readable format. + * This function uses the current locale setting for + * formatting the time. + * + * @param s The stream to be written. + * @param t The instance whose value should be displayed. + * + * @returns The stream. + */ + friend ostream &operator<<(ostream &s, const PsiTime &t); + + enum zone { + PSI_TZ_NONE = 0, + PSI_TZ_EUROPEAN = 1, + PSI_TZ_NORTHERN = 2, + PSI_TZ_SOUTHERN = 4, + PSI_TZ_HOME = 0x40000000, + }; + +private: + void psi2unix(void); + void unix2psi(void); + + psi_timeval ptv; + psi_timezone ptz; + struct timeval utv; + struct timezone utz; + bool ptzValid; +}; +#endif diff --git a/lib/rfsv.h b/lib/rfsv.h index e6006ef..888db8a 100644 --- a/lib/rfsv.h +++ b/lib/rfsv.h @@ -5,12 +5,29 @@ class ppsocket; class bufferStore; class bufferArray; -#define RFSV_SENDLEN 2000 +const unsigned long RFSV_SENDLEN = 2000; +/** + * Defines the callback procedure for + * progress indication of copy operations. + */ typedef int (*cpCallback_t)(long); // Abstract base class of RFSV ; 16-bit and 32-bit variants implement this // interface +/** + * Access remote file services of a Psion. + * + * rfsv provides an API for accessing file services + * of a Psion connected via ncpd. This class defines the + * interface and a small amount of common constants and + * methods. The majority of implementation is provided + * by @ref rfsv32 and @ref rfsv16, which implement the + * variations of the protocol for EPOC and SIBO respectively. + * Usually, the class @ref rfsvfactory is used to instantiate + * the correct variant depending on the remote machine, + * currently connected. + */ class rfsv { public: virtual ~rfsv() {} @@ -46,20 +63,32 @@ class rfsv { virtual long rename(const char *, const char *) = 0; virtual long remove(const char *) = 0; + virtual long attr2std(long) = 0; + virtual long std2attr(long) = 0; + char *opErr(long); + /** + * The kown modes for seek. + */ enum seek_mode { PSI_SEEK_SET = 1, PSI_SEEK_CUR = 2, PSI_SEEK_END = 3 }; + /** + * The known modes for file open. + */ enum open_flags { PSI_O_RDONLY = 00, PSI_O_WRONLY = 01, PSI_O_RDWR = 02, }; + /** + * The known modes for file creation. + */ enum open_mode { PSI_O_CREAT = 0100, PSI_O_EXCL = 0200, @@ -67,6 +96,9 @@ class rfsv { PSI_O_APPEND = 02000, }; + /** + * The known error codes. + */ enum errs { E_PSI_GEN_NONE = 0, E_PSI_GEN_FAIL = -1, @@ -145,6 +177,36 @@ class rfsv { // Special error code for "Operation not permitted in RFSV16" E_PSI_NOT_SIBO = -200 }; + + /** + * The known file attributes + */ + enum file_attribs { + /** + * Attributes, valid on both EPOC and SIBO. + */ + PSI_A_RDONLY = 0x0001, + PSI_A_HIDDEN = 0x0002, + PSI_A_SYSTEM = 0x0004, + PSI_A_DIR = 0x0008, + PSI_A_ARCHIVE = 0x0010, + PSI_A_VOLUME = 0x0020, + + /** + * Attributes, valid on EPOC only. + */ + PSI_A_NORMAL = 0x0040, + PSI_A_TEMP = 0x0080, + PSI_A_COMPRESSED = 0x0100, + + /** + * Attributes, valid on SIBO only. + */ + PSI_A_READ = 0x0200, + PSI_A_EXEC = 0x0400, + PSI_A_STREAM = 0x0800, + PSI_A_TEXT = 0x1000 + }; }; #endif diff --git a/lib/rfsv16.cc b/lib/rfsv16.cc index 9ee24f2..f71be9f 100644 --- a/lib/rfsv16.cc +++ b/lib/rfsv16.cc @@ -37,6 +37,8 @@ #include "ppsocket.h" #include "bufferarray.h" +#define RFSV16_MAXDATALEN 852 // 640 + rfsv16::rfsv16(ppsocket *_skt) : serNum(0) { skt = _skt; @@ -57,7 +59,6 @@ rfsv16::~rfsv16() void rfsv16:: reconnect() { -cerr << "rfsv16::reconnect" << endl; skt->closeSocket(); skt->reconnect(); serNum = 0; @@ -68,7 +69,6 @@ cerr << "rfsv16::reconnect" << endl; void rfsv16:: reset() { -cerr << "rfsv16::reset" << endl; bufferStore a; status = E_PSI_FILE_DISC; a.addStringT(getConnectName()); @@ -91,7 +91,7 @@ getStatus() const char *rfsv16:: getConnectName() { - return "SYS$RFSV.*"; + return "SYS$RFSV"; } int rfsv16:: @@ -148,14 +148,10 @@ fopen(long attr, const char *name, long &handle) return E_PSI_FILE_DISC; long res = getResponse(a); - // cerr << "fopen, getword 0 is " << hex << setw(2) << a.getWord(0) << endl; - // cerr << "fopen, getlen is " << hex << setw(2) << a.getLen() << endl; - // cerr << "fopen, res is " << hex << setw(2) << res << endl; - if (!res && a.getLen() == 4 && a.getWord(0) == 0) { - handle = (long)a.getWord(2); + if (res == 0) { + handle = (long)a.getWord(0); return 0; } - // cerr << "fopen: Unknown response (" << attr << "," << name << ") " << a < 16) { int version = a.getWord(0); if (version != 2) { @@ -242,7 +248,7 @@ dir(const char *dirName, bufferArray * files) temp.addDWord(size); temp.addDWord((long)status); temp.addStringT(s); - files->pushBuffer(temp); + files->append(temp); } } if ((short int)res == E_PSI_FILE_EOF) @@ -300,15 +306,13 @@ cerr << "rfsv16::fgetmtime" << endl; return E_PSI_FILE_DISC; long res = getResponse(a); - if (res != 0) + if (res != 0) { + cerr << "fgetmtime: Error " << res << " on file " << name << endl; return res; - if (a.getLen() == 2) { - cerr << "fgetmtime: Error " << a.getWord(0) << " on file " << name << endl; - return 1; } - else if (a.getLen() == 18 && a.getWord(0) == 0) { - *mtime = a.getDWord(10); - return a.getWord(0); + else if (a.getLen() == 16) { + *mtime = a.getDWord(8); + return res; } cerr << "fgetmtime: Unknown response (" << name << ") " << a < 16) { int version = a.getWord(0); if (version != 2) { @@ -475,7 +475,7 @@ devlist(long *devbits) // Find the drive to FOPEN char name[4] = { 'x', ':', '\\', '\0' } ; - a.discardFirstBytes(8); // Result, fsys, dev, path, file, file, ending, flag + a.discardFirstBytes(6); // Result, fsys, dev, path, file, file, ending, flag /* This leaves R E M : : M : \ */ name[0] = (char) a.getByte(5); // the M long status = fopen(P_FDEVICE, name, fileHandle); @@ -491,7 +491,6 @@ devlist(long *devbits) res = getResponse(a); if (res) break; - a.discardFirstBytes(2); // Result int version = a.getWord(0); if (version != 2) { cerr << "devlist: not version 2" << endl; @@ -551,7 +550,6 @@ devinfo(int devnum, long *vfree, long *vtotal, long *vattr, // cerr << "devinfo STATUSDEVICE res is " << dec << (signed short int) res << endl; return NULL; } - a.discardFirstBytes(2); // Result int type = a.getWord(2); int changeable = a.getWord(4); long size = a.getDWord(6); @@ -571,14 +569,24 @@ devinfo(int devnum, long *vfree, long *vtotal, long *vattr, bool rfsv16:: sendCommand(enum commands cc, bufferStore & data) { + if (status == E_PSI_FILE_DISC) { + reconnect(); + if (status == E_PSI_FILE_DISC) + return FALSE; + } + bool result; bufferStore a; a.addWord(cc); a.addWord(data.getLen()); a.addBuff(data); result = skt->sendBufferStore(a); + if (!result) { + reconnect(); + result = skt->sendBufferStore(a); if (!result) status = E_PSI_FILE_DISC; + } return result; } @@ -589,17 +597,22 @@ getResponse(bufferStore & data) // getWord(2) is the size field // which is the body of the response not counting the command (002a) and // the size word. - if (skt->getBufferStore(data) == 1 && - data.getWord(0) == 0x2a && + if (skt->getBufferStore(data) != 1) { + cerr << "rfsv16::getResponse: duff response. " + "getBufferStore failed." << endl; + } else if (data.getWord(0) == 0x2a && data.getWord(2) == data.getLen()-4) { - data.discardFirstBytes(4); - long ret = data.getWord(0); + long ret = (short)data.getWord(4); + data.discardFirstBytes(6); return ret; - } else - status = E_PSI_FILE_DISC; + } else { cerr << "rfsv16::getResponse: duff response. Size field:" << -data.getWord(2) << " Frame size:" << data.getLen()-4 << " Result field:" << -data.getWord(4) << endl; + data.getWord(2) << " Frame size:" << + data.getLen()-4 << " Result field:" << + data.getWord(4) << endl; + } + + status = E_PSI_FILE_DISC; return status; } @@ -614,61 +627,88 @@ cerr << "rfsv16::opErr 0x" << hex << setfill('0') << setw(4) long rfsv16:: fread(long handle, unsigned char *buf, long len) { -cerr << "rfsv16::fread ***" << endl; + long res; + long count = 0; + + while (count < len) { bufferStore a; - long remaining = len; - // Read in blocks of 291 bytes; the maximum payload for an RFSV frame. - // ( As seen in traces ) - this isn't optimal: RFSV can handle - // fragmentation of frames, where only the first FREAD RESPONSE frame - // has a RESPONSE (00 2A), SIZE and RESULT field. Every subsequent frame + + // Read in blocks of 291 bytes; the maximum payload for + // an RFSV frame. ( As seen in traces ) - this isn't optimal: + // RFSV can handle fragmentation of frames, where only the + // first FREAD RESPONSE frame has a RESPONSE (00 2A), SIZE + // and RESULT field. Every subsequent frame // just has data, 297 bytes (or less) of it. - const int maxblock = 291; - long readsofar = 0; - while (remaining) { - long thisblock = (remaining > maxblock) ? maxblock : remaining; -cerr << "fread: " << dec << remaining << " bytes remain. This block is " << thisblock -<< " bytes." << endl; - a.init(); a.addWord(handle); - a.addWord(thisblock); + a.addWord((len - count) > RFSV16_MAXDATALEN + ? RFSV16_MAXDATALEN + : (len - count)); sendCommand(FREAD, a); - long res = getResponse(a); - remaining -= a.getLen(); -// copy the data to buf + res = getResponse(a); -cerr << "fread getResponse returned " << dec<< (signed short int) res << " data: " << a << dec < RFSV16_MAXDATALEN + ? RFSV16_MAXDATALEN + : (len - count); + a.addWord(handle); + a.addBytes(buf, nbytes); + sendCommand(FWRITE, a); + res = getResponse(a); + if (res != 0) + return res; + + count += nbytes; + buf += nbytes; + } + return count; } long rfsv16:: copyFromPsion(const char *from, const char *to, cpCallback_t cb) { -cerr << "rfsv16::copyFromPsion" << endl; long handle; long res; long len; if ((res = fopen(P_FSHARE | P_FSTREAM, from, handle)) != 0) return res; -cerr << "fopen response is " << dec << (signed short int)res << endl; ofstream op(to); if (!op) { fclose(handle); return -1; } do { - unsigned char buf[2000]; + unsigned char buf[RFSV_SENDLEN]; if ((len = fread(handle, buf, sizeof(buf))) > 0) op.write(buf, len); if (cb) { @@ -681,13 +721,12 @@ cerr << "fopen response is " << dec << (signed short int)res << endl; fclose(handle); op.close(); - return len; + return len == E_PSI_FILE_EOF ? 0 : len; } long rfsv16:: copyToPsion(const char *from, const char *to, cpCallback_t cb) { -cerr << "rfsv16::copyToPsion" << endl; long handle; long res; @@ -701,50 +740,30 @@ cerr << "rfsv16::copyToPsion" << endl; return res; } unsigned char *buff = new unsigned char[RFSV_SENDLEN]; - int total = 0; - while (ip && !ip.eof()) { + while (res >= 0 && ip && !ip.eof()) { ip.read(buff, RFSV_SENDLEN); - bufferStore tmp(buff, ip.gcount()); - int len = tmp.getLen(); - total += len; - if (len == 0) - break; - bufferStore a; - a.addDWord(handle); - a.addBuff(tmp); - if (!sendCommand(FWRITE, a)) { // FIXME: need to check params - fclose(handle); - ip.close(); - delete[]buff; - return E_PSI_FILE_DISC; + res = fwrite(handle, buff, ip.gcount()); + if (cb) + if (!cb(res)) { + res = E_PSI_FILE_CANCEL; } - res = getResponse(a); - if (res) { - fclose(handle); - ip.close(); - delete[]buff; - return res; } - if (cb) { - if (!cb(len)) { - fclose(handle); - ip.close(); + delete[]buff; - return E_PSI_FILE_CANCEL; - } - } - } fclose(handle); ip.close(); - delete[]buff; return 0; } long rfsv16:: fsetsize(long handle, long size) { -cerr << "rfsv16::fsetsize ***" << endl; - return 0; + bufferStore a; + a.addWord(handle); + a.addDWord(size); + if (!sendCommand(FSETEOF, a)) + return E_PSI_FILE_DISC; + return getResponse(a); } /* @@ -755,8 +774,92 @@ cerr << "rfsv16::fsetsize ***" << endl; long rfsv16:: fseek(long handle, long pos, long mode) { -cerr << "rfsv16::fseek ***" << endl; - return 0; + 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 < PSI_SEEK_SET) || (mode > PSI_SEEK_END)) + return E_PSI_GEN_ARG; + + if ((mode == PSI_SEEK_CUR) && (pos >= 0)) { + /* get and save current position */ + a.init(); + a.addWord(handle); + a.addDWord(0); + a.addWord(PSI_SEEK_CUR); + if (!sendCommand(FSEEK, a)) + return E_PSI_FILE_DISC; + if ((res = getResponse(a)) != 0) + return res; + savpos = a.getDWord(0); + if (pos == 0) + return savpos; + } + if ((mode == PSI_SEEK_END) && (pos >= 0)) { + /* get and save end position */ + a.init(); + a.addWord(handle); + a.addDWord(0); + a.addWord(PSI_SEEK_END); + if (!sendCommand(FSEEK, a)) + return E_PSI_FILE_DISC; + if ((res = getResponse(a)) != 0) + return res; + savpos = a.getDWord(0); + if (pos == 0) + return savpos; + } + /* Now the real seek */ + a.addWord(handle); + a.addDWord(pos); + a.addWord(mode); + if (!sendCommand(FSEEK, a)) + return E_PSI_FILE_DISC; + if ((res = getResponse(a)) != 0) + return res; + realpos = a.getDWord(0); + switch (mode) { + case PSI_SEEK_SET: + calcpos = pos; + break; + case PSI_SEEK_CUR: + calcpos = savpos + pos; + break; + case PSI_SEEK_END: + return realpos; + break; + } + if (calcpos > realpos) { + /* Beyond end of file */ + res = fsetsize(handle, calcpos); + if (res != 0) + return res; + a.init(); + a.addWord(handle); + a.addDWord(calcpos); + a.addWord(PSI_SEEK_SET); + if (!sendCommand(FSEEK, a)) + return E_PSI_FILE_DISC; + if ((res = getResponse(a)) != 0) + return res; + realpos = a.getDWord(0); + } + return realpos; } long rfsv16:: @@ -771,11 +874,11 @@ mkdir(const char* dirName) // and this needs sending in the length word. sendCommand(MKDIR, a); long res = getResponse(a); - if (!res && a.getLen() == 2) { + if (!res) { // Correct response - return a.getWord(0); + return res; } - cerr << "Unknown response from mkdir "<< a <tm_isdst) micro -= (60*60); /* Adjust for DST */ + } + return (long) micro; } @@ -216,8 +225,17 @@ time2micro(unsigned long time, unsigned long µHi, unsigned long µLo) pes <<= 8; micro += pes; micro -= EPOCH_DIFF_SECS; - micro += EPOCH_2H; - micro -= 3600; /* 1 hour PJC */ + + /* Adjust for timezone and daylight saving time */ + { + struct tm *t; + long date=time; + + t = localtime(&date); + micro -= timezone; /* Adjust for timezone */ + if (t->tm_isdst) micro += (60*60); /* Adjust for DST */ + } + micro *= (unsigned long long)1000000; microLo = (micro & (unsigned long long)0x0FFFFFFFF); micro >>= 32; @@ -263,7 +281,7 @@ dir(const char *name, bufferArray * files) s.addByte(0); while (d % 4) d++; - files->pushBuffer(s); + files->append(s); d += shortLen; while (d % 4) d++; @@ -495,8 +513,12 @@ sendCommand(enum commands cc, bufferStore & data) serNum = 0; a.addBuff(data); result = skt->sendBufferStore(a); + if (!result) { + reconnect(); + result = skt->sendBufferStore(a); if (!result) status = E_PSI_FILE_DISC; + } return result; } @@ -888,3 +910,73 @@ err2psierr(long status) } return e2psi[status - E_EPOC_DIR_FULL]; } + + +/* + * Translate EPOC attributes to standard attributes. + */ +long rfsv32:: +attr2std(long attr) +{ + long res = 0; + + // Common attributes + if (attr & EPOC_ATTR_RONLY) + res |= PSI_A_RDONLY; + if (attr & EPOC_ATTR_HIDDEN) + res |= PSI_A_HIDDEN; + if (attr & EPOC_ATTR_SYSTEM) + res |= PSI_A_SYSTEM; + if (attr & EPOC_ATTR_DIRECTORY) + res |= PSI_A_DIR; + if (attr & EPOC_ATTR_ARCHIVE) + res |= PSI_A_ARCHIVE; + if (attr & EPOC_ATTR_VOLUME) + res |= PSI_A_VOLUME; + + // EPOC-specific + if (attr & EPOC_ATTR_NORMAL) + res |= PSI_A_NORMAL; + if (attr & EPOC_ATTR_TEMPORARY) + res |= PSI_A_TEMP; + if (attr & EPOC_ATTR_COMPRESSED) + res |= PSI_A_COMPRESSED; + + // Do what we can for SIBO + res |= PSI_A_READ; + + return res; +} + +/* + * Translate standard attributes to EPOC attributes. + */ +long rfsv32:: +std2attr(long attr) +{ + long res = 0; + + // Common attributes + if (!(attr & PSI_A_RDONLY)) + res |= EPOC_ATTR_RONLY; + if (attr & PSI_A_HIDDEN) + res |= EPOC_ATTR_HIDDEN; + if (attr & PSI_A_SYSTEM) + res |= EPOC_ATTR_SYSTEM; + if (attr & PSI_A_DIR) + res |= EPOC_ATTR_DIRECTORY; + if (attr & PSI_A_ARCHIVE) + res |= EPOC_ATTR_ARCHIVE; + if (attr & PSI_A_VOLUME) + res |= EPOC_ATTR_VOLUME; + + // EPOC-specific + if (attr & PSI_A_NORMAL) + res |= EPOC_ATTR_NORMAL; + if (attr & PSI_A_TEMP) + res |= EPOC_ATTR_TEMPORARY; + if (attr & PSI_A_COMPRESSED) + res |= EPOC_ATTR_COMPRESSED; + + return res; +} diff --git a/lib/rfsv32.h b/lib/rfsv32.h index 8383e72..2aac5b9 100644 --- a/lib/rfsv32.h +++ b/lib/rfsv32.h @@ -44,6 +44,9 @@ class rfsv32 : public rfsv { char *opAttr(long); long opMode(long); + long attr2std(long); + long std2attr(long); + private: enum file_attrib { diff --git a/lib/rpcs.cc b/lib/rpcs.cc index 5863c5b..79630cf 100644 --- a/lib/rpcs.cc +++ b/lib/rpcs.cc @@ -28,11 +28,21 @@ #include "ppsocket.h" #include "bufferarray.h" +static const char * const langstrings[] = { + "Test", "English", "French", "German", "Spanish", "Italian", "Swedish", + "Danish", "Norwegian", "Finnish", "American", "Swiss French", + "Swiss German", "Portugese", "Turkish", "Icelandic", "Russian", + "Hungarian", "Dutch", "Belgian Flemish", "Australian", + "Belgish French", "Austrian", "New Zealand", + "International French", "Czech", "Slovak", "Polish", "Slovenian", + 0L +}; + // // public common API // void rpcs:: -reconnect() +reconnect(void) { skt->closeSocket(); skt->reconnect(); @@ -40,7 +50,7 @@ reconnect() } void rpcs:: -reset() +reset(void) { bufferStore a; status = E_PSI_FILE_DISC; @@ -54,13 +64,13 @@ reset() } long rpcs:: -getStatus() +getStatus(void) { return status; } const char *rpcs:: -getConnectName() +getConnectName(void) { return "SYS$RPCS"; } @@ -68,16 +78,6 @@ getConnectName() // // protected internals // -char *rpcs:: -convertSlash(const char *name) -{ - char *n = strdup(name); - for (char *p = n; *p; p++) - if (*p == '/') - *p = '\\'; - return n; -} - bool rpcs:: sendCommand(enum commands cc, bufferStore & data) { @@ -91,16 +91,21 @@ sendCommand(enum commands cc, bufferStore & data) a.addByte(cc); a.addBuff(data); result = skt->sendBufferStore(a); - if (!result) - status = E_PSI_FILE_DISC; + if (!result) { + reconnect(); + result = skt->sendBufferStore(a); + if (!result) + status = E_PSI_FILE_DISC; + } return result; } -long rpcs:: +int rpcs:: getResponse(bufferStore & data) { if (skt->getBufferStore(data) == 1) { - long ret = data.getByte(0); + char ret = data.getByte(0); + data.discardFirstBytes(1); return ret; } else status = E_PSI_FILE_DISC; @@ -113,12 +118,12 @@ getResponse(bufferStore & data) int rpcs:: getNCPversion(int &major, int &minor) { + int res; bufferStore a; + if (!sendCommand(QUERY_NCP, a)) return E_PSI_FILE_DISC; - long res = getResponse(a); - a.discardFirstBytes(1); - if (res) + if ((res = getResponse(a))) return res; if (a.getLen() != 2) return E_PSI_GEN_FAIL; @@ -131,6 +136,7 @@ int rpcs:: execProgram(const char *program, const char *args) { bufferStore a; + a.addStringT(program); int l = strlen(program); for (int i = 127; i > l; i--) @@ -139,15 +145,14 @@ execProgram(const char *program, const char *args) a.addStringT(args); if (!sendCommand(EXEC_PROG, a)) return E_PSI_FILE_DISC; - long res = getResponse(a); -cout << res << " " << a << endl; - return res; + return getResponse(a); } int rpcs:: stopProgram(const char *program) { bufferStore a; + a.addStringT(program); if (!sendCommand(STOP_PROG, a)) return E_PSI_FILE_DISC; @@ -158,6 +163,7 @@ int rpcs:: queryProgram(const char *program) { bufferStore a; + a.addStringT(program); if (!sendCommand(QUERY_PROG, a)) return E_PSI_FILE_DISC; @@ -167,13 +173,13 @@ queryProgram(const char *program) int rpcs:: formatOpen(const char *drive, int &handle, int &count) { + int res; bufferStore a; + a.addStringT(drive); if (!sendCommand(FORMAT_OPEN, a)) return E_PSI_FILE_DISC; - long res = getResponse(a); - a.discardFirstBytes(1); - if (res) + if ((res = getResponse(a))) return res; if (a.getLen() != 4) return E_PSI_GEN_FAIL; @@ -186,6 +192,7 @@ int rpcs:: formatRead(int handle) { bufferStore a; + a.addWord(handle); if (!sendCommand(FORMAT_READ, a)) return E_PSI_FILE_DISC; @@ -195,13 +202,13 @@ formatRead(int handle) int rpcs:: getUniqueID(const char *device, long &id) { + int res; bufferStore a; + a.addStringT(device); if (!sendCommand(GET_UNIQUEID, a)) return E_PSI_FILE_DISC; - long res = getResponse(a); - a.discardFirstBytes(1); - if (res) + if ((res = getResponse(a))) return res; if (a.getLen() != 4) return E_PSI_GEN_FAIL; @@ -210,14 +217,14 @@ getUniqueID(const char *device, long &id) } int rpcs:: -getOwnerInfo(bufferArray &ret) +getOwnerInfo(bufferArray &owner) { + int res; bufferStore a; + if (!sendCommand(GET_OWNERINFO, a)) return E_PSI_FILE_DISC; - long res = getResponse(a); - a.discardFirstBytes(1); - if (res) + if ((res = getResponse(a))) return res; a.addByte(0); int l = a.getLen(); @@ -225,13 +232,18 @@ getOwnerInfo(bufferArray &ret) for (int i = 0; i < l; i++) if (s[i] == 6) s[i] = 0; - ret.clear(); + owner.clear(); while (l > 0) { - bufferStore b; - b.addStringT(s); - ret += b; - l -= (strlen(s) + 1); - s += (strlen(s) + 1); + if (*s != '\0') { + bufferStore b; + b.addStringT(s); + owner += b; + l -= (strlen(s) + 1); + s += (strlen(s) + 1); + } else { + l--; + s++; + } } return res; } @@ -239,12 +251,12 @@ getOwnerInfo(bufferArray &ret) int rpcs:: getMachineType(int &type) { + int res; bufferStore a; + if (!sendCommand(GET_MACHINETYPE, a)) return E_PSI_FILE_DISC; - long res = getResponse(a); - a.discardFirstBytes(1); - if (res) + if ((res = getResponse(a))) return res; if (a.getLen() != 2) return E_PSI_GEN_FAIL; @@ -253,27 +265,25 @@ getMachineType(int &type) } int rpcs:: -fuser(const char *name, char *buf, int bufsize) +fuser(const char *name, char *buf, int maxlen) { + int res; bufferStore a; + char *p; + a.addStringT(name); if (!sendCommand(FUSER, a)) return E_PSI_FILE_DISC; - long res = getResponse(a); - a.discardFirstBytes(1); - if (res) + if ((res = getResponse(a))) return res; - int len = ((int)a.getLen() > bufsize) ? bufsize - 1 : a.getLen(); - strncpy(buf, a.getString(0), len); - buf[len] = '\0'; - char *p; + strncpy(buf, a.getString(0), maxlen - 1); while ((p = strchr(buf, 6))) - *p = '\n'; + *p = '\0'; return res; } int rpcs:: -quitServer() +quitServer(void) { bufferStore a; if (!sendCommand(QUIT_SERVER, a)) @@ -281,3 +291,25 @@ quitServer() return getResponse(a); } +const char *rpcs:: +languageString(int code) { + for (int i = 0; i <= code; i++) + if (langstrings[i] == 0L) + return "Unknown"; + return langstrings[code]; +} + +const char *rpcs:: +batteryStatusString(int code) { + switch (code) { + case PSI_BATT_DEAD: + return "Empty"; + case PSI_BATT_VERYLOW: + return "Very low"; + case PSI_BATT_LOW: + return "Low"; + case PSI_BATT_GOOD: + return "Good"; + } + return "Unknown"; +} diff --git a/lib/rpcs.h b/lib/rpcs.h index cb71c88..3c569bb 100644 --- a/lib/rpcs.h +++ b/lib/rpcs.h @@ -1,37 +1,252 @@ #ifndef _rpcs_h_ #define _rpcs_h_ +#include "psitime.h" + class ppsocket; class bufferStore; class bufferArray; +/** + * This struct holds the data returned + * by @ref rpcs::getMachineInfo. + */ +typedef struct machineInfo_t { + unsigned long machineType; + char machineName[17]; + unsigned long long machineUID; + unsigned long countryCode; + char uiLanguage[32]; + + unsigned short romMajor; + unsigned short romMinor; + unsigned short romBuild; + unsigned long romSize; + bool romProgrammable; + + unsigned long ramSize; + unsigned long ramFree; + unsigned long ramMaxFree; + unsigned long ramDiskSize; + + unsigned long registrySize; + unsigned long displayWidth; + unsigned long displayHeight; + + psi_timeval time; + psi_timezone tz; + + psi_timeval mainBatteryInsertionTime; + unsigned long mainBatteryStatus; + psi_timeval mainBatteryUsedTime; + unsigned long mainBatteryCurrent; + unsigned long mainBatteryUsedPower; + unsigned long mainBatteryVoltage; + unsigned long mainBatteryMaxVoltage; + + unsigned long backupBatteryStatus; + unsigned long backupBatteryVoltage; + unsigned long backupBatteryMaxVoltage; + psi_timeval backupBatteryUsedTime; + + bool externalPower; +} machineInfo; + +/** + * Remote procedure call services via PLP + * + * rpcs provides an interface for communicating + * with the Psion's remote procedure call + * service. The generic facilities for both, + * EPOC and SIBO are implemented here, while + * the facilities, unique to each of those + * variants are implemented in + * @ref rpcs32 or @ref rpcs16 respectively. + * These normally are instantiated by using + * @ref rpcsfactory. + */ class rpcs { public: + /** + * Provides a virtual destructor. + */ virtual ~rpcs() {}; + + /** + * Initializes a connection to the remote + * machine. + */ void reset(); + + /** + * Attempts to re-establish a remote + * connection by first closing the socket, + * then connecting again to the ncpd daemon + * and finally calling @ref reset. + */ void reconnect(); + + /** + * Retrieves the current status of the + * connection. + * + * @returns The connection status. + */ long getStatus(); - // API idendical on SIBO and EPOC - int getNCPversion(int &, int &); - int execProgram(const char *, const char *); + /** + * Retrieves the version of the NCP protocol + * on the remote side. + * + * This function is working with both SIBO and EPOC + * devices. + * + * @param major The major part of the NCP version. + * Valid only if returned with no error. + * @param minor The minor part of the NCP version. + * Valid only if returned with no error. + * + * @returns A psion error code. 0 = Ok. + */ + int getNCPversion(int &major, int &minor); + + /** + * Starts execution of a program on the remote machine. + * + * This function is working with both SIBO and EPOC + * devices. + * + * @param program The full path of the executable + * on the remote machine + * @param args The arguments for this program, separated + * by space. + * + * @returns A psion error code. 0 = Ok. + */ + int execProgram(const char *program, const char *args); + + /** + * Requests termination of a program running on the + * remote machine. + * + * This function is working with both SIBO and EPOC + * devices. + * + * @param program + * + * @returns A psion error code. 0 = Ok. + */ int stopProgram(const char *); int queryProgram(const char *); int formatOpen(const char *, int &, int &); int formatRead(int); int getUniqueID(const char *, long &); + + /** + * Retrieve owner information of the remote machine. + * + * This function is working with both SIBO and EPOC + * devices. + * + * @param owner A bufferArray, containing the lines + * of the owner info upon return. + * + * @returns A psion error code. 0 = Ok. + */ int getOwnerInfo(bufferArray &); - int getMachineType(int &); - int fuser(const char *, char *, int); + + /** + * Retrieves the type of machine on the remote side + * as defined in @ref #machs. + * + * This function is working with both SIBO and EPOC + * devices + * + * @param type The code describing the type of machine + * on the remote side is stored here on return. + * + * @returns A psion error code. 0 = Ok. + */ + int getMachineType(int &type); + + /** + * Retrieves the name of a process, having a + * given file opened on the remote side. + * + * This function is working with both SIBO and EPOC + * devices + * + * @param name The full path of a file to be checked + * for beeing used by a program. + * @param buf A buffer which gets filled with the + * program's name. + * @param maxlen The maximum capacity of the buffer. + */ + int fuser(const char *name, char *buf, int maxlen); + + /** + * Requests the remote server to terminate. + * + * This function is working with both SIBO and EPOC + * devices. There is usually no need to call this + * function, because the remote server is automatically + * stopped on disconnect. + * + * @returns A psion error code. 0 = Ok. + */ int quitServer(void); + /** + * Maps a language code to a human readable language name. + * + * @param code The language code to map. + * + * @returns The name of the language, represented by code, or + * "Unknown", if the code does not match one of the known + * languages. + */ + const char *languageString(const int code); + + /** + * Maps a battery status code to a human readable description. + * + * @param code The battary status code to map. + * + * @returns A descriptive text for the battery status, or + * "Unknown", if the code does not match a known + * battery status. + */ + const char *batteryStatusString(const int code); + + // API different on SIBO and EPOC virtual int queryDrive(const char, bufferArray &) = 0; - virtual int getCmdLine(const char *, char *, int) = 0; + /** + * Retrieves the command line of a running process. + * + * This function works with EPOC only. Using it with SIBO + * machines, returns always an error code E_PSI_NOT_SIBO. + * + * @param process Name of process. Format: processname.$pid + * @param ret The program name and arguments are returned here. + * + * @return Psion error code. 0 = Ok. + */ + virtual int getCmdLine(const char *process, bufferStore &ret) = 0; // API only existent on EPOC // default-methods for SIBO here. - virtual int getMachineInfo(void) { return E_PSI_NOT_SIBO;} + /** + * Retrieve general Information about the connected + * machine. + * + * This function works with EPOC only. Using it with SIBO + * machines, returns always an error code E_PSI_NOT_SIBO. + * + * @param machineInfo The struct holding all information on return. + * @return Psion error code. 0 = Ok. + */ + virtual int getMachineInfo(machineInfo &) { return E_PSI_NOT_SIBO;} virtual int closeHandle(int) { return E_PSI_NOT_SIBO;} virtual int regOpenIter(void) { return E_PSI_NOT_SIBO;} virtual int regReadIter(void) { return E_PSI_NOT_SIBO;} @@ -46,13 +261,16 @@ class rpcs { virtual int queryRead(void) { return E_PSI_NOT_SIBO;} enum errs { - E_PSI_GEN_NONE = 0, + E_PSI_GEN_NONE = 0, E_PSI_GEN_FAIL = -1, - E_PSI_FILE_DISC = -50, + E_PSI_FILE_DISC = -50, // Special error code for "Operation not permitted in RPCS16" - E_PSI_NOT_SIBO = -200 + E_PSI_NOT_SIBO = -200 }; + /** + * The known machine types. + */ enum machs { PSI_MACH_UNKNOWN = 0, PSI_MACH_PC = 1, @@ -65,15 +283,44 @@ class rpcs { PSI_MACH_S3C = 8, PSI_MACH_S5 = 32, PSI_MACH_WINC = 33, -//TODO: Code for 5mx + // TODO: Code for 5mx }; - protected: + /** + * The known interface languages. + */ + enum languagecodes { + PSI_LANG_TEST = 0, + PSI_LANG_ENGLISH = 1, + PSI_LANG_FRENCH = 2, + PSI_LANG_GERMAN = 3, + }; + + /** + * The known battery states. + */ + enum batterystates { + PSI_BATT_DEAD = 0, + PSI_BATT_VERYLOW = 1, + PSI_BATT_LOW = 2, + PSI_BATT_GOOD = 3, + }; - // Vars + protected: + /** + * The socket, used for communication + * with ncpd. + */ ppsocket *skt; + + /** + * The current status of the connection. + */ long status; + /** + * The possible commands. + */ enum commands { QUERY_NCP = 0x00, EXEC_PROG = 0x01, @@ -87,17 +334,38 @@ class rpcs { GET_MACHINETYPE = 0x09, GET_CMDLINE = 0x0a, FUSER = 0x0b, - CONFIG_OPEN = 0x66, + GET_MACHINE_INFO = 0x64, + REG_OPEN_ITER = 0x66, + REG_READ_ITER = 0x67, + REG_WRITE = 0x68, + REG_READ = 0x69, + REG_DELETE = 0x6a, + SET_TIME = 0x6b, + CONFIG_OPEN = 0x6c, CONFIG_READ = 0x6d, + CONFIG_WRITE = 0x6e, + QUERY_OPEN = 0x6f, + QUERY_READ = 0x70, QUIT_SERVER = 0xff }; - // Communication - bool sendCommand(enum commands, bufferStore &); - long getResponse(bufferStore &); + /** + * Sends a command to the remote side. + * + * If communication fails, a reconnect is triggered + * and a second attempt to transmit the request + * is attempted. If that second attempt fails, + * the function returns an error an sets rpcs::status + * to E_PSI_FILE_DISC. + * + * @param cc The command to execute on the remote side. + * @param data Additional data for this command. + * + * @returns true on success, false on failure. + */ + bool sendCommand(enum commands cc, bufferStore &data); + int getResponse(bufferStore &); const char *getConnectName(); - - char *convertSlash(const char *); }; #endif diff --git a/lib/rpcs16.cc b/lib/rpcs16.cc index 2786ee8..a3af320 100644 --- a/lib/rpcs16.cc +++ b/lib/rpcs16.cc @@ -57,7 +57,7 @@ cout << dec << "qd: " << res << " " << a.getLen() << " a="<< a << endl; } int rpcs16:: -getCmdLine(const char *process, char *buf, int bufsize) +getCmdLine(const char *process, bufferStore &ret) { return 0; } diff --git a/lib/rpcs16.h b/lib/rpcs16.h index 14809ae..c803fff 100644 --- a/lib/rpcs16.h +++ b/lib/rpcs16.h @@ -12,7 +12,7 @@ class rpcs16 : public rpcs { ~rpcs16(); int queryDrive(const char, bufferArray &); - int getCmdLine(const char *, char *, int); + int getCmdLine(const char *, bufferStore &); }; #endif diff --git a/lib/rpcs32.cc b/lib/rpcs32.cc index d710b9c..74d5ca4 100644 --- a/lib/rpcs32.cc +++ b/lib/rpcs32.cc @@ -48,14 +48,16 @@ int rpcs32:: queryDrive(char drive, bufferArray &ret) { bufferStore a; + int res; + a.addByte(drive); if (!sendCommand(rpcs::QUERY_DRIVE, a)) return rpcs::E_PSI_FILE_DISC; - getResponse(a); + if ((res = getResponse(a))) + return res; int l = a.getLen(); ret.clear(); -//cout << dec << "qd: " << a.getLen() << " a="<< a << endl; - while (l > 1) { + while (l > 0) { bufferStore b, c; const char *s; char *p; @@ -66,8 +68,7 @@ queryDrive(char drive, bufferArray &ret) sl = strlen(s) + 1; l -= sl; a.discardFirstBytes(sl); - p = strstr(s, ".$"); - if (p) { + if ((p = strstr(s, ".$"))) { *p = '\0'; p += 2; sscanf(p, "%d", &pid); } else @@ -82,33 +83,125 @@ queryDrive(char drive, bufferArray &ret) ret.push(c); ret.push(b); } - return 0; + return res; } int rpcs32:: -getCmdLine(const char *process, char *buf, int bufsize) +getCmdLine(const char *process, bufferStore &ret) { - return 0; + bufferStore a; + int res; + + a.addStringT(process); + if (!sendCommand(rpcs::GET_CMDLINE, a)) + return rpcs::E_PSI_FILE_DISC; + res = getResponse(a); + ret = a; + return res; } +int rpcs32:: +getMachineInfo(machineInfo &mi) +{ + bufferStore a; + int res; + + if (!sendCommand(rpcs::GET_MACHINE_INFO, a)) + return rpcs::E_PSI_FILE_DISC; + if ((res = getResponse(a))) + return res; + if (a.getLen() != 256) + return E_PSI_GEN_FAIL; + mi.machineType = a.getDWord(0); + strncpy(mi.machineName, a.getString(16), 16); + mi.machineName[16] = '\0'; + mi.machineUID = a.getDWord(44); + mi.machineUID <<= 32; + mi.machineUID |= a.getDWord(40); + mi.countryCode = a.getDWord(56); + strcpy(mi.uiLanguage, languageString(a.getDWord(164))); + + mi.romMajor = a.getByte(4); + mi.romMinor = a.getByte(5); + mi.romBuild = a.getWord(6); + mi.romSize = a.getDWord(140); + + mi.ramSize = a.getDWord(136); + mi.ramMaxFree = a.getDWord(144); + mi.ramFree = a.getDWord(148); + mi.ramDiskSize = a.getDWord(152); + + mi.registrySize = a.getDWord(156); + mi.romProgrammable = (a.getDWord(160) != 0); + + mi.displayWidth = a.getDWord(32); + mi.displayHeight = a.getDWord(36); + + mi.time.tv_low = a.getDWord(48); + mi.time.tv_high = a.getDWord(52); + + mi.tz.utc_offset = a.getDWord(60); + mi.tz.dst_zones = a.getDWord(64); + mi.tz.home_zone = a.getDWord(68); + + mi.mainBatteryInsertionTime.tv_low = a.getDWord(72); + mi.mainBatteryInsertionTime.tv_high = a.getDWord(76); + mi.mainBatteryStatus = a.getDWord(80); + mi.mainBatteryUsedTime.tv_low = a.getDWord(84); + mi.mainBatteryUsedTime.tv_high = a.getDWord(88); + mi.mainBatteryCurrent = a.getDWord(92); + mi.mainBatteryUsedPower = a.getDWord(96); + mi.mainBatteryVoltage = a.getDWord(100); + mi.mainBatteryMaxVoltage = a.getDWord(104); + + mi.backupBatteryStatus = a.getDWord(108); + mi.backupBatteryVoltage = a.getDWord(112); + mi.backupBatteryMaxVoltage = a.getDWord(116); + mi.backupBatteryUsedTime.tv_low = a.getDWord(124); + mi.backupBatteryUsedTime.tv_high = a.getDWord(128); + + mi.externalPower = (a.getDWord(120) != 0); + + return res; +} + +static unsigned long hhh; + int rpcs32:: configOpen(void) { bufferStore a; -cout << "configOpen:" << endl; + int res; + if (!sendCommand(rpcs::CONFIG_OPEN, a)) return rpcs::E_PSI_FILE_DISC; - getResponse(a); -cout << a << endl; + res = getResponse(a); +cout << "co: r=" << res << " a=" << a << endl; + hhh = a.getDWord(0); + return 0; } int rpcs32:: configRead(void) { bufferStore a; -cout << "configRead:" << endl; - if (!sendCommand(rpcs::CONFIG_READ, a)) - return rpcs::E_PSI_FILE_DISC; - getResponse(a); -cout << a << endl; + int res; + int l; + FILE *f; + + f = fopen("blah", "w"); + do { + a.init(); + a.addDWord(hhh); + if (!sendCommand(rpcs::CONFIG_READ, a)) + return rpcs::E_PSI_FILE_DISC; + if ((res = getResponse(a))) + return res; + l = a.getLen(); + cout << "cr: " << l << endl; + fwrite(a.getString(0), 1, l, f); + } while (l > 0); + fclose(f); +//cout << "cr: r=" << res << " a=" << a << endl; + return 0; } diff --git a/lib/rpcs32.h b/lib/rpcs32.h index e33ef10..6c333b4 100644 --- a/lib/rpcs32.h +++ b/lib/rpcs32.h @@ -11,9 +11,11 @@ class rpcs32 : public rpcs { ~rpcs32(); int queryDrive(const char, bufferArray &); - int getCmdLine(const char *, char *, int); + int getCmdLine(const char *, bufferStore &); + int getMachineInfo(machineInfo &); + int configOpen(void); + int configRead(void); #if 0 - int getMachineInfo(void); int closeHandle(int); int regOpenIter(void); int regReadIter(void); @@ -21,10 +23,8 @@ class rpcs32 : public rpcs { int regRead(void); int regDelete(void); int setTime(void); -#endif int configOpen(void); int configRead(void); -#if 0 int configWrite(void); int queryOpen(void); int queryRead(void); diff --git a/lib/rpcsfactory.cc b/lib/rpcsfactory.cc index 7358e56..4fe0bff 100644 --- a/lib/rpcsfactory.cc +++ b/lib/rpcsfactory.cc @@ -34,7 +34,7 @@ #include "bufferstore.h" #include "ppsocket.h" -rpcsfactory::rpcsfactory(ppsocket *_skt) : serNum(0) +rpcsfactory::rpcsfactory(ppsocket *_skt) //: serNum(0) { skt = _skt; } @@ -52,9 +52,10 @@ rpcs * rpcsfactory::create(bool reconnect) a.addStringT("NCP$INFO"); if (!skt->sendBufferStore(a)) { if (!reconnect) - cerr << "rpcsfactory::create couldn't send version request" << endl; else { + cerr << "rpcsfactory::create couldn't send version request" << endl; + else { skt->closeSocket(); - serNum = 0; + // serNum = 0; skt->reconnect(); } return NULL; @@ -68,7 +69,7 @@ rpcs * rpcsfactory::create(bool reconnect) } if ((a.getLen() > 8) && !strncmp(a.getString(), "No Psion", 8)) { skt->closeSocket(); - serNum = 0; + // serNum = 0; skt->reconnect(); return NULL; } diff --git a/lib/rpcsfactory.h b/lib/rpcsfactory.h index 17a2719..feffaee 100644 --- a/lib/rpcsfactory.h +++ b/lib/rpcsfactory.h @@ -5,15 +5,37 @@ class ppsocket; +/** + * A factory for automatically instantiating the correct protocol + * variant depending on the connected Psion. + */ class rpcsfactory { public: + /** + * Constructs a rpcsfactory. + * + * @param skt The socket to be used for connecting + * to the ncpd daemon. + */ rpcsfactory(ppsocket * skt); - virtual rpcs * create(bool); + + /** + * Creates a new rpsc instance. + * + * @param reconnect Set to true, if automatic reconnect + * should be performed on failure. + * + * @returns A pointer to a newly created rpcs instance or + * NULL on failure. + */ + virtual rpcs * create(bool reconnect); private: - // Vars + /** + * The socket to be used for connecting to the + * ncpd daemon. + */ ppsocket *skt; - int serNum; }; #endif diff --git a/ncpd/link.cc b/ncpd/link.cc index c455324..d07b78b 100644 --- a/ncpd/link.cc +++ b/ncpd/link.cc @@ -90,7 +90,7 @@ send(const bufferStore & buff) if (buff.getLen() > 300) failed = true; else - sendQueue.pushBuffer(buff); + sendQueue += buff; } bufferArray link:: @@ -116,7 +116,7 @@ poll() // Send ack if (idLastGot != seq) { idLastGot = seq; - ret.pushBuffer(buff); + ret += buff; } else { if (verbose & LNK_DEBUG_LOG) cout << "link: DUP\n"; @@ -177,7 +177,7 @@ poll() } else { if (!sendQueue.empty()) { somethingToSend = true; - toSend = sendQueue.popBuffer(); + toSend = sendQueue.pop(); idSent++; if (idSent > 7) idSent = 0; diff --git a/ncpd/linkchan.cc b/ncpd/linkchan.cc index 4a2a4d4..f8e586f 100644 --- a/ncpd/linkchan.cc +++ b/ncpd/linkchan.cc @@ -60,7 +60,7 @@ ncpDataCallback(bufferStore & a) << srvName << "\"" << endl; while (!registerStack.empty()) { - se = registerStack.popBuffer(); + se = registerStack.pop(); if (se.getWord(0) == ser) { if (verbose & LINKCHAN_DEBUG_LOG) cout << "linkchan: found ser=0x" << hex << setw(4) << @@ -68,7 +68,7 @@ ncpDataCallback(bufferStore & a) " on stack -> callBack to waiting chan" << endl; ncpDoRegisterAck((int)se.getWord(2)); } else - newStack.pushBuffer(se); + newStack += se; } registerStack = newStack; return; @@ -111,7 +111,7 @@ Register(channel *ch) stack.addWord(registerSer); stack.addWord(ch->getNcpChannel()); - registerStack.pushBuffer(stack); + registerStack += stack; a.addByte(0); a.addWord(registerSer++); a.addString(ch->getNcpConnectName()); diff --git a/ncpd/main.cc b/ncpd/main.cc index 3a0ddb6..2c0fd3d 100644 --- a/ncpd/main.cc +++ b/ncpd/main.cc @@ -79,7 +79,7 @@ pollSocketConnections(int &numScp, socketChan ** scp) void usage() { - cerr << "Usage : ncpd [-V] [-v logclass] [-d] [-p ] [-s ] [-b ]\n"; + cerr << "Usage : ncpd [-V] [-v logclass] [-d] [-e] [-p ] [-s ] [-b ]\n"; exit(1); } @@ -90,6 +90,7 @@ main(int argc, char **argv) IOWatch iow; int pid; bool dofork = true; + bool autoexit = false; // Command line parameter processing int sockNum = DPORT; @@ -120,7 +121,7 @@ main(int argc, char **argv) if (!strcmp(argv[i], "pd")) pverbose |= PKT_DEBUG_DUMP; if (!strcmp(argv[i], "ph")) - lverbose |= PKT_DEBUG_HANDSHAKE; + pverbose |= PKT_DEBUG_HANDSHAKE; if (!strcmp(argv[i], "m")) verbose = true; if (!strcmp(argv[i], "all")) { @@ -133,6 +134,8 @@ main(int argc, char **argv) baudRate = atoi(argv[++i]); } else if (!strcmp(argv[i], "-d")) { dofork = 0; + } else if (!strcmp(argv[i], "-e")) { + autoexit = true; } else if (!strcmp(argv[i], "-V")) { cout << "ncpd version " << VERSION << endl; exit(0); @@ -180,6 +183,9 @@ main(int argc, char **argv) iow.watch(1, 0); if (a->hasFailed()) { + if (autoexit) + break; + iow.watch(5, 0); if (verbose) cout << "ncp: restarting\n"; diff --git a/ncpd/mp_serial.c b/ncpd/mp_serial.c index b153e77..05a014c 100644 --- a/ncpd/mp_serial.c +++ b/ncpd/mp_serial.c @@ -153,7 +153,7 @@ init_serial(const char *dev, int speed, int debug) #endif #if defined(sun) || defined(linux) || defined(__sgi) || defined(__NetBSD__) ti.c_cflag = CS8 | HUPCL | clocal | CRTSCTS | CREAD; - ti.c_iflag = IGNBRK | IGNPAR; + ti.c_iflag = IGNBRK | IGNPAR | IXON | IXOFF; ti.c_cc[VMIN] = 1; ti.c_cc[VTIME] = 0; #endif diff --git a/ncpd/ncp.cc b/ncpd/ncp.cc index e1bf96a..1a5c317 100644 --- a/ncpd/ncp.cc +++ b/ncpd/ncp.cc @@ -113,7 +113,7 @@ poll() bufferArray res(l->poll()); if (!res.empty()) { do { - bufferStore s = res.popBuffer(); + bufferStore s = res.pop(); if (s.getLen() > 1) { int channel = s.getByte(0); s.discardFirstBytes(1); diff --git a/ncpd/packet.cc b/ncpd/packet.cc index 26823c8..53774d6 100644 --- a/ncpd/packet.cc +++ b/ncpd/packet.cc @@ -54,6 +54,7 @@ iow(_iow) inPtr = inBuffer = new unsigned char[BUFFERLEN + 1]; outPtr = outBuffer = new unsigned char[BUFFERLEN + 1]; inLen = outLen = termLen = 0; + foundSync = 0; esc = false; crcIn = crcOut = 0; @@ -87,7 +88,7 @@ void packet:: send(unsigned char type, const bufferStore & b) { if (verbose & PKT_DEBUG_LOG) { - cout << "packet: >> "; + cout << "packet: type " << hex << (int) type << " >> "; if (verbose & PKT_DEBUG_DUMP) cout << b << endl; else @@ -185,7 +186,7 @@ get(unsigned char &type, bufferStore & ret) if (verbose & PKT_DEBUG_LOG) { cout << "packet: get "; if (verbose & PKT_DEBUG_DUMP) { - for (int i = 0; i < termLen; i++) + for (int i = foundSync - 3; i < termLen; i++) cout << hex << setw(2) << setfill('0') << (int) inBuffer[i] << " "; } else cout << "len=" << dec << termLen; @@ -193,6 +194,7 @@ get(unsigned char &type, bufferStore & ret) } inLen -= termLen; termLen = 0; + foundSync = 0; bool crcOk = (endPtr[0] == ((crcIn >> 8) & 0xff) && endPtr[1] == (crcIn & 0xff)); if (inLen > 0) memmove(inBuffer, &endPtr[2], inLen); @@ -218,15 +220,29 @@ terminated() if (inLen < 6) return false; p = inBuffer + termLen; - if (termLen == 0) { + if (!foundSync) { + while (!foundSync && (inLen - termLen >= 6)) + { + termLen++; if (*p++ != 0x16) - return false; + continue; + termLen++; if (*p++ != 0x10) - return false; + continue; + termLen++; if (*p++ != 0x02) + continue; + foundSync = termLen; + } + if (!foundSync) return false; + + if (verbose & PKT_DEBUG_LOG) { + if (foundSync != 3) + cout << "packet: terminated found sync at " << foundSync << endl; + } esc = false; - termLen = 3; + // termLen = 3; crcIn = 0; rcv.init(); } diff --git a/ncpd/packet.h b/ncpd/packet.h index 26d4282..5c4bb4f 100644 --- a/ncpd/packet.h +++ b/ncpd/packet.h @@ -63,6 +63,7 @@ class packet { int inLen; int outLen; int termLen; + int foundSync; int fd; short int verbose; bool esc; diff --git a/patches/README b/patches/README new file mode 100644 index 0000000..11b7c95 --- /dev/null +++ b/patches/README @@ -0,0 +1,16 @@ +The following patches may be applied to other programs to allow them to operate +better with plptools. + +mgetty-1.1.21-plp.diff is from Christof Meerwald, and adds autodetection +support for the PLP-protocol to mgetty - thus mgetty can autodetect a +Psion connected to the serial port and execute ncpd (with the autoexit +option). Having mgetty watch the serial port makes it a lot more easy to +switch between a PLP (file transfer) and a PPP (TCP/IP) connection. Christof +used the following login.conf for mgetty: + +/AutoPPP/ - - /usr/sbin/pppd +/PLP/ - - /usr/sbin/ncpd -d -e +* - - /bin/login @ + + +-- MJG diff --git a/patches/mgetty-1.1.21-plp.diff b/patches/mgetty-1.1.21-plp.diff new file mode 100644 index 0000000..943a173 --- /dev/null +++ b/patches/mgetty-1.1.21-plp.diff @@ -0,0 +1,40 @@ +diff -ur mgetty-1.1.21/logname.c mgetty-1.1.21.new/logname.c +--- mgetty-1.1.21/logname.c Tue Sep 1 11:56:19 1998 ++++ mgetty-1.1.21.new/logname.c Sat Jan 1 17:12:11 2000 +@@ -270,6 +270,9 @@ + static int ppp_level = 0, ppp_escaped = 0; + char ppp_ch; + #endif ++#if 1 ++ static int plp_level = 0; ++#endif + + /* read character by character! */ + tio_save = *tio; +@@ -413,6 +416,26 @@ + ppp_level = 0; + ppp_escaped = 0; + } ++#endif ++#if 1 ++ if (ch == '\026') ++ { ++ plp_level = 1; ++ } ++ else if ((ch == '\020') && (plp_level == 1)) ++ { ++ plp_level = 2; ++ } ++ else if ((ch == '\002') && (plp_level == 2)) ++ { ++ strcpy (buf, "/PLP/"); ++ i=5; ++ ch = '\r'; ++ } ++ else ++ { ++ plp_level = 0; ++ } + #endif + + #ifdef JANUS diff --git a/plpftp/ftp.cc b/plpftp/ftp.cc index 45ec2eb..b46e24a 100644 --- a/plpftp/ftp.cc +++ b/plpftp/ftp.cc @@ -25,9 +25,11 @@ #include #include #include +#include #include #include #include +#include #include #include #include @@ -43,7 +45,6 @@ #if HAVE_LIBREADLINE extern "C" { -#include #include #if HAVE_LIBHISTORY #include @@ -53,7 +54,6 @@ extern "C" { static char psionDir[1024]; static rfsv *comp_a; -static rpcs *comp_r; static int continueRunning; @@ -184,6 +184,8 @@ sigint_handler2(int i) { signal(SIGINT, sigint_handler2); } +const char *datefmt = "%c"; + int ftp:: session(rfsv & a, rpcs & r, int xargc, char **xargv) { @@ -205,7 +207,7 @@ session(rfsv & a, rpcs & r, int xargc, char **xargv) } if (!once) { bufferArray b; - if (!r.getOwnerInfo(b)) { + if (!(res = r.getOwnerInfo(b))) { int machType; r.getMachineType(machType); cout << "Connected to "; @@ -251,7 +253,8 @@ session(rfsv & a, rpcs & r, int xargc, char **xargv) while (!b.empty()) cout << " " << b.pop().getString() << endl; cout << endl; - } + } else + cerr << "OwnerInfo returned error " << res << endl; } if (!strcmp(DDRIVE, "AUTO")) { @@ -334,9 +337,7 @@ session(rfsv & a, rpcs & r, int xargc, char **xargv) else { // never used to do this char dateBuff[100]; - struct tm *t; - t = localtime(&time); - strftime(dateBuff, 100, "%c", t); + strftime(dateBuff, sizeof(dateBuff), datefmt, localtime(&time)); cout << a.opAttr(attr); cout << " " << dec << setw(10) << setfill(' ') << size; cout << " " << dateBuff; @@ -364,9 +365,7 @@ session(rfsv & a, rpcs & r, int xargc, char **xargv) errprint(res, a); else { char dateBuff[100]; - struct tm *t; - t = localtime(&mtime); - strftime(dateBuff, 100, "%c %Z", t); + strftime(dateBuff, sizeof(dateBuff), datefmt, localtime(&mtime)); cout << dateBuff << endl; } continue; @@ -456,9 +455,7 @@ session(rfsv & a, rpcs & r, int xargc, char **xargv) long size = s.getDWord(4); long attr = s.getDWord(8); char dateBuff[100]; - struct tm *t; - t = localtime(&date); - strftime(dateBuff, 100, "%c", t); + strftime(dateBuff, sizeof(dateBuff), datefmt, localtime(&date)); cout << a.opAttr(attr); cout << " " << dec << setw(10) << setfill(' ') << size; cout << " " << dateBuff; @@ -748,10 +745,14 @@ session(rfsv & a, rpcs & r, int xargc, char **xargv) continue; } // RPCS commands - // if (!strcmp(argv[0], "xxx")) { - // r.configOpen(); - // continue; - // } + if (!strcmp(argv[0], "x")) { + r.configOpen(); + continue; + } + if (!strcmp(argv[0], "y")) { + r.configRead(); + continue; + } if (!strcmp(argv[0], "run") && (argc >= 2)) { char argbuf[1024]; char cmdbuf[1024]; @@ -772,6 +773,99 @@ session(rfsv & a, rpcs & r, int xargc, char **xargv) r.execProgram(cmdbuf, argbuf); continue; } + if (!strcmp(argv[0], "machinfo")) { + machineInfo mi; + if ((res = r.getMachineInfo(mi))) { + errprint(res, a); + continue; + } + + cout << "General:" << endl; + cout << " Machine Type: " << mi.machineType << endl; + cout << " Machine Name: " << mi.machineName << endl; + cout << " Machine UID: " << hex << mi.machineUID << dec << endl; + cout << " UI Language: " << mi.uiLanguage << endl; + cout << "ROM:" << endl; + cout << " Version: " << mi.romMajor << "." << setw(2) << setfill('0') << + mi.romMinor << "(" << mi.romBuild << ")" << endl; + cout << " Size: " << mi.romSize / 1024 << "k" << endl; + cout << " Programmable: " << + (mi.romProgrammable ? "yes" : "no") << endl; + cout << "RAM:" << endl; + cout << " Size: " << mi.ramSize / 1024 << "k" << endl; + cout << " Free: " << mi.ramFree / 1024 << "k" << endl; + cout << " Free max: " << mi.ramMaxFree / 1024 << "k" << endl; + cout << "RAM disk size: " << mi.ramDiskSize / 1024 << "k" << endl; + cout << "Registry size: " << mi.registrySize << endl; + cout << "Display size: " << mi.displayWidth << "x" << + mi.displayHeight << endl; + cout << "Time:" << endl; + PsiTime pt(&mi.time, &mi.tz); + cout << " Current time: " << pt << endl; + cout << " UTC offset: " << mi.tz.utc_offset << " seconds" << endl; + cout << " DST: " << + (mi.tz.dst_zones & PsiTime::PSI_TZ_HOME ? "yes" : "no") << endl; + cout << " Timezone: " << mi.tz.home_zone << endl; + cout << " Country Code: " << mi.countryCode << endl; + cout << "Main battery:" << endl; + pt.setPsiTime(&mi.mainBatteryInsertionTime); + cout << " Changed at: " << pt << endl; + cout << " Used for: " << mi.mainBatteryUsedTime << endl; + cout << " Status: " << + r.batteryStatusString(mi.mainBatteryStatus) << endl; + cout << " Current: " << mi.mainBatteryCurrent << " mA" << endl; + cout << " UsedPower: " << mi.mainBatteryUsedPower << " mAs" << endl; + cout << " Voltage: " << mi.mainBatteryVoltage << " mV" << endl; + cout << " Max. voltage: " << mi.mainBatteryMaxVoltage << " mV" << endl; + cout << "Backup battery:" << endl; + cout << " Status: " << + r.batteryStatusString(mi.backupBatteryStatus) << endl; + cout << " Voltage: " << mi.backupBatteryVoltage << " mV" << endl; + cout << " Max. voltage: " << mi.backupBatteryMaxVoltage << " mV" << endl; + cout << " Used for: " << mi.backupBatteryUsedTime << endl; + continue; + } + if (!strcmp(argv[0], "runrestore") && (argc == 2)) { + ifstream ip(argv[1]); + if (!ip) { + cerr << "Could not read processlist " << argv[1] << endl; + continue; + } + while (!ip.eof()) { + char cmd[256]; + char arg[256]; + ip >> cmd >> arg; + if ((res = r.execProgram(cmd, arg))) { + cerr << "Could not start " << cmd << " " << arg << endl; + errprint(res, a); + } + } + ip.close(); + continue; + } + if (!strcmp(argv[0], "killsave") && (argc == 2)) { + bufferArray tmp; + ofstream op(argv[1]); + if (!op) { + cerr << "Could not write processlist " << argv[1] << endl; + continue; + } + r.queryDrive('C', tmp); + while (!tmp.empty()) { + char pbuf[128]; + bufferStore cmdargs; + bufferStore bs = tmp.pop(); + int pid = bs.getWord(0); + const char *proc = bs.getString(2); + sprintf(pbuf, "%s.$%d", proc, pid); + bs = tmp.pop(); + if (r.getCmdLine(pbuf, cmdargs) == 0) + op << cmdargs.getString(0) << " " << bs.getString(0) << endl; + r.stopProgram(pbuf); + } + op.close(); + continue; + } if (!strcmp(argv[0], "kill") && (argc >= 2)) { bufferArray tmp, tmp2; bool anykilled = false; @@ -834,7 +928,8 @@ errprint(long errcode, rfsv & a) { static char *all_commands[] = { "pwd", "ren", "touch", "gtime", "test", "gattr", "sattr", "devs", "dir", "ls", "dircnt", "cd", "lcd", "get", "put", "mget", "mput", - "del", "rm", "mkdir", "rmdir", "prompt", "bye", "ps", "kill", "run", NULL + "del", "rm", "mkdir", "rmdir", "prompt", "bye", + "ps", "kill", "killsave", "runrestore", "run", "machinfo", NULL }; static char *localfile_commands[] = { diff --git a/plpnfsd/main.cc b/plpnfsd/main.cc index e322685..6bf0f01 100644 --- a/plpnfsd/main.cc +++ b/plpnfsd/main.cc @@ -46,14 +46,14 @@ long rfsv_dir(const char *file, dentry **e) { ret = a->dir(&(*file), &entries); while (!entries.empty()) { bufferStore s; - s = entries.popBuffer(); + s = entries.pop(); 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)->attr = a->attr2std(s.getDWord(8)); (*e)->name = strdup(s.getString(12)); (*e)->next = tmp; } @@ -138,7 +138,6 @@ static long rfsv_opencached(const char *name, long mode) { } long rfsv_read(char *buf, long offset, long len, char *name) { - // FIXME: this might break on RFSV16? long ret = 0; if (!a) @@ -161,7 +160,6 @@ long rfsv_read(char *buf, long offset, long len, char *name) { } long rfsv_write(char *buf, long offset, long len, char *name) { - // FIXME: this might break on RFSV16? long ret = 0; if (!a) @@ -196,7 +194,6 @@ long rfsv_setmtime(const char *name, long time) { long rfsv_setsize(const char *name, long size) { long ph; long ret; - // FIXME: this might break on RFSV16? if (!a) return -1; @@ -215,14 +212,19 @@ long rfsv_setattr(const char *name, long sattr, long dattr) { return -1; if (a_filename && !strcmp(name, a_filename)) rfsv_closecached(); - long ret = a->fsetattr(name, dattr, sattr); - return ret; + dattr = a->std2attr(dattr); + sattr = a->std2attr(sattr); + return a->fsetattr(name, dattr, sattr); } long rfsv_getattr(const char *name, long *attr, long *size, long *time) { + long res, psiattr; + if (!a) return -1; - return a->fgeteattr(&(*name), &(*attr), &(*size), &(*time)); + res = a->fgeteattr(&(*name), &psiattr, &(*size), &(*time)); + *attr = a->attr2std(psiattr); + return res; } long rfsv_statdev(char letter) { diff --git a/plpnfsd/mp_mount.c b/plpnfsd/mp_mount.c index f0a82d4..0f9e1e9 100644 --- a/plpnfsd/mp_mount.c +++ b/plpnfsd/mp_mount.c @@ -66,7 +66,7 @@ static char nfshost[128]; #ifndef __GLIBC__ #include /* struct nfs_mount_data */ #endif -#include /* struct nfs_mount_data */ +#include "linux-misc.h" /* struct nfs_mount_data */ #include /* inet_addr() */ #endif #ifdef _IBMR2 @@ -75,7 +75,6 @@ static char nfshost[128]; #include #endif - #ifndef DONT_UPDATE_MTAB #if defined(sun) && defined(__SVR4) #include diff --git a/plpnfsd/mp_pfs_ops.c b/plpnfsd/mp_pfs_ops.c index 669d435..71ed2e9 100644 --- a/plpnfsd/mp_pfs_ops.c +++ b/plpnfsd/mp_pfs_ops.c @@ -106,29 +106,35 @@ attr2pattr(long oattr, long nattr, long *psisattr, long *psidattr) * work properly */ *psisattr = *psidattr = 0; + if ((oattr & 0400) != (nattr & 0400)) { + if (nattr & 0400) /* readable */ + *psidattr |= PSI_A_READ; + else + *psisattr |= PSI_A_READ; + } if ((oattr & 0200) != (nattr & 0200)) { if (nattr & 0200) /* readonly */ - *psidattr |= 0x01; + *psidattr |= PSI_A_RDONLY; else - *psisattr |= 0x01; + *psisattr |= PSI_A_RDONLY; } if ((oattr & 0020) != (nattr & 0020)) { if (nattr & 0020) /* group-write -> archive */ - *psisattr |= 0x20; + *psisattr |= PSI_A_ARCHIVE; else - *psidattr |= 0x20; + *psidattr |= PSI_A_ARCHIVE; } if ((oattr & 0004) != (nattr & 0004)) { if (nattr & 0004) /* Not world-read -> hidden */ - *psidattr |= 0x02; + *psidattr |= PSI_A_HIDDEN; else - *psisattr |= 0x02; + *psisattr |= PSI_A_HIDDEN; } if ((oattr & 0002) != (nattr & 0002)) { if (nattr & 0002) /* world-write -> system */ - *psisattr |= 0x04; + *psisattr |= PSI_A_SYSTEM; else - *psidattr |= 0x04; + *psidattr |= PSI_A_SYSTEM; } } @@ -137,7 +143,7 @@ dpattr2attr(long psiattr, long size, long ftime, fattr *fp, int inode) { bzero((char *) fp, sizeof(*fp)); - if (psiattr & 0x10) { + if (psiattr & PSI_A_DIR) { fp->type = NFDIR; fp->mode = NFSMODE_DIR | 0700; /* @@ -159,17 +165,18 @@ dpattr2attr(long psiattr, long size, long ftime, fattr *fp, int inode) * Following flags have to be set in order to let backups * work properly */ + if (psiattr & PSI_A_READ) fp->mode |= 0400; /* File readable (?) */ - if (!(psiattr & 0x01)) + if (!(psiattr & PSI_A_RDONLY)) fp->mode |= 0200; /* File writeable */ /* fp->mode |= 0100; File executable */ - if (!(psiattr & 0x02)) + if (!(psiattr & PSI_A_HIDDEN)) fp->mode |= 0004; /* Not Hidden <-> world read */ - if (psiattr & 0x04) + if (psiattr & PSI_A_SYSTEM) fp->mode |= 0002; /* System <-> world write */ - if (psiattr & 0x40) + if (psiattr & PSI_A_VOLUME) fp->mode |= 0001; /* Volume <-> world exec */ - if (psiattr & 0x20) + if (psiattr & PSI_A_ARCHIVE) fp->mode |= 0020; /* Modified <-> group write */ /* fp->mode |= 0040; Byte <-> group read */ /* fp->mode |= 0010; Text <-> group exec */ @@ -189,7 +196,7 @@ pattr2attr(long psiattr, long size, long ftime, fattr *fp, unsigned char *fh) { bzero((char *) fp, sizeof(*fp)); - if (psiattr & 0x10) { + if (psiattr & PSI_A_DIR) { fp->type = NFDIR; fp->mode = NFSMODE_DIR | 0700; /* @@ -211,17 +218,18 @@ pattr2attr(long psiattr, long size, long ftime, fattr *fp, unsigned char *fh) * Following flags have to be set in order to let backups * work properly */ + if (psiattr & PSI_A_READ) fp->mode |= 0400; /* File readable (?) */ - if (!(psiattr & 0x01)) + if (!(psiattr & PSI_A_RDONLY)) fp->mode |= 0200; /* File writeable */ /* fp->mode |= 0100; File executable */ - if (!(psiattr & 0x02)) + if (!(psiattr & PSI_A_HIDDEN)) fp->mode |= 0004; /* Not Hidden <-> world read */ - if (psiattr & 0x04) + if (psiattr & PSI_A_SYSTEM) fp->mode |= 0002; /* System <-> world write */ - if (psiattr & 0x40) + if (psiattr & PSI_A_VOLUME) fp->mode |= 0001; /* Volume <-> world exec */ - if (psiattr & 0x20) + if (psiattr & PSI_A_ARCHIVE) fp->mode |= 0020; /* Modified <-> group write */ /* fp->mode |= 0040; Byte <-> group read */ /* fp->mode |= 0010; Text <-> group exec */ diff --git a/plpnfsd/rfsv_api.h b/plpnfsd/rfsv_api.h index d4a996b..14c26d5 100644 --- a/plpnfsd/rfsv_api.h +++ b/plpnfsd/rfsv_api.h @@ -29,4 +29,19 @@ extern long rfsv_statdev(char letter); extern long rfsv_isalive(); extern long rfsv_closecached(void); +/* File attributes, C-style */ +#define PSI_A_RDONLY 0x0001 +#define PSI_A_HIDDEN 0x0002 +#define PSI_A_SYSTEM 0x0004 +#define PSI_A_DIR 0x0008 +#define PSI_A_ARCHIVE 0x0010 +#define PSI_A_VOLUME 0x0020 +#define PSI_A_NORMAL 0x0040 +#define PSI_A_TEMP 0x0080 +#define PSI_A_COMPRESSED 0x0100 +#define PSI_A_READ 0x0200 +#define PSI_A_EXEC 0x0400 +#define PSI_A_STREAM 0x0800 +#define PSI_A_TEXT 0x1000 + #endif -- cgit v1.2.3