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

  1. /*  This is all the smarts behind NFS - or at least glue to the real stuff
  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.     30-Nov-1999 - Major changes to support new RPC code.
  12. */
  13.  
  14. #include "nfsd.h"
  15. #include "memory.h"
  16. #include "nfs_utils.h"
  17. #include "handle_list.h"
  18. #include "auth.h"
  19. #include <string.h>
  20. #include <stdio.h>
  21.  
  22. #include <dos/dos.h>
  23. #include <proto/dos.h>
  24.  
  25. int32 *fillinfibattrs(int32 *rptr, struct LocalFile *lf);
  26. nfsstat set_attrs(struct LocalFile *lf, struct sattr *sa, BPTR handle);
  27. BOOL SeekWithExtend(BPTR handle, LONG offset);
  28.  
  29. extern struct InfoData infodata;
  30. extern struct FileInfoBlock fib;
  31.  
  32. #define HEADER_INT32S (6)
  33. #define FATTR_INT32S (11 + (3 * 2))
  34. #define FHANDLE_INT32S (INT32S(NFS_FHSIZE))
  35.  
  36. #define DIROPRES_INT32S (HEADER_INT32S + 1 + FHANDLE_INT32S + FATTR_INT32S)
  37.  
  38. #define ISERR(x) ((x) != NFS_OK)
  39. #define PERR(c,s,x) VERBOSE(print_auth_once(c); printf(s " failed - %s\n", reason(x)))
  40. #define PRES(c,s,x) if(ISERR(x)){PERR(c,s,x)}
  41.  
  42. int nfsproc_getattr_2_svc(nfs_fh *handle, struct Call *call, int32 *rptr)
  43. {
  44.     DEBUG(print_auth_once(call));
  45.     DEBUG(puts("nfsproc_getattr_2_svc"));
  46.  
  47.     /* Strictly, Unix would usually require only read access to the
  48.         parent directory here. However, that doesn't make much sense
  49.         under AmigaDOS. It's all a little arbitrary at the moment,
  50.         but it sort of makes sense.
  51.     */
  52.  
  53.     nfsstat status;
  54.     struct LocalFile *lf;
  55.  
  56.     if (lf = get_by_handle(handle, &status, ACCESS_READ)) {
  57.         DEBUG(printf("Getting status of '%s'\n", lf->lf_Name));
  58.  
  59.         status = check_permission(call, lf, ALLOW_GETATTRS);
  60.  
  61.         if (status == NFS_OK) {
  62.             *rptr++ = P_ENUM(NFS_OK);
  63.             fillinfibattrs(rptr, lf);
  64.         } else {
  65.             print_auth_once(call);
  66.             printf("Not authorised to get attributes of '%s' - %s\n", lf->lf_Name,
  67.                 reason(status));
  68.         }
  69.  
  70.         release_lf(lf);
  71.     } else {
  72.         PERR(call, "getattr", status);
  73.     }
  74.  
  75.     if (status == NFS_OK) {
  76.         return HEADER_INT32S + 1 + FATTR_INT32S;
  77.     } else {
  78.         *rptr = P_ENUM(status);
  79.         return HEADER_INT32S + 1;
  80.     }
  81. }
  82.  
  83. /* This isn't quite atomic at the moment, although this is only
  84.     tickled in a couple of cases */
  85. int nfsproc_setattr_2_svc(struct sattrargs *args, struct Call *call, int32 *rptr)
  86. {
  87.     DEBUG(print_auth_once(call));
  88.     DEBUG(puts("nfsproc_setattr_2_svc"));
  89.  
  90.     nfsstat status;
  91.  
  92.     struct LocalFile *lf;
  93.     if (lf = get_by_handle(args->handle, &status, ACCESS_READ)) {
  94.  
  95.         /* Are they allowed to set the attributes? */
  96.         status = check_permission(call, lf, ALLOW_SETATTRS);
  97.  
  98.         if (status == NFS_OK) {
  99.             status = set_attrs(lf, &args->sattr, (BPTR)NULL);
  100.  
  101.             if (status == NFS_OK) {
  102.                 *rptr++ = P_ENUM(NFS_OK);
  103.                 fillinfibattrs(rptr, lf);
  104.             } else {
  105.                 print_auth_once(call);
  106.                 printf("Failed to set attributes of '%s' - %s\n",
  107.                     lf->lf_Name, reason(status));
  108.             }
  109.         } else {
  110.             print_auth_once(call);
  111.             printf("Attribute setting of '%s' not permitted", lf->lf_Name);
  112.         }
  113.  
  114.         release_lf(lf);
  115.     }
  116.  
  117.     if (status != NFS_OK) {
  118.         *rptr = P_ENUM(status);
  119.         PERR(call, "setattr", status);
  120.         return HEADER_INT32S + 1;
  121.     }
  122.  
  123.     return HEADER_INT32S + 1 + FATTR_INT32S;
  124. }
  125.  
  126. int nfsproc_lookup_2_svc(struct diropargs *argp, struct Call *call, int32 *rptr)
  127. {
  128.     DEBUG(print_auth_once(call));
  129.     DEBUG(puts("nfsproc_lookup_2_svc"));
  130.  
  131.     /* They must have read access to the parent directory,
  132.         as well as to the file being looked up */
  133.  
  134.     nfsstat status;
  135.     struct LocalFile *dir_lf;
  136.  
  137.     if (dir_lf = get_by_handle(argp->dir_handle, &status, ACCESS_READ))
  138.     {
  139.         status = check_permission(call, dir_lf, ALLOW_READ);
  140.  
  141.         if (status == NFS_OK) {
  142.             STRPTR name = argp->filename;
  143.  
  144.             /* A few special cases... */
  145.             if (!strcmp(name, ".") || (*name == '\0')) { // "." or ""
  146.                 /* They're looking up the directory itself */
  147.                 *rptr++ = P_ENUM(NFS_OK);
  148.                 rptr = fh_copy(dir_lf, rptr);
  149.                 fillinfibattrs(rptr, dir_lf);
  150.             } else {
  151.                 STRPTR full_name;
  152.                 /* Frankly this should be handled locally. Some clients
  153.                     don't see it quite the same way, however, so I suppose
  154.                     we'd better deal with it. */
  155.                 if (!strcmp(name, "..")) {
  156.                     /* They want the parent of this directory */
  157.                     full_name = DupString(dir_lf->lf_Name);
  158.  
  159.                     if (full_name) {
  160.                         *PathPart(full_name) = 0; /* Can this *ever* return NULL? */
  161.                         DEBUG(printf("Parent of '%s' is '%s'\n",
  162.                             dir_lf->lf_Name, full_name));
  163.                     } else {
  164.                         status = NFSERR_NOENT;
  165.                         print_auth_once(call);
  166.                         printf("Problem getting parent of '%s'\n",
  167.                             dir_lf->lf_Name);
  168.                     }
  169.                 } else {
  170.                     full_name = name_of_diropargs(argp->filename, dir_lf, &status);
  171.                 }
  172.  
  173.                 /* Did we get anything? */
  174.  
  175.                 if (full_name) {
  176.                     struct LocalFile *nlf = get_namedlocalfile(full_name);
  177.  
  178.                     if (nlf) {
  179.                         BPTR lock = Lock(full_name, ACCESS_READ);
  180.                         if (lock) {
  181.                             if (Examine(lock, &fib)) { /* Everything seems to have worked! */
  182.                                 correct_struct(nlf); /* Give it an inode etc. */
  183.  
  184.                                 /* Can they actually read that file? If
  185.                                     not, then they don't get it */
  186.  
  187.                                 status = check_permission(call,
  188.                                     nlf, ALLOW_READ);
  189.  
  190.                                 if (status == NFS_OK) {
  191.                                     *rptr++ = P_ENUM(NFS_OK);
  192.                                     rptr = fh_copy(nlf, rptr);
  193.                                     fillinfibattrs(rptr, nlf);
  194.                                 } else {
  195.                                     print_auth_once(call);
  196.                                     printf("Forbidden from looking up '%s' - %s\n", full_name, reason(status));
  197.                                 }
  198.                             } else
  199.                                 status = NFS_err(IoErr());
  200.  
  201.                             UnLock(lock);
  202.                         } else
  203.                             status = NFS_wt_err(NFSERR_NOTDIR);
  204.                     } else
  205.                         status = NFSERR_IO; /* No memory? */
  206.  
  207.                     FreeVecPooled(full_name);
  208.                 }
  209.             }
  210.         }
  211.  
  212.         release_lf(dir_lf);
  213.     }
  214.  
  215.     if (status != NFS_OK) {
  216.         *rptr = P_ENUM(status);
  217.         PERR(call, "lookup", status);
  218.         return HEADER_INT32S + 1;
  219.     }
  220.  
  221.     return DIROPRES_INT32S;
  222. }
  223.  
  224. int nfsproc_read_2_svc(struct readargs *argp, struct Call *call, int32 *rptr,
  225.     int32 *rlimit)
  226. {
  227.     struct LocalFile *lf;
  228.     int len;
  229.     BPTR handle;
  230.  
  231.     DEBUG(print_auth_once(call));
  232.     DEBUG(puts("nfsproc_read_2_svc"));
  233.  
  234.     nfsstat status;
  235.     int count = HEADER_INT32S + 1;
  236.  
  237.     /* How odd - I'm using a completely different structure for
  238.         this function. Odd. */
  239.  
  240.     lf = get_by_handle(argp->handle, &status, ACCESS_READ);
  241.  
  242.     if (!lf) {            /* Some kind of error */
  243.         *rptr = P_ENUM(status);
  244.         return HEADER_INT32S + 1;
  245.     }
  246.  
  247.     /* Obviously they need to have permission here... */
  248.     status = check_permission(call, lf, ALLOW_READ);
  249.  
  250.     if (status != NFS_OK) {
  251.         *rptr = P_ENUM(status);
  252.         return HEADER_INT32S + 1;
  253.     }
  254.  
  255.     if (verbose) {
  256.         print_auth_once(call);
  257.         printf("%s: Asked to read %d bytes from %d\n",
  258.             lf->lf_Name, argp->count, argp->offset);
  259.     }
  260.  
  261.     len = argp->count;
  262.     if (len > NFS_MAXDATA)
  263.         len = NFS_MAXDATA;
  264.  
  265.     if (handle = OpenFromLock(lf->lf_Lock)) {
  266.         lf->lf_Lock = NULL; /* It's no longer valid */
  267.  
  268.         if (Seek(handle, argp->offset, OFFSET_BEGINNING) != -1) {
  269.             int32 *buffer = rptr + 1 + FATTR_INT32S + 1;
  270.  
  271.             /* This will be NFS_MAXDATA, but let's check anyway */
  272.             int buf_len = (rlimit - buffer) * SINT32;
  273.             if (len > buf_len) {
  274.                 len = buf_len;
  275.             }
  276.  
  277.             len = Read(handle, buffer, len);
  278.             if (len == -1) { /* Error */
  279.                 LONG e = IoErr();
  280.                 if (verbose) {
  281.                     print_auth_once(call);
  282.                     PrintFault(e, "Unable to read from file");
  283.                 }
  284.                 status = NFS_err(e);
  285.             } else {
  286.                 /* We succeeded */
  287.                 *rptr++ = P_ENUM(NFS_OK);
  288.                 rptr = fillinfibattrs(rptr, lf); /* The old fib won't have been changed */
  289.                 *rptr = P_UINT(len);
  290.  
  291.                 count = HEADER_INT32S + 1 + FATTR_INT32S + 1 + INT32S(len);
  292.             }
  293.         } else {
  294.             status = NFS_err(IoErr()); /* That's an error, I'm afraid */
  295.         }
  296.  
  297.         Close(handle);
  298.     } else
  299.         status = NFS_wt_err(NFSERR_ISDIR);
  300.  
  301.     release_lf(lf);
  302.  
  303.     if (status != NFS_OK) {
  304.         *rptr = P_ENUM(status);
  305.         PERR(call, "read", status);
  306.     }
  307.  
  308.     return count;
  309. }
  310.  
  311. int nfsproc_write_2_svc(struct writeargs *argp, struct Call *call, int32 *rptr)
  312. {
  313.     DEBUG(print_auth_once(call));
  314.     DEBUG(puts("nfsproc_write_2_svc"));
  315.  
  316.     /* Obviously, they must have write access to this file */
  317.  
  318.     nfsstat status;
  319.     struct LocalFile *lf;
  320.  
  321.     if (lf = get_by_handle(argp->handle, &status, ACCESS_WRITE)) {
  322.         /* Basic debugging output */
  323.         VERBOSE(printf("'%s' - writing %d bytes at %d\n",
  324.             lf->lf_Name, argp->count, argp->offset));
  325.  
  326.         status = check_permission(call, lf, ALLOW_WRITE);
  327.  
  328.         if (status == NFS_OK) {
  329.             BPTR handle;
  330.             if (handle = OpenFromLock(lf->lf_Lock)) {
  331.                 lf->lf_Lock = NULL;
  332.  
  333.                 /* Since seeking in the Right Way involves some work
  334.                     it's moved to its own function */
  335.                 if (SeekWithExtend(handle, argp->offset) &&
  336.                         (Write(handle, argp->data, argp->count) == argp->count))
  337.                 {
  338.                     if (ExamineFH(handle, &fib)) {
  339.                         /* Success */
  340.                         *rptr++ = P_ENUM(NFS_OK);
  341.                         fillinfibattrs(rptr, lf);
  342.                     } else {
  343.                         status = NFS_err(IoErr());
  344.                     }
  345.                 } else {
  346.                     status = NFS_err(IoErr());
  347.                 }
  348.  
  349.                 Close(handle);
  350.             } else
  351.                 status = NFS_wt_err(NFSERR_ISDIR);
  352.         }
  353.  
  354.         release_lf(lf);
  355.     }
  356.  
  357.     if (status != NFS_OK) {
  358.         *rptr = P_ENUM(status);
  359.         PERR(call, "write", status);
  360.         return HEADER_INT32S + 1;
  361.     }
  362.  
  363.     return HEADER_INT32S + 1 + FATTR_INT32S;
  364. }
  365.  
  366. /* When a creation request comes in, attribute it if it is not
  367.     explicitly claiming ownership */
  368. static void impose_auth(struct Call *call, struct sattr *sa)
  369. {
  370.     if (!call->c_auth.isUnix)
  371.         return;
  372.  
  373.     if (sa->uid == -1)
  374.         sa->uid = call->c_auth.uid;
  375.  
  376.     if (sa->gid == -1)
  377.         sa->gid = call->c_auth.gid;
  378. }
  379.  
  380. int nfsproc_create_2_svc(struct createargs *argp, struct Call *call, int32 *rptr)
  381. {
  382.     struct LocalFile *dir_lf;
  383.  
  384.     DEBUG(print_auth_once(call));
  385.     DEBUG(puts("nfsproc_create_2_svc"));
  386.  
  387.     /* We must have write access to the directory,
  388.         and there must not be an existing entity of that name */
  389.  
  390.     nfsstat status;
  391.  
  392.     if (dir_lf = get_by_handle(argp->where.dir_handle,
  393.         &status, ACCESS_READ)) {
  394.  
  395.         status = check_permission(call, dir_lf, ALLOW_WRITE);
  396.  
  397.         if (status == NFS_OK) {
  398.             STRPTR full_name;
  399.  
  400.             if (full_name = name_of_diropargs(argp->where.filename, dir_lf,
  401.                 &status))
  402.             {
  403.                 struct LocalFile *nlf;
  404.  
  405.                 print_auth_once(call);
  406.                 printf("Creating file '%s'\n", full_name);
  407.  
  408.                 nlf = get_namedlocalfile(full_name);
  409.  
  410.                 /* There is room for a race condition here, in which we
  411.                     delete a file just created by another process */
  412.  
  413.                 if (nlf->lf_Type == NFNON) { /* It doesn't already exist */
  414.                     BPTR handle;
  415.                     if (handle = Open(full_name, MODE_NEWFILE)) {
  416.                         /* To set things, we need a non-exclusive handle */
  417.                         if (ChangeMode(CHANGE_FH, handle, MODE_READWRITE)) {
  418.                             ExamineFH(handle, &fib);
  419.                             correct_struct(nlf); /* Give it an inode */
  420.  
  421.                             impose_auth(call, &(argp->sattr));
  422.                             status = set_attrs(nlf, &(argp->sattr), handle);
  423.  
  424.                             if (status == NFS_OK) {
  425.                                 /* Succeeded */
  426.                                 *rptr++ = P_ENUM(NFS_OK);
  427.                                 rptr = fh_copy(nlf, rptr);
  428.                                 rptr = fillinfibattrs(rptr, nlf);
  429.                                 DEBUG(printf("Created '%s'\n", full_name));
  430.                             } else {
  431.                                 printf("Unable to set attributes of new file - %s", reason(status));
  432.                             }
  433.                         } else {
  434.                             PrintFault(IoErr(), "Unable to change a read-only handle into a read-write one");
  435.                             status = NFS_err(IoErr());
  436.                         }
  437.                         Close(handle);
  438.                     } else {
  439.                         PrintFault(IoErr(), "Unable to open new file");
  440.                         status = NFS_err(IoErr());
  441.                     }
  442.                 } else {
  443.                     printf("File already exists - type is %d\n", nlf->lf_Type);
  444.                     status = NFSERR_EXIST;
  445.                 }
  446.  
  447.                 FreeVecPooled(full_name);
  448.             }
  449.         }
  450.         release_lf(dir_lf);
  451.     }
  452.  
  453.     if (status != NFS_OK) {
  454.         *rptr = P_ENUM(status);
  455.         PERR(call, "create", status);
  456.         return HEADER_INT32S + 1;
  457.     }
  458.  
  459.     return DIROPRES_INT32S;
  460. }
  461.  
  462.  
  463. /* This will delete files and empty directories */
  464. static nfsstat generic_remove(struct diropargs *argp, struct Call *call)
  465. {
  466.     nfsstat status;
  467.     struct LocalFile *dir_lf;
  468.  
  469.     /* They only need write access to the parent directory, not access
  470.         to the actual file in question. UNIX has the notion of the 'sticky bit'
  471.         to get around this, and require users to own files they want to delete,
  472.         but we don't consider that here.
  473.     */
  474.  
  475.     if (dir_lf = get_by_handle(argp->dir_handle, &status, ACCESS_READ))
  476.     {
  477.         /* They must be able to write to this directory */
  478.         status = check_permission(call, dir_lf, ALLOW_WRITE);
  479.  
  480.         if (status == NFS_OK) {
  481.             STRPTR full_name = name_of_diropargs(argp->filename, dir_lf, &status);
  482.  
  483.             if (full_name) {
  484.                 print_auth_once(call);
  485.                 printf("Deleting '%s'\n", full_name);
  486.  
  487.                 /* Remove any trace */
  488.                 if (DeleteFile(full_name)) {
  489.                     lose_localfile(full_name);
  490.                     /* We succeeded - status is already NFS_OK */
  491.                 } else {
  492.                     status = NFS_wt_err(NFSERR_NOTDIR);
  493.                 }
  494.  
  495.                 FreeVecPooled(full_name);
  496.             }
  497.         }
  498.         release_lf(dir_lf);
  499.     }
  500.  
  501.     return status;
  502. }
  503.  
  504. nfsstat nfsproc_remove_2_svc(struct diropargs *argp, struct Call *call)
  505. {
  506.     DEBUG(print_auth_once(call));
  507.     DEBUG(puts("nfsproc_remove_2_svc"));
  508.  
  509.     /* Note that this will delete directories as well as files -
  510.         I do not consider this a security hole */
  511.  
  512.     nfsstat result = generic_remove(argp, call);
  513.  
  514.     PRES(call, "remove", result);
  515.     return result;
  516. }
  517.  
  518. nfsstat nfsproc_rmdir_2_svc(struct diropargs *argp, struct Call *call)
  519. {
  520.     DEBUG(print_auth_once(call));
  521.     DEBUG(puts("nfsproc_rmdir_2_svc"));
  522.  
  523.     /* Note that this will delete files as well as directories -
  524.         I do not consider this a security hole */
  525.  
  526.     nfsstat result = generic_remove(argp, call);
  527.  
  528.     PRES(call, "rmdir", result);
  529.     return result;
  530. }
  531.  
  532.  
  533. nfsstat nfsproc_rename_2_svc(struct renameargs *argp, struct Call *call)
  534. {
  535.     nfsstat  result;
  536.     struct LocalFile *lf_orig, *lf_new;
  537.  
  538.     DEBUG(print_auth_once(call));
  539.     DEBUG(puts("nfsproc_rename_2_svc"));
  540.  
  541.     /* Security: We must have write access to both the directories
  542.         involved */
  543.  
  544.     /* Note that write access to the file itself is *not* required */
  545.  
  546.     if (lf_orig = get_by_handle(argp->from.dir_handle, &result,
  547.         ACCESS_READ)) {
  548.  
  549.         result = check_permission(call, lf_orig, ALLOW_WRITE);
  550.  
  551.         if (result == NFS_OK) {
  552.             if (lf_new = get_by_handle(argp->to.dir_handle, &result,
  553.                 ACCESS_READ)) {
  554.  
  555.                 result = check_permission(call, lf_new, ALLOW_WRITE);
  556.  
  557.                 if (result == NFS_OK) {
  558.                     STRPTR source_name =
  559.                         name_of_diropargs(argp->from.filename, lf_orig, &result);
  560.  
  561.                     if (source_name) {
  562.                         STRPTR dest_name =
  563.                             name_of_diropargs(argp->to.filename, lf_new, &result);
  564.  
  565.                         if (dest_name) {
  566.                             print_auth_once(call);
  567.                             printf("Renaming '%s' to '%s'\n", source_name, dest_name);
  568.  
  569.                             if (Rename(source_name, dest_name)) {
  570.                                 /* Lose any reference to the old name */
  571.                                 lose_localfile(source_name);
  572.                                 result = NFS_OK;
  573.                             } else
  574.                                 result = NFS_err(IoErr());
  575.  
  576.                             FreeVecPooled(dest_name);
  577.                         }
  578.                         FreeVecPooled(source_name);
  579.                     }
  580.                 }
  581.  
  582.                 release_lf(lf_new);
  583.             }
  584.         }
  585.  
  586.         release_lf(lf_orig);
  587.     }
  588.  
  589.     PRES(call, "rename", result);
  590.     return result;
  591. }
  592.  
  593. int nfsproc_mkdir_2_svc(struct createargs *argp, struct Call *call, int32 *rptr)
  594. {
  595.     DEBUG(print_auth_once(call));
  596.     DEBUG(puts("nfsproc_mkdir_2_svc"));
  597.  
  598.     /* Security - the user must have write access to the parent
  599.         directory */
  600.  
  601.     nfsstat status;
  602.     struct LocalFile *dir_lf;
  603.  
  604.     if (dir_lf = get_by_handle(argp->where.dir_handle,
  605.         &status, ACCESS_READ)) {
  606.  
  607.         status = check_permission(call, dir_lf, ALLOW_WRITE);
  608.  
  609.         if (status == NFS_OK) {
  610.             STRPTR full_name = name_of_diropargs(argp->where.filename,
  611.                 dir_lf, &status);
  612.  
  613.             if (full_name) {
  614.                 struct LocalFile *nlf;
  615.  
  616.                 print_auth_once(call);
  617.                 printf("Making directory '%s'\n", full_name);
  618.  
  619.                 if (nlf = get_namedlocalfile(full_name)) {
  620.                     if (nlf->lf_Lock = CreateDir(full_name) ) {
  621.                         /* We can't do much with an exclusive lock on it,
  622.                             so turn it into a shared one */
  623.  
  624.                         if (ChangeMode(CHANGE_LOCK, nlf->lf_Lock, ACCESS_READ)) {
  625.                             if (Examine(nlf->lf_Lock, &fib)) {
  626.                                 correct_struct(nlf);
  627.  
  628.                                 /* Set the attributes */
  629.                                 impose_auth(call, &(argp->sattr));
  630.                                 status =
  631.                                 set_attrs(nlf, &(argp->sattr), (BPTR)NULL);
  632.  
  633.                                 if (status == NFS_OK) {
  634.                                     *rptr++ = P_ENUM(NFS_OK);
  635.                                     rptr = fh_copy(nlf, rptr);
  636.                                     fillinfibattrs(rptr, nlf);
  637.                                 }
  638.  
  639.                             } else {
  640.                                 PrintFault(IoErr(), "Unable to Examine() new directory");
  641.                                 status = NFS_err(IoErr());
  642.                             }
  643.                         } else {
  644.                             PrintFault(IoErr(), "Could not change exclusive lock to shared lock on new directory");
  645.                             status = NFS_err(IoErr());
  646.                         }
  647.  
  648.                         UnLock(nlf->lf_Lock);
  649.                         nlf->lf_Lock = NULL;
  650.                     } else {
  651.                         PrintFault(IoErr(), "Could not create directory");
  652.                         status = NFS_err(IoErr());
  653.                     }
  654.                 } else
  655.                     status = NFS_err(IoErr());
  656.  
  657.                 FreeVecPooled(full_name);
  658.             }
  659.         }
  660.     }
  661.  
  662.     if (status != NFS_OK) {
  663.         *rptr = P_ENUM(status);
  664.         PERR(call, "mkdir", status);
  665.         return HEADER_INT32S + 1;
  666.     }
  667.  
  668.     return DIROPRES_INT32S;
  669. }
  670.  
  671.  
  672. int nfsproc_readdir(struct readdirargs *args, struct Call *call,
  673.     int32 *rptr, int32 *rlimit)
  674. {
  675.     struct LocalFile *dir_lf;
  676.  
  677.     DEBUG(print_auth_once(call));
  678.     DEBUG(puts("nfsproc_readdir_2_svc"));
  679.  
  680.     nfsstat status;
  681.     /* They need read access to the directory */
  682.  
  683.     int count;
  684.  
  685.     if (dir_lf = get_by_handle(args->dir_handle, &status, ACCESS_READ)) {
  686.  
  687.         status = check_permission(call, dir_lf, ALLOW_READ);
  688.  
  689.         if (status == NFS_OK) {
  690.             count = HEADER_INT32S + readdir(dir_lf, rptr, rlimit, args->cookie, args->count);
  691.         } else {
  692.             *rptr = P_ENUM(status);
  693.             count = 7;
  694.         }
  695.         release_lf(dir_lf);
  696.     } else {
  697.         *rptr = P_ENUM(status);
  698.         count = 7;
  699.     }
  700.  
  701.     PRES(call, "readdir", status);
  702.  
  703.     return count;
  704. }
  705.  
  706. int nfsproc_statfs_2_svc(nfs_fh *handle, struct Call *call, int32 *rptr)
  707. {
  708.     DEBUG(print_auth_once(call));
  709.     DEBUG(puts("nfsproc_statfs_2_svc"));
  710.  
  711.     int count;
  712.     nfsstat status;
  713.     struct LocalFile *lf;
  714.  
  715.     if (lf = get_by_handle(handle, &status, ACCESS_READ)) {
  716.         status = check_permission(call, lf, ALLOW_READ);
  717.  
  718.         if (status == NFS_OK) {
  719.             VERBOSE(printf("BPB %ld; NB %ld; BU %ld\n",
  720.                 infodata.id_BytesPerBlock, infodata.id_NumBlocks,
  721.                 infodata.id_NumBlocksUsed));
  722.  
  723.             *rptr++ = P_ENUM(NFS_OK);
  724.  
  725.             *rptr++ = P_UINT(NFS_MAXDATA); // preferred transfer size in bytes
  726.             *rptr++ = P_UINT(infodata.id_BytesPerBlock); // fundamental file system block size
  727.             *rptr++ = P_UINT(infodata.id_NumBlocks); // total blocks in file system
  728.  
  729.             /* Free blocks in filing system */
  730.             *rptr++ = P_UINT(infodata.id_NumBlocks - infodata.id_NumBlocksUsed);
  731.  
  732.             /* Free blocks available to non-superuser (the same under AmigaOS */
  733.             *rptr   = P_UINT(infodata.id_NumBlocks - infodata.id_NumBlocksUsed);
  734.  
  735.             count = 6 + 6;
  736.         } else {
  737.             *rptr = P_ENUM(status);
  738.             count = 7;
  739.         }
  740.  
  741.         release_lf(lf);
  742.     } else {
  743.         *rptr = P_ENUM(status);
  744.         count = 7;
  745.     }
  746.  
  747.     PRES(call, "statfs", status);
  748.  
  749.     return count;
  750. }
  751.  
  752.  
  753. /* These are private support functions */
  754.  
  755. static int32 *fillinfibattrs(int32 *rptr, struct LocalFile *lf)
  756. {
  757.     u_int mode;
  758.  
  759.     /* What type is it? */
  760.     switch (*rptr++ = P_ENUM(NFS_type(fib.fib_DirEntryType))) {
  761.         /* V2 mandates this nasty feature - we need to encode the filetype
  762.             in the mode as well */
  763.         case NFDIR:
  764.             mode = NFSMODE_DIR;
  765.             break;
  766.  
  767.         case NFREG:
  768.             mode = NFSMODE_REG;
  769.             break;
  770.  
  771.         case NFLNK:
  772.             mode = NFSMODE_LNK;
  773.             break;
  774.  
  775.         default:
  776.             mode = 0;
  777.             break;
  778.     }
  779.  
  780.     /* Set the protection bits here... */
  781.     mode |= NFS_mode((lf->lf_ForcedProtection != -1)
  782.                 ? lf->lf_ForcedProtection
  783.                 : fib.fib_Protection);
  784.  
  785.     *rptr++ = P_UINT(mode);
  786.  
  787.     /* # hard links - may confuse Unix programs for directories */
  788.     *rptr++ = P_UINT(1);
  789.  
  790.     /* Do any UID/GID mappings here */
  791.     *rptr++ = P_UINT((lf->lf_ForcedUID != -1) ? lf->lf_ForcedUID : fib.fib_OwnerUID);
  792.     *rptr++ = P_UINT((lf->lf_ForcedGID != -1) ? lf->lf_ForcedGID : fib.fib_OwnerGID);
  793.  
  794.     *rptr++ = P_UINT(fib.fib_Size); // file size in bytes
  795.     *rptr++ = P_UINT(infodata.id_BytesPerBlock); // preferred block size
  796.     *rptr++ = P_UINT(0); // special device # (we ignore this)
  797.     *rptr++ = P_UINT(fib.fib_NumBlocks); // Kb of disk used by file
  798.     *rptr++ = P_UINT(0); // device # - pointless unless we allow re-exports
  799.  
  800.     if ((*rptr++ = lf->lf_FileID) <= 0) /* Should never happen */
  801.         printf("ERROR: Gave out inode %d for %s\n",
  802.             lf->lf_FileID, lf->lf_Name);
  803.  
  804.     /* We say that the file was creating, modified *and* used at the same
  805.         time - namely, the real last modification time */
  806.     struct nfstime ntime;
  807.     Unix_date(&(fib.fib_Date), &ntime);
  808.  
  809.     /* NFS uses unsigned values here, so we can't refer to anything before
  810.         1970. In fact, we're not checking that at the moment, so
  811.         problems would result if somebody tried it. */
  812.  
  813.     *rptr++ = P_UINT(ntime.seconds); // time of last access
  814.     *rptr++ = P_UINT(ntime.useconds);
  815.     *rptr++ = P_UINT(ntime.seconds); // time of last modification
  816.     *rptr++ = P_UINT(ntime.useconds);
  817.     *rptr++ = P_UINT(ntime.seconds); // time of last status change
  818.     *rptr++ = P_UINT(ntime.useconds);
  819.  
  820.     return rptr;
  821. }
  822.  
  823. /* Try and set the attributes of a file, taking a locked LocalFile structure
  824.     which may or may not be locked on return.
  825.     If one attribute is not properly set,
  826.     it will continue and try and set the others. You may consider this
  827.     to be wrong.
  828.     It assumes the file was Examine()'d beforehand, and will leave it
  829.     with an up-to-date examination afterwards.
  830.     You may optionally pass an open file handle which will be used.
  831. */
  832. static nfsstat set_attrs(struct LocalFile *lf, struct sattr *sa, BPTR handle)
  833. {
  834.     nfsstat status = NFS_OK;
  835.  
  836.     VERBOSE(printf("'%s' - desired attributes: %o %d %d %d (%d %d) (%d %d)\n",
  837.         lf->lf_Name,
  838.         sa->mode, sa->uid, sa->gid, sa->size,
  839.         sa->atime.seconds, sa->atime.useconds,
  840.         sa->mtime.seconds, sa->mtime.useconds));
  841.  
  842.     /* Only some attributes may need setting */
  843.     #define ISSET(x) ((x) != -1)
  844.  
  845.     /* Here we only change the protection bits we know about.
  846.         This means delete gets left alone. */
  847.     if (ISSET(sa->mode)) {
  848.         #define MASK (FIBF_READ | FIBF_WRITE | FIBF_EXECUTE \
  849.             | FIBF_GRP_READ | FIBF_GRP_WRITE \
  850.             | FIBF_GRP_EXECUTE | FIBF_OTR_READ \
  851.             | FIBF_OTR_WRITE | FIBF_OTR_EXECUTE)
  852.  
  853.         LONG prot = Amiga_prot(sa->mode);
  854.         prot &= MASK;
  855.         prot |= (fib.fib_Protection & (~MASK));
  856.  
  857.         /* That is, we take the old values for things we don't
  858.             concern ourselves with */
  859.  
  860.         if (!SetProtection(lf->lf_Name, prot)) {
  861.             PrintFault(IoErr(), "Unable to set protection bits");
  862.             status = NFS_err(IoErr());
  863.         }
  864.  
  865.         #undef MASK
  866.     }
  867.  
  868.     /* There has to be a better way of doing this bit... */
  869.     if (ISSET(sa->uid) || ISSET(sa->gid)) {
  870.         LONG owner = (fib.fib_OwnerUID << 16) | fib.fib_OwnerGID;
  871.  
  872.         if (ISSET(sa->uid))
  873.             owner = ((owner & 0x0000ffff) | (sa->uid << 16));
  874.  
  875.         if (ISSET(sa->gid))
  876.             owner = ((owner & 0xffff0000) | sa->gid);
  877.  
  878.         /* The ramdisk doesn't handle this in v39 */
  879.         if (!SetOwner(lf->lf_Name, owner)) {
  880.             PrintFault(IoErr(), "Unable to set ownership");
  881.             status = NFS_err(IoErr());
  882.         }
  883.     }
  884.  
  885.     /* Let's sort out the dates... */
  886.  
  887.     /* We simply ignore atime - the Amiga has no concept of it,
  888.         and any kludgy use runs the risk of creating subtle problems */
  889.  
  890.     struct nfstime *mt = &(sa->mtime);
  891.     if (ISSET(mt->seconds)) {
  892.         if (!ISSET(mt->useconds)) {
  893.             mt->useconds = 0;
  894.         }
  895.  
  896.         struct DateStamp ds;
  897.         Amiga_date(mt, &ds);
  898.         if (!SetFileDate(lf->lf_Name, &ds) && (status == NFS_OK)) {
  899.             PrintFault(IoErr(), "Unable to set date");
  900.             status = NFS_err(IoErr());
  901.         }
  902.     }
  903.  
  904.     /* Set the size - we may need to open the file */
  905.     if (ISSET(sa->size)) {
  906.         BOOL we_opened = FALSE;
  907.         if (!handle) {
  908.             we_opened = TRUE;
  909.             if (handle = OpenFromLock(lf->lf_Lock)) {
  910.                 lf->lf_Lock = NULL;
  911.  
  912.                 /* We possibly need to change the mode of the lock */
  913.                 ChangeMode(CHANGE_FH, handle, MODE_READWRITE);
  914.  
  915.                 /* If there's an error changing the mode, it will be
  916.                     reported later when we try and write */
  917.             }
  918.         }
  919.  
  920.         if (handle) {
  921.             if (-1 == SetFileSize(handle, sa->size, OFFSET_BEGINNING)) {
  922.                 PrintFault(IoErr(), "Unable to set file size");
  923.                 status = NFS_err(IoErr());
  924.             }
  925.             if (!ExamineFH(handle, &fib)) {
  926.                 PrintFault(IoErr(), "Unable to examine open file");
  927.                 status = NFS_err(IoErr());
  928.             }
  929.             if (we_opened)
  930.                 Close(handle);
  931.         } else {
  932.             /* Hmmm... is it an error to set the size of a directory? */
  933.             PrintFault(IoErr(), "Couldn't open file to set its length");
  934.             status = NFS_wt_err(NFSERR_ISDIR);
  935.         }
  936.     }
  937.  
  938.     #undef ISSET
  939.  
  940.     /* Examine the lock if we still have it, otherwise trust that
  941.         our last examination was correct */
  942.  
  943.     if (status == NFS_OK) {
  944.         if (lf->lf_Lock && !Examine(lf->lf_Lock, &fib))
  945.                 return NFS_err(IoErr());
  946.     }
  947.  
  948.     return status;
  949. }
  950.  
  951.  
  952. /* Seek in a file, extending it if necessary */
  953. static BOOL SeekWithExtend(BPTR handle, LONG offset)
  954. {
  955.     if (Seek(handle, offset, OFFSET_BEGINNING) != -1) {
  956.         return TRUE; /* It worked fine */
  957.     }
  958.  
  959.     /* If the write position is past the current EOF then
  960.         we need to extend it ourselves - DOS won't do it.
  961.        Thanks to Henryk Richter
  962.     */
  963.  
  964.     if (Seek(handle, 0, OFFSET_END) == -1) {
  965.         return FALSE;
  966.     }
  967.  
  968.     LONG position = Seek(handle, 0, OFFSET_CURRENT);
  969.  
  970.     /* Do we need to extend it? */
  971.     if (position < offset) {
  972.         if (offset != SetFileSize(handle, offset, OFFSET_BEGINNING))
  973.             return FALSE;
  974.  
  975.         Seek(handle, offset, OFFSET_BEGINNING);
  976.         position = Seek(handle, 0, OFFSET_CURRENT);
  977.     }
  978.  
  979.     return (position == offset);
  980. }
  981.  
  982.