home *** CD-ROM | disk | FTP | other *** search
/ Magazyn Amiga 13 / MA_Cover_13.bin / source / c / nfsd / src / nfs_utils.c < prev    next >
Encoding:
C/C++ Source or Header  |  1999-11-30  |  8.9 KB  |  371 lines

  1. /*  Various utility functions
  2.  
  3.     ©1998, 1999 Joseph Walton
  4.  
  5.     This software is distributed under the terms of the GNU General Public
  6.     License; either version 2 of the License, or (at your option) any
  7.     later version.
  8. */
  9.  
  10. /*
  11.     29-Sep-1999 - GMT offset now configurable.
  12.     30-Nov-1999 - reason() to give error codes as strings.
  13.                 - NFS_wt_err() made into a global function.
  14.                 - Protection/Mode filters rewritten.
  15. */
  16.  
  17. #include "nfsd.h"
  18. #include "memory.h"
  19. #include "handle_list.h"
  20.  
  21. #include <stdio.h>
  22. #include <bsdsocket/socketbasetags.h>
  23. #include <proto/dos.h>
  24. #include <proto/socket.h>
  25.  
  26. /* This is how many hours we must add to GMT to get the current wall clock time */
  27. LONG amigaGMTOffset = 0;
  28.  
  29. /*
  30.     Reports the reason for an error encountered during use of
  31.      bsdsocket.library.
  32. */
  33. void printSocketError(STRPTR s)
  34. {
  35.     int err = Errno();
  36.     struct TagItem taglist[] = {
  37.         {SBTM_GETVAL(SBTC_ERRNOSTRPTR), err},
  38.         {TAG_END, 0}
  39.     };
  40.  
  41.     if (0 == SocketBaseTagList(taglist)) {
  42.         printf("%s: %s\n", s, (STRPTR)taglist[0].ti_Data);
  43.     } else {
  44.         printf("%s: (unkown reason - %d)\n", s, err);
  45.     }
  46. }
  47.  
  48.  
  49. /* Maps Amiga error codes to NFS errors
  50.    Remember some special cases:
  51. User is not the owner of a file they're modifiying, nor root
  52.     NFSERR_PERM
  53.  
  54. case ERROR_OBJECT_WRONG_TYPE
  55.     Either NFSERR_ISDIR or NFSERR_NOTDIR, depending on context
  56.  
  57. Anything else, NFSERR_IO
  58.  
  59. Note that an error code will *always* be returned, even if what was passed
  60. wasn't an error itself
  61. */
  62.  
  63. nfsstat NFS_err(LONG errno)
  64. {
  65.     switch (errno) {
  66.         case ERROR_OBJECT_IN_USE:
  67.             return NFSERR_ACCES;
  68.  
  69.         case ERROR_OBJECT_EXISTS:
  70.             return NFSERR_EXIST;
  71.  
  72.         case ERROR_DIR_NOT_FOUND:
  73.         case ERROR_OBJECT_NOT_FOUND:
  74.             return NFSERR_NOENT;
  75.  
  76.         case ERROR_OBJECT_TOO_LARGE:
  77.             return NFSERR_IO;
  78.  
  79.         case ERROR_INVALID_COMPONENT_NAME:
  80.             return NFSERR_INVAL;
  81.  
  82.         case ERROR_DISK_NOT_VALIDATED:
  83.         case ERROR_DISK_WRITE_PROTECTED:
  84.             return NFSERR_ROFS;
  85.  
  86.         case ERROR_RENAME_ACROSS_DEVICES:
  87.             return NFSERR_ACCES;
  88.  
  89.         case ERROR_DIRECTORY_NOT_EMPTY:
  90.             return NFSERR_NOTEMPTY;
  91.  
  92.         case ERROR_DISK_FULL:
  93.             return NFSERR_NOSPC;
  94.  
  95.         case ERROR_DELETE_PROTECTED:
  96.         case ERROR_WRITE_PROTECTED:
  97.         case ERROR_READ_PROTECTED:
  98.             return NFSERR_ACCES;
  99.  
  100.         /* Hmhmmhmh... if I ever handle links properly, y'know... */
  101.         case ERROR_IS_SOFT_LINK:
  102.         case ERROR_OBJECT_LINKED:
  103.             return NFSERR_IO;
  104.  
  105.         case ERROR_NOT_A_DOS_DISK:
  106.         case ERROR_NO_DISK:
  107.         case ERROR_DEVICE_NOT_MOUNTED:
  108.         case ERROR_SEEK_ERROR:
  109.             return NFSERR_IO;
  110.  
  111.         default:
  112.             return NFSERR_IO;
  113.     }
  114. }
  115.  
  116.  
  117. /* This is in so much it's starting to look messy... let's make it a
  118.     function in its own right!
  119.    NFS is more specific than AmigaDOS when it comes to things being
  120.     of the wrong type. If the error is a wrong type one, we return
  121.     the more suitable code supplied (eg. NFSERR_ISDIR)
  122. */
  123. nfsstat NFS_wt_err(nfsstat wrongtype)
  124. {
  125.     LONG err = IoErr();
  126.     if (err == ERROR_OBJECT_WRONG_TYPE)
  127.         return wrongtype;
  128.     else
  129.         return NFS_err(err);
  130. }
  131.  
  132.  
  133. STRPTR reason(nfsstat err)
  134. {
  135.     switch (err) {
  136.         case NFS_OK:
  137.             return "no error";
  138.  
  139.         case NFSERR_PERM:
  140.             return "not owner";
  141.  
  142.         case NFSERR_NOENT:
  143.             return "no such file or directory";
  144.  
  145.         case NFSERR_IO:
  146.             return "I/O error";
  147.  
  148.         case NFSERR_NXIO:
  149.             return "no such device or address";
  150.  
  151.         case NFSERR_ACCES:
  152.             return "permission denied";
  153.  
  154.         case NFSERR_EXIST:
  155.             return "file exists";
  156.  
  157.         case NFSERR_NODEV:
  158.             return "no such device";
  159.  
  160.         case NFSERR_NOTDIR:
  161.             return "not a directory";
  162.  
  163.         case NFSERR_ISDIR:
  164.             return "is a directory";
  165.  
  166.         case NFSERR_INVAL:
  167.             return "invalid argument";
  168.  
  169.         case NFSERR_FBIG:
  170.             return "file too large";
  171.  
  172.         case NFSERR_NOSPC:
  173.             return "no space left on device";
  174.  
  175.         case NFSERR_ROFS:
  176.             return "read-only file system";
  177.  
  178.         case NFSERR_NAMETOOLONG:
  179.             return "file name too long";
  180.  
  181.         case NFSERR_NOTEMPTY:
  182.             return "directory not empty";
  183.  
  184.         case NFSERR_DQUOT:
  185.             return "disc quota exceeded";
  186.  
  187.         case NFSERR_STALE:
  188.             return "stale NFS file handle";
  189.  
  190.         case NFSERR_WFLUSH:
  191.             return "write cache flushed";
  192.  
  193.         default:
  194.             /* No, this isn't thread safe */
  195.             static char buf[16 + 11];
  196.             sprintf(buf, "unknown error(%d)", err);
  197.             return buf;
  198.     }
  199. }
  200.  
  201. /* Protection bits */
  202.  
  203. /* These used to be far more verbose, but these are just tidier */
  204.  
  205. /* Does a basic conversion of Amiga protection bits to Unix mode
  206.     - all special bits are ignored */
  207. u_int NFS_mode(ULONG prot)
  208. {
  209.     /* For the user bits, 0 means allowed - this is reversed
  210.         for the others. D'oh! */
  211.  
  212.     return ((~prot & (0x07 << 1)) << 5)
  213.             | ((prot & (0x07 << 9)) >> 6)
  214.             | ((prot & (0x07 << 13)) >> 13);
  215. }
  216.  
  217. /* Does a basic mapping of Unix modes to Amiga protection bits -
  218.     all special bits are ignored (including 'delete') */
  219. ULONG Amiga_prot(u_int mode)
  220. {
  221.     /* Same craziness as above */
  222.     return ((~mode & 0700) >> 5) | ((mode & 0070) << 6)
  223.         | ((mode & 0007) << 13);
  224. }
  225.  
  226. /* Date handling */
  227.  
  228. #define AMIGA_GMT_OFFSET_SECONDS (amigaGMTOffset * 60 * 60)
  229.  
  230. /* This is the Unix date that AmigaOS time begins from */
  231. #define UNIX_AMIGA_EPOCH (252460800)
  232.  
  233. /* Convert an Amiga DateStamp to an nfstime */
  234. void Unix_date(struct DateStamp *ds, struct nfstime *tv)
  235. {
  236.     /* We need the time as seconds from Jan 1 1970 */
  237.     tv->seconds = (ds->ds_Days * 24 * 60
  238.         + ds->ds_Minute) * 60
  239.         + UNIX_AMIGA_EPOCH /* Offset Unix->Amiga epoch */
  240.         - AMIGA_GMT_OFFSET_SECONDS;
  241.  
  242.     tv->useconds = ds->ds_Tick * (1000 / TICKS_PER_SECOND);
  243.  
  244.     /* We'd better normalize it */
  245.     while (tv->useconds >= 1000) {
  246.         tv->useconds -= 1000;
  247.         tv->seconds++;
  248.     }
  249.  
  250.     /* The Amiga stores all dates in local time, and there's no way
  251.         of finding what the correct offset is, so we make the user
  252.         tell us.
  253.     */
  254. }
  255.  
  256. /* Convert an nfstime to an Amiga DateStamp */
  257. void Amiga_date(struct nfstime *tv, struct DateStamp *ds)
  258. {
  259.     #define MPD (60 * 24)
  260.  
  261.     LONG ami_seconds = tv->seconds - UNIX_AMIGA_EPOCH
  262.         + AMIGA_GMT_OFFSET_SECONDS,
  263.         ami_minutes = ami_seconds / 60;
  264.  
  265.     ds->ds_Days = ami_minutes / MPD;
  266.     ds->ds_Minute = ami_minutes % MPD;
  267.  
  268.     ami_seconds -= ami_minutes * 60;
  269.  
  270.     ds->ds_Tick = tv->useconds / (1000 / TICKS_PER_SECOND)
  271.         + ami_seconds * TICKS_PER_SECOND;
  272.  
  273.     /* So, we'd better normalise it... */
  274.     #define TPM (60 * TICKS_PER_SECOND)
  275.     while (ds->ds_Tick >= TPM) {
  276.         ds->ds_Tick -= TPM;
  277.         ds->ds_Minute++;
  278.     }
  279.     #undef TPM
  280.  
  281.     while (ds->ds_Minute >= MPD) {
  282.         ds->ds_Minute -= MPD;
  283.         ds->ds_Days++;
  284.     }
  285.  
  286.     #undef MPD
  287.  
  288. }
  289.  
  290.  
  291. /* Convert Amiga to NFS file types */
  292. ftype NFS_type(LONG type)
  293. {
  294.     switch (type) {
  295.         case ST_ROOT:
  296.         case ST_USERDIR:
  297.         case ST_LINKDIR:
  298.             return NFDIR;
  299.  
  300.         case ST_FILE:
  301.             return NFREG;
  302.  
  303.         case ST_SOFTLINK:
  304.             return NFLNK;
  305.  
  306.         default:
  307.             if (type < 0)
  308.                 return NFREG;
  309.             else if (type > 0)
  310.                 return NFDIR;
  311.             else
  312.                 return NFNON;
  313.     }
  314. }
  315.  
  316.  
  317. /* Is this a valid Amiga filename component? */
  318. BOOL is_valid_filename(STRPTR name)
  319. {
  320.     if (!name)
  321.         return FALSE;
  322.  
  323.     if ((FilePart(name) == name) && (strlen(name) > 0))
  324.         return TRUE;
  325.  
  326.     return FALSE;
  327. }
  328.  
  329.  
  330. /* Get the full name from a diropargs */
  331. STRPTR name_of_diropargs(STRPTR filename,
  332.     struct LocalFile *dir_lf, nfsstat *stat)
  333. {
  334.     int length;
  335.     STRPTR full_name;
  336.  
  337.     if (!is_valid_filename(filename)) {
  338.         *stat = NFSERR_ACCES;
  339.         printf("Illegal reference to file '%s'\n", filename);
  340.         return NULL;
  341.     }
  342.  
  343.     DEBUG(printf("Referring to '%s' in '%s'\n", filename, dir_lf->lf_Name));
  344.  
  345.     /* Is it actually a directory? */
  346.     if (dir_lf->lf_Type != NFDIR) {
  347.         *stat = NFSERR_NOTDIR;
  348.         return NULL;
  349.     }
  350.  
  351.     /* The code above may not be perfect if we're using symlinks... */
  352.  
  353.     /* So, I guess we need a buffer to concatenate those in */
  354.     length = strlen(filename) + strlen(dir_lf->lf_Name)
  355.         + 2; /* Terminating NULL and separating slash */
  356.  
  357.     if (full_name = AllocVecPooled(length)) {
  358.         strcpy(full_name, dir_lf->lf_Name);
  359.         if (!AddPart(full_name, filename, length)) {
  360.             /* This *shouldn't* happen */
  361.             FreeVecPooled(full_name);
  362.             *stat = NFSERR_NAMETOOLONG;
  363.             return NULL;
  364.         }
  365.     } else
  366.         *stat = NFSERR_IO; /* No memory? */
  367.  
  368.     return full_name;
  369. }
  370.  
  371.