All files / json-pack/src/nfs/v4/server Nfsv4CompoundProcCtx.ts

81.34% Statements 109/134
82.22% Branches 74/90
66.66% Functions 2/3
81.91% Lines 77/94

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140      25x 25x             25x   756x   756x     756x 756x                                       756x 756x 756x 756x 756x 756x 756x 1585x 1585x   1585x 1585x 1585x 1582x 1163x 1163x 1026x 943x 923x 893x 880x 876x 814x 596x 488x 462x 446x 444x 395x 332x 313x   313x   313x 3x 310x 5x 305x 303x 299x 299x   299x   299x 298x 298x 295x 189x 167x 154x 8x 7x 4x   4x 1585x 1585x   1585x 1585x 1568x   1568x 1568x 1568x   17x 17x                   17x 17x 17x 17x 17x                 17x 17x   1585x   756x      
import {Nfsv4Stat} from '../constants';
import type {Nfsv4OperationFn} from './operations/Nfsv4Operations';
import type {Nfsv4Connection} from './Nfsv4Connection';
import * as msg from '../messages';
import {formatNfsv4Request, formatNfsv4Response} from '../format';
 
/**
 * NFS v4 COMPOUND Procedure Context, holds state for a single COMPOUND procedure
 * call. This state is injected into each operation handler called as part of
 * the COMPOUND procedure.
 */
export class Nfsv4CompoundProcCtx {
  /** Current file handle */
  cfh: Uint8Array | null = null;
  /** Saved file handle */
  sfh: Uint8Array | null = null;
 
  constructor(
    public readonly connection: Nfsv4Connection,
    public readonly req: msg.Nfsv4CompoundRequest,
  ) {}
 
  /**
   * Returns the principal associated with the current RPC call. For now,
   * this is a stub returning "none" since we don't have real authentication.
   * In a real implementation, this would extract the principal from the RPC
   * credentials in the connection's current RPC call context.
   *
   * - AUTH_NONE -> `none`
   * - AUTH_SYS -> `sys:machinename:uid`
   * - GSS -> `gss:client@REALM`
   *
   * @returns The principal associated with the current RPC call.
   */
  public getPrincipal(): string {
    return 'none';
  }
 
  public async exec(): Promise<msg.Nfsv4CompoundResponse> {
    const {req, connection} = this;
    const {ops, debug, logger} = connection;
    const {argarray, tag} = req;
    const length = argarray.length;
    let status: Nfsv4Stat = Nfsv4Stat.NFS4_OK;
    const resarray: msg.Nfsv4Response[] = [];
    OPS_LOOP: for (let i = 0; i < length; i++) {
      const op = argarray[i];
      const opReq: msg.Nfsv4Request = op;
      type Res = msg.Nfsv4Response;
      let fn: Nfsv4OperationFn<any, any> | undefined = void 0;
      let Response: (new (status: Nfsv4Stat) => Res) | undefined = void 0;
      if (op instanceof msg.Nfsv4AccessRequest) (fn = ops.ACCESS), (Response = msg.Nfsv4AccessResponse);
      else if (op instanceof msg.Nfsv4PutrootfhRequest) (fn = ops.PUTROOTFH), (Response = msg.Nfsv4PutrootfhResponse);
      else Iif (op instanceof msg.Nfsv4PutpubfhRequest) (fn = ops.PUTPUBFH), (Response = msg.Nfsv4PutpubfhResponse);
      else if (op instanceof msg.Nfsv4PutfhRequest) (fn = ops.PUTFH), (Response = msg.Nfsv4PutfhResponse);
      else if (op instanceof msg.Nfsv4GetfhRequest) (fn = ops.GETFH), (Response = msg.Nfsv4GetfhResponse);
      else if (op instanceof msg.Nfsv4SavefhRequest) (fn = ops.SAVEFH), (Response = msg.Nfsv4SavefhResponse);
      else if (op instanceof msg.Nfsv4ReadRequest) (fn = ops.READ), (Response = msg.Nfsv4ReadResponse);
      else if (op instanceof msg.Nfsv4ReaddirRequest) (fn = ops.READDIR), (Response = msg.Nfsv4ReaddirResponse);
      else if (op instanceof msg.Nfsv4ReadlinkRequest) (fn = ops.READLINK), (Response = msg.Nfsv4ReadlinkResponse);
      else if (op instanceof msg.Nfsv4WriteRequest) (fn = ops.WRITE), (Response = msg.Nfsv4WriteResponse);
      else if (op instanceof msg.Nfsv4OpenRequest) (fn = ops.OPEN), (Response = msg.Nfsv4OpenResponse);
      else if (op instanceof msg.Nfsv4CloseRequest) (fn = ops.CLOSE), (Response = msg.Nfsv4CloseResponse);
      else if (op instanceof msg.Nfsv4RemoveRequest) (fn = ops.REMOVE), (Response = msg.Nfsv4RemoveResponse);
      else if (op instanceof msg.Nfsv4RenameRequest) (fn = ops.RENAME), (Response = msg.Nfsv4RenameResponse);
      else if (op instanceof msg.Nfsv4OpenattrRequest) (fn = ops.OPENATTR), (Response = msg.Nfsv4OpenattrResponse);
      else if (op instanceof msg.Nfsv4GetattrRequest) (fn = ops.GETATTR), (Response = msg.Nfsv4GetattrResponse);
      else if (op instanceof msg.Nfsv4SetattrRequest) (fn = ops.SETATTR), (Response = msg.Nfsv4SetattrResponse);
      else if (op instanceof msg.Nfsv4CreateRequest) (fn = ops.CREATE), (Response = msg.Nfsv4CreateResponse);
      else Iif (op instanceof msg.Nfsv4SetclientidRequest)
        (fn = ops.SETCLIENTID), (Response = msg.Nfsv4SetclientidResponse);
      else Iif (op instanceof msg.Nfsv4SetclientidConfirmRequest)
        (fn = ops.SETCLIENTID_CONFIRM), (Response = msg.Nfsv4SetclientidConfirmResponse);
      else if (op instanceof msg.Nfsv4OpenConfirmRequest)
        (fn = ops.OPEN_CONFIRM), (Response = msg.Nfsv4OpenConfirmResponse);
      else if (op instanceof msg.Nfsv4OpenDowngradeRequest)
        (fn = ops.OPEN_DOWNGRADE), (Response = msg.Nfsv4OpenDowngradeResponse);
      else if (op instanceof msg.Nfsv4CommitRequest) (fn = ops.COMMIT), (Response = msg.Nfsv4CommitResponse);
      else if (op instanceof msg.Nfsv4LinkRequest) (fn = ops.LINK), (Response = msg.Nfsv4LinkResponse);
      else Iif (op instanceof msg.Nfsv4RenewRequest) (fn = ops.RENEW), (Response = msg.Nfsv4RenewResponse);
      else Iif (op instanceof msg.Nfsv4DelegpurgeRequest)
        (fn = ops.DELEGPURGE), (Response = msg.Nfsv4DelegpurgeResponse);
      else Iif (op instanceof msg.Nfsv4DelegreturnRequest)
        (fn = ops.DELEGRETURN), (Response = msg.Nfsv4DelegreturnResponse);
      else if (op instanceof msg.Nfsv4RestorefhRequest) (fn = ops.RESTOREFH), (Response = msg.Nfsv4RestorefhResponse);
      else Iif (op instanceof msg.Nfsv4SecinfoRequest) (fn = ops.SECINFO), (Response = msg.Nfsv4SecinfoResponse);
      else if (op instanceof msg.Nfsv4VerifyRequest) (fn = ops.VERIFY), (Response = msg.Nfsv4VerifyResponse);
      else if (op instanceof msg.Nfsv4LockRequest) (fn = ops.LOCK), (Response = msg.Nfsv4LockResponse);
      else if (op instanceof msg.Nfsv4LocktRequest) (fn = ops.LOCKT), (Response = msg.Nfsv4LocktResponse);
      else if (op instanceof msg.Nfsv4LockuRequest) (fn = ops.LOCKU), (Response = msg.Nfsv4LockuResponse);
      else if (op instanceof msg.Nfsv4LookupRequest) (fn = ops.LOOKUP), (Response = msg.Nfsv4LookupResponse);
      else if (op instanceof msg.Nfsv4LookuppRequest) (fn = ops.LOOKUPP), (Response = msg.Nfsv4LookuppResponse);
      else if (op instanceof msg.Nfsv4NverifyRequest) (fn = ops.NVERIFY), (Response = msg.Nfsv4NverifyResponse);
      else Iif (op instanceof msg.Nfsv4ReleaseLockOwnerRequest)
        (fn = ops.RELEASE_LOCKOWNER), (Response = msg.Nfsv4ReleaseLockOwnerResponse);
      else if (op instanceof msg.Nfsv4IllegalRequest) (fn = ops.ILLEGAL), (Response = msg.Nfsv4IllegalResponse);
      Iif (!fn || !Response) return new msg.Nfsv4CompoundResponse(Nfsv4Stat.NFS4ERR_OP_ILLEGAL, tag, resarray);
      EXEC_OP: try {
        // if (debug) logger.log(fn.name, opReq);
        Iif (debug) logger.log(formatNfsv4Request(opReq));
        const opResponse = await fn.call(ops, opReq, this);
        Iif (!(opResponse instanceof Response)) throw new Error('Unexpected response, fn = ' + fn.name);
        // if (debug) logger.log(fn.name, opResponse);
        Iif (debug) logger.log(': ' + formatNfsv4Response(opResponse));
        status = opResponse.status;
        resarray.push(opResponse);
      } catch (err) {
        Iif (debug) logger.error(': ERROR', fn.name, err);
        Iif (err instanceof Response) {
          if (err.status !== Nfsv4Stat.NFS4_OK) {
            status = err.status;
            resarray.push(err);
            break EXEC_OP;
          } else {
            logger.error('Operation [' + fn.name + '] threw response with NFS4_OK');
            err = Nfsv4Stat.NFS4ERR_SERVERFAULT;
          }
        }
        FIND_STATUS_CODE: {
          if (typeof err === 'number') {
            if (err > Nfsv4Stat.NFS4_OK && err <= 0x00_ff_ff_ff) {
              status = err;
              break FIND_STATUS_CODE;
            }
            status = Nfsv4Stat.NFS4ERR_SERVERFAULT;
            logger.error('Invalid status [code = ' + err + ', fn = ' + fn.name + ']');
            break FIND_STATUS_CODE;
          }
          status = Nfsv4Stat.NFS4ERR_SERVERFAULT;
          logger.error(fn.name, err);
        }
        const opResponse = new Response(status);
        resarray.push(opResponse);
      }
      if (status !== Nfsv4Stat.NFS4_OK) break OPS_LOOP;
    }
    return new msg.Nfsv4CompoundResponse(status, tag, resarray);
  }
}