home *** CD-ROM | disk | FTP | other *** search
- /* Various utility functions
-
- ©1998, 1999 Joseph Walton
-
- This software is distributed under the terms of the GNU General Public
- License; either version 2 of the License, or (at your option) any
- later version.
- */
-
- /*
- 29-Sep-1999 - GMT offset now configurable.
- 30-Nov-1999 - reason() to give error codes as strings.
- - NFS_wt_err() made into a global function.
- - Protection/Mode filters rewritten.
- */
-
- #include "nfsd.h"
- #include "memory.h"
- #include "handle_list.h"
-
- #include <stdio.h>
- #include <bsdsocket/socketbasetags.h>
- #include <proto/dos.h>
- #include <proto/socket.h>
-
- /* This is how many hours we must add to GMT to get the current wall clock time */
- LONG amigaGMTOffset = 0;
-
- /*
- Reports the reason for an error encountered during use of
- bsdsocket.library.
- */
- void printSocketError(STRPTR s)
- {
- int err = Errno();
- struct TagItem taglist[] = {
- {SBTM_GETVAL(SBTC_ERRNOSTRPTR), err},
- {TAG_END, 0}
- };
-
- if (0 == SocketBaseTagList(taglist)) {
- printf("%s: %s\n", s, (STRPTR)taglist[0].ti_Data);
- } else {
- printf("%s: (unkown reason - %d)\n", s, err);
- }
- }
-
-
- /* Maps Amiga error codes to NFS errors
- Remember some special cases:
- User is not the owner of a file they're modifiying, nor root
- NFSERR_PERM
-
- case ERROR_OBJECT_WRONG_TYPE
- Either NFSERR_ISDIR or NFSERR_NOTDIR, depending on context
-
- Anything else, NFSERR_IO
-
- Note that an error code will *always* be returned, even if what was passed
- wasn't an error itself
- */
-
- nfsstat NFS_err(LONG errno)
- {
- switch (errno) {
- case ERROR_OBJECT_IN_USE:
- return NFSERR_ACCES;
-
- case ERROR_OBJECT_EXISTS:
- return NFSERR_EXIST;
-
- case ERROR_DIR_NOT_FOUND:
- case ERROR_OBJECT_NOT_FOUND:
- return NFSERR_NOENT;
-
- case ERROR_OBJECT_TOO_LARGE:
- return NFSERR_IO;
-
- case ERROR_INVALID_COMPONENT_NAME:
- return NFSERR_INVAL;
-
- case ERROR_DISK_NOT_VALIDATED:
- case ERROR_DISK_WRITE_PROTECTED:
- return NFSERR_ROFS;
-
- case ERROR_RENAME_ACROSS_DEVICES:
- return NFSERR_ACCES;
-
- case ERROR_DIRECTORY_NOT_EMPTY:
- return NFSERR_NOTEMPTY;
-
- case ERROR_DISK_FULL:
- return NFSERR_NOSPC;
-
- case ERROR_DELETE_PROTECTED:
- case ERROR_WRITE_PROTECTED:
- case ERROR_READ_PROTECTED:
- return NFSERR_ACCES;
-
- /* Hmhmmhmh... if I ever handle links properly, y'know... */
- case ERROR_IS_SOFT_LINK:
- case ERROR_OBJECT_LINKED:
- return NFSERR_IO;
-
- case ERROR_NOT_A_DOS_DISK:
- case ERROR_NO_DISK:
- case ERROR_DEVICE_NOT_MOUNTED:
- case ERROR_SEEK_ERROR:
- return NFSERR_IO;
-
- default:
- return NFSERR_IO;
- }
- }
-
-
- /* This is in so much it's starting to look messy... let's make it a
- function in its own right!
- NFS is more specific than AmigaDOS when it comes to things being
- of the wrong type. If the error is a wrong type one, we return
- the more suitable code supplied (eg. NFSERR_ISDIR)
- */
- nfsstat NFS_wt_err(nfsstat wrongtype)
- {
- LONG err = IoErr();
- if (err == ERROR_OBJECT_WRONG_TYPE)
- return wrongtype;
- else
- return NFS_err(err);
- }
-
-
- STRPTR reason(nfsstat err)
- {
- switch (err) {
- case NFS_OK:
- return "no error";
-
- case NFSERR_PERM:
- return "not owner";
-
- case NFSERR_NOENT:
- return "no such file or directory";
-
- case NFSERR_IO:
- return "I/O error";
-
- case NFSERR_NXIO:
- return "no such device or address";
-
- case NFSERR_ACCES:
- return "permission denied";
-
- case NFSERR_EXIST:
- return "file exists";
-
- case NFSERR_NODEV:
- return "no such device";
-
- case NFSERR_NOTDIR:
- return "not a directory";
-
- case NFSERR_ISDIR:
- return "is a directory";
-
- case NFSERR_INVAL:
- return "invalid argument";
-
- case NFSERR_FBIG:
- return "file too large";
-
- case NFSERR_NOSPC:
- return "no space left on device";
-
- case NFSERR_ROFS:
- return "read-only file system";
-
- case NFSERR_NAMETOOLONG:
- return "file name too long";
-
- case NFSERR_NOTEMPTY:
- return "directory not empty";
-
- case NFSERR_DQUOT:
- return "disc quota exceeded";
-
- case NFSERR_STALE:
- return "stale NFS file handle";
-
- case NFSERR_WFLUSH:
- return "write cache flushed";
-
- default:
- /* No, this isn't thread safe */
- static char buf[16 + 11];
- sprintf(buf, "unknown error(%d)", err);
- return buf;
- }
- }
-
- /* Protection bits */
-
- /* These used to be far more verbose, but these are just tidier */
-
- /* Does a basic conversion of Amiga protection bits to Unix mode
- - all special bits are ignored */
- u_int NFS_mode(ULONG prot)
- {
- /* For the user bits, 0 means allowed - this is reversed
- for the others. D'oh! */
-
- return ((~prot & (0x07 << 1)) << 5)
- | ((prot & (0x07 << 9)) >> 6)
- | ((prot & (0x07 << 13)) >> 13);
- }
-
- /* Does a basic mapping of Unix modes to Amiga protection bits -
- all special bits are ignored (including 'delete') */
- ULONG Amiga_prot(u_int mode)
- {
- /* Same craziness as above */
- return ((~mode & 0700) >> 5) | ((mode & 0070) << 6)
- | ((mode & 0007) << 13);
- }
-
- /* Date handling */
-
- #define AMIGA_GMT_OFFSET_SECONDS (amigaGMTOffset * 60 * 60)
-
- /* This is the Unix date that AmigaOS time begins from */
- #define UNIX_AMIGA_EPOCH (252460800)
-
- /* Convert an Amiga DateStamp to an nfstime */
- void Unix_date(struct DateStamp *ds, struct nfstime *tv)
- {
- /* We need the time as seconds from Jan 1 1970 */
- tv->seconds = (ds->ds_Days * 24 * 60
- + ds->ds_Minute) * 60
- + UNIX_AMIGA_EPOCH /* Offset Unix->Amiga epoch */
- - AMIGA_GMT_OFFSET_SECONDS;
-
- tv->useconds = ds->ds_Tick * (1000 / TICKS_PER_SECOND);
-
- /* We'd better normalize it */
- while (tv->useconds >= 1000) {
- tv->useconds -= 1000;
- tv->seconds++;
- }
-
- /* The Amiga stores all dates in local time, and there's no way
- of finding what the correct offset is, so we make the user
- tell us.
- */
- }
-
- /* Convert an nfstime to an Amiga DateStamp */
- void Amiga_date(struct nfstime *tv, struct DateStamp *ds)
- {
- #define MPD (60 * 24)
-
- LONG ami_seconds = tv->seconds - UNIX_AMIGA_EPOCH
- + AMIGA_GMT_OFFSET_SECONDS,
- ami_minutes = ami_seconds / 60;
-
- ds->ds_Days = ami_minutes / MPD;
- ds->ds_Minute = ami_minutes % MPD;
-
- ami_seconds -= ami_minutes * 60;
-
- ds->ds_Tick = tv->useconds / (1000 / TICKS_PER_SECOND)
- + ami_seconds * TICKS_PER_SECOND;
-
- /* So, we'd better normalise it... */
- #define TPM (60 * TICKS_PER_SECOND)
- while (ds->ds_Tick >= TPM) {
- ds->ds_Tick -= TPM;
- ds->ds_Minute++;
- }
- #undef TPM
-
- while (ds->ds_Minute >= MPD) {
- ds->ds_Minute -= MPD;
- ds->ds_Days++;
- }
-
- #undef MPD
-
- }
-
-
- /* Convert Amiga to NFS file types */
- ftype NFS_type(LONG type)
- {
- switch (type) {
- case ST_ROOT:
- case ST_USERDIR:
- case ST_LINKDIR:
- return NFDIR;
-
- case ST_FILE:
- return NFREG;
-
- case ST_SOFTLINK:
- return NFLNK;
-
- default:
- if (type < 0)
- return NFREG;
- else if (type > 0)
- return NFDIR;
- else
- return NFNON;
- }
- }
-
-
- /* Is this a valid Amiga filename component? */
- BOOL is_valid_filename(STRPTR name)
- {
- if (!name)
- return FALSE;
-
- if ((FilePart(name) == name) && (strlen(name) > 0))
- return TRUE;
-
- return FALSE;
- }
-
-
- /* Get the full name from a diropargs */
- STRPTR name_of_diropargs(STRPTR filename,
- struct LocalFile *dir_lf, nfsstat *stat)
- {
- int length;
- STRPTR full_name;
-
- if (!is_valid_filename(filename)) {
- *stat = NFSERR_ACCES;
- printf("Illegal reference to file '%s'\n", filename);
- return NULL;
- }
-
- DEBUG(printf("Referring to '%s' in '%s'\n", filename, dir_lf->lf_Name));
-
- /* Is it actually a directory? */
- if (dir_lf->lf_Type != NFDIR) {
- *stat = NFSERR_NOTDIR;
- return NULL;
- }
-
- /* The code above may not be perfect if we're using symlinks... */
-
- /* So, I guess we need a buffer to concatenate those in */
- length = strlen(filename) + strlen(dir_lf->lf_Name)
- + 2; /* Terminating NULL and separating slash */
-
- if (full_name = AllocVecPooled(length)) {
- strcpy(full_name, dir_lf->lf_Name);
- if (!AddPart(full_name, filename, length)) {
- /* This *shouldn't* happen */
- FreeVecPooled(full_name);
- *stat = NFSERR_NAMETOOLONG;
- return NULL;
- }
- } else
- *stat = NFSERR_IO; /* No memory? */
-
- return full_name;
- }
-
-