/* Copyright (c) 1992 Microsoft Corporation Module Name: afpapi.c Abstract: This module contains the AFP API Dispatcher. Author: Jameel Hyder (microsoft!jameelh) Revision History: 25 Apr 1992 Initial Version Notes: Tab stop: 4 --*/ #define FILENUM FILE_AFPAPI #include #include #include #include #include #ifdef ALLOC_PRAGMA #pragma alloc_text( PAGE, AfpStartApiProcessing) #endif /* * The following array is indexed by the AFP opcode. The rationale behind this * table is that the majority of codes are unused (> 200 out of 255). This * scheme makes the actual dispatch table much smaller at the cost of an extra * array look-up. */ LOCAL BYTE AfpOpCodeTable[256] = { /*00-02*/ _AFP_INVALID_OPCODE, _AFP_BYTE_RANGE_LOCK, _AFP_CLOSE_VOL, /*03-05*/ _AFP_CLOSE_DIR, _AFP_CLOSE_FORK, _AFP_COPY_FILE, /*06-08*/ _AFP_CREATE_DIR, _AFP_CREATE_FILE, _AFP_DELETE, /*09-0B*/ _AFP_ENUMERATE, _AFP_FLUSH, _AFP_FLUSH_FORK, /*0C-0E*/ _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, _AFP_GET_FORK_PARMS, /*0F-11*/ _AFP_GET_SRVR_INFO, _AFP_GET_SRVR_PARMS, _AFP_GET_VOL_PARMS, /*12-14*/ _AFP_LOGIN, _AFP_LOGIN_CONT, _AFP_LOGOUT, /*15-17*/ _AFP_MAP_ID, _AFP_MAP_NAME, _AFP_MOVE_AND_RENAME, /*18-1A*/ _AFP_OPEN_VOL, _AFP_OPEN_DIR, _AFP_OPEN_FORK, /*1B-1D*/ _AFP_READ, _AFP_RENAME, _AFP_SET_DIR_PARMS, /*1E-20*/ _AFP_SET_FILE_PARMS, _AFP_SET_FORK_PARMS, _AFP_SET_VOL_PARMS, /*21-23*/ _AFP_WRITE, _AFP_GET_FILE_DIR_PARMS,_AFP_SET_FILE_DIR_PARMS, /*24-26*/ _AFP_CHANGE_PASSWORD, _AFP_GET_USER_INFO, _AFP_GET_SRVR_MSG, /*27-29*/ _AFP_CREATE_ID, _AFP_DELETE_ID, _AFP_RESOLVE_ID, /*2A-2C*/ _AFP_EXCHANGE_FILES, _AFP_CAT_SEARCH, _AFP_INVALID_OPCODE, /*2D-2F*/ _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, /*30-32*/ _AFP_OPEN_DT, _AFP_CLOSE_DT, _AFP_INVALID_OPCODE, /*33-35*/ _AFP_GET_ICON, _AFP_GET_ICON_INFO, _AFP_ADD_APPL, /*36-38*/ _AFP_REMOVE_APPL, _AFP_GET_APPL, _AFP_ADD_COMMENT, /*39-3B*/ _AFP_REMOVE_COMMENT, _AFP_GET_COMMENT, _AFP_INVALID_OPCODE, /*3C-3E*/ _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, /*3F-41*/ _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, /*42-44*/ _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, /*45-47*/ _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, /*48-4A*/ _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, /*4B-4D*/ _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, /*4E-50*/ _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, /*51-53*/ _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, /*54-56*/ _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, /*57-59*/ _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, /*5A-5C*/ _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, /*5D-5F*/ _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, /*60-62*/ _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, /*63-65*/ _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, /*66-68*/ _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, /*69-6B*/ _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, /*6C-6E*/ _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, /*6F-71*/ _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, /*72-74*/ _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, /*75-77*/ _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, /*78-7A*/ _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, /*7B-7D*/ _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, /*7E-80*/ _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, /*81-83*/ _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, /*84-86*/ _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, /*87-89*/ _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, /*8A-8C*/ _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, /*8D-8F*/ _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, /*90-92*/ _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, /*93-95*/ _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, /*96-98*/ _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, /*99-9B*/ _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, /*9C-9E*/ _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, /*9F-A1*/ _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, /*A2-A4*/ _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, /*A5-A7*/ _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, /*A8-AA*/ _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, /*AB-AD*/ _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, /*AE-B0*/ _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, /*B1-B3*/ _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, /*B4-B6*/ _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, /*B7-B9*/ _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, /*BA-BC*/ _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, /*BD-BF*/ _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, /*C0-C2*/ _AFP_ADD_ICON, _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, /*C3-C5*/ _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, /*C6-C8*/ _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, /*C9-CB*/ _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, /*CC-CE*/ _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, /*CF-D1*/ _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, /*D2-D4*/ _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, /*D5-D7*/ _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, /*D8-DA*/ _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, /*DB-DD*/ _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, /*DE-E0*/ _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, /*E1-E3*/ _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, /*E4-E6*/ _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, /*E7-E9*/ _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, /*EA-EC*/ _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, /*ED-EF*/ _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, /*F0-F2*/ _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, /*F3-F5*/ _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, /*F6-F8*/ _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, /*F9-FB*/ _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, /*FC-FE*/ _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, _AFP_INVALID_OPCODE, /*FF*/ _AFP_GET_DOMAIN_LIST }; #if DBG PCHAR afpApiNames[] = { "AfpInvalidOpcode", "AfpUnsupportedOpcode", "AfpGetSrvrInfo", "AfpGetSrvrParms", "AfpChangePassword", "AfpLogin", "AfpLoginCont", "AfpLogout", "AfpMapId", "AfpMapName", "AfpGetUserInfo", "AfpGetSrvrMsg", "AfpGetDomainList", "AfpOpenVol", "AfpCloseVol", "AfpGetVolParms", "AfpSetVolParms", "AfpFlush", "AfpGetFileDirParms", "AfpSetFileDirParms", "AfpDelete", "AfpRename", "AfpMoveAndRename", "AfpOpenDir", "AfpCloseDir", "AfpCreateDir", "AfpEnumerate", "AfpSetDirParms", "AfpCreateFile", "AfpCopyFile", "AfpCreateId", "AfpDeleteId", "AfpResolveId", "AfpSetFileParms", "AfpExchangeFiles", "AfpOpenFork", "AfpCloseFork", "AfpFlushFork", "AfpRead", "AfpWrite", "AfpByteRangeLock", "AfpGetForkParms", "AfpSetForkParms", "AfpOpenDt", "AfpCloseDt", "AfpAddAppl", "AfpGetAppl", "AfpRemoveAppl", "AfpAddComment", "AfpGetComment", "AfpRemoveComment", "AfpAddIcon", "AfpGetIcon", "AfpGetIconInfo", "AfpCatSearch" }; #endif /* * The following structure is the API Dispatch table. The structure is indexed * by the _AFP code. Each entry consists of the routine address that handles * the request and/or dispatches to FSP, the fixed size of the request * packet and optionally three variable size packets. The fixed size request * packet is further split up into SEVEN fields. Each field is of the type * FLD_BYTE, FLD_WORD or FLD_DWRD. A field of the type FLD_WORD and FLD_DWRD * is converted from on-the-wire format to the internal format. An FLD_NONE * entry stops the scan for the fixed part of the request. * NamexType where x is 1,2,3 defines what type of variable size packets * follow. A NONE on any of the fields stops the parsing. A type of BLOCK * consumes the balance of the packet. Each of the variable size packets are * copied to the sda_Namex field which is defined as ANSI_STRING. For the * TYP_BLOCK field, the Length field of the ANSI_STRING defines the length * of the block. The motivation for this structure is to conserve memory. * Since a request packet is 578 bytes long and most APIs use only a small * subset of that, the fixed portion of the packet is copied to the SDA * and a smaller buffer is allocated for the variable packet. * The orignal buffer cannot be accessed once we return back from this call. */ // DO NOT CHANGE THE MANIFESTS BELOW BEFORE YOU CHECK THE CODE IN // AfpUnmarshallReq // Descriptor values for fixed data #define FLD_NONE 0x00 // Terminate #define FLD_BYTE sizeof(BYTE) // Byte field #define FLD_WORD sizeof(USHORT) // WORD field #define FLD_DWRD sizeof(DWORD) // DWORD field #define FLD_SIGNED 0x08 // The value is to be treated as a signed #define FLD_NON_ZERO 0x10 // The value cannot be zero #define FLD_CHECK_MASK 0x20 // Check against the mask in ReqPktMask #define FLD_NOCONV 0x40 // Skip conversion from on-the-wire to host #define FLD_NOPAD 0x80 // Do not EVEN align the next field #define FLD_PROP_MASK (FLD_SIGNED | \ FLD_NON_ZERO | \ FLD_CHECK_MASK | \ FLD_NOCONV | \ FLD_NOPAD) // Descriptor values for variable data #define TYP_NONE 0x00 // Terminate #define TYP_PATH 0x01 // AFPPATH -> ANSI_STRING #define TYP_STRING 0x02 // PASCALSTR -> ANSI_STRING #define TYP_BLK16 0x03 // Block of 16 bytes #define TYP_BLOCK 0x04 // Block of bytes #define TYP_NON_NULL 0x20 // The variable data cannot be null #define TYP_OPTIONAL 0x40 // This field can be optinal #define TYP_NOPAD 0x80 // Do not even align the next field #define TYP_PROP_MASK (TYP_NON_NULL | TYP_OPTIONAL | TYP_NOPAD) #define API_AFP21ONLY 0x01 // Valid only for AFP 2.1 clients #define API_SKIPLOGONVALIDATION 0x02 // Don't check if user is logged on #define API_NOSUBFUNCTION 0x04 // For the AfpLogin Function #define API_CHECK_VOLID 0x08 // This API reference volume #define API_CHECK_OFORKREFNUM 0x10 // This API reference open fork #define API_TYPE_WRITE 0x20 // This attempts a write #define API_QUEUE_IF_DPC 0x40 // This conditionally queues to worker only if at DPC #define API_MUST_BE_QUEUED 0x80 // The Api must be queued to the worker thread #define MAX_MASK_ENTRIES 4 // Max. bitmasks to validate LOCAL struct _DispatchTable { AFPAPIWORKER AfpWorkerRoutine; // Worker routine to call/queue BYTE AfpStatus; // Status to return on error // This has to be added to the base BYTE ApiOptions; // API_xxx values BYTE ReqPktDesc[MAX_REQ_ENTRIES]; // Fixed data desc BYTE NameXType[MAX_VAR_ENTRIES]; // Variable data desc USHORT ReqPktMask[MAX_MASK_ENTRIES]; // Valid values for bit-maps } AfpDispatchTable[_AFP_MAX_ENTRIES] = { /* 0x00 */ { AfpFsdDispInvalidFunc, (AFP_ERR_BASE - AFP_ERR_PARAM), 0, { FLD_NONE, FLD_NONE, FLD_NONE, FLD_NONE, FLD_NONE, FLD_NONE, FLD_NONE }, { TYP_NONE, TYP_NONE, TYP_NONE }, { 0, 0, 0, 0 } }, /* 0x01 */ { AfpFsdDispUnsupportedFunc, (AFP_ERR_BASE - AFP_ERR_PARAM), 0, { FLD_NONE, FLD_NONE, FLD_NONE, FLD_NONE, FLD_NONE, FLD_NONE, FLD_NONE }, { TYP_NONE, TYP_NONE, TYP_NONE }, { 0, 0, 0, 0 } }, /* SERVER APIs */ /* 0x02 */ { AfpFsdDispInvalidFunc, (AFP_ERR_BASE - AFP_ERR_PARAM), 0, { FLD_NONE, FLD_NONE, FLD_NONE, FLD_NONE, FLD_NONE, FLD_NONE, FLD_NONE }, { TYP_NONE, TYP_NONE, TYP_NONE }, { 0, 0, 0, 0 } }, /* 0x03 */ { AfpFsdDispGetSrvrParms, (AFP_ERR_BASE - AFP_ERR_PARAM), API_NOSUBFUNCTION, { FLD_NONE, FLD_NONE, FLD_NONE, FLD_NONE, FLD_NONE, FLD_NONE, FLD_NONE }, { TYP_NONE, TYP_NONE, TYP_NONE }, { 0, 0, 0, 0 } }, /* 0x04 */ { AfpFspDispChangePassword, (AFP_ERR_BASE - AFP_ERR_PARAM), API_SKIPLOGONVALIDATION+API_MUST_BE_QUEUED, { FLD_NONE, FLD_NONE, FLD_NONE, FLD_NONE, FLD_NONE, FLD_NONE, FLD_NONE }, { TYP_STRING+TYP_NON_NULL, // UAM Name TYP_STRING+TYP_NON_NULL, // User Name TYP_BLOCK+TYP_NON_NULL // UAM dependent info }, { 0, 0, 0, 0 } }, /* 0x05 */ { AfpFspDispLogin, (AFP_ERR_BASE - AFP_ERR_PARAM), API_SKIPLOGONVALIDATION+API_NOSUBFUNCTION+API_MUST_BE_QUEUED, { FLD_NONE, FLD_NONE, FLD_NONE, FLD_NONE, FLD_NONE, FLD_NONE, FLD_NONE }, { TYP_STRING+TYP_NOPAD+TYP_NON_NULL, // AFP Version TYP_STRING+TYP_NOPAD+TYP_NON_NULL, // UAM String TYP_BLOCK+TYP_NOPAD // UAM dependent data }, { 0, 0, 0, 0 } }, /* 0x06 */ { AfpFspDispLoginCont, (AFP_ERR_BASE - AFP_ERR_PARAM), API_SKIPLOGONVALIDATION+API_MUST_BE_QUEUED, { FLD_DWRD+FLD_NOCONV, // FLD_DWRD+FLD_NOCONV, // FLD_DWRD+FLD_NOCONV, // Response to Challenge FLD_DWRD+FLD_NOCONV, // FLD_DWRD+FLD_NOCONV, // FLD_DWRD+FLD_NOCONV, // FLD_NONE }, { TYP_NONE, TYP_NONE, TYP_NONE }, { 0, 0, 0, 0 } }, /* 0x07 */ { AfpFspDispLogout, (AFP_ERR_BASE - AFP_ERR_PARAM), API_NOSUBFUNCTION+API_MUST_BE_QUEUED, { FLD_NONE, FLD_NONE, FLD_NONE, FLD_NONE, FLD_NONE, FLD_NONE, FLD_NONE }, { TYP_NONE, TYP_NONE, TYP_NONE }, { 0, 0, 0, 0 } }, /* 0x08 */ { AfpFspDispMapId, (AFP_ERR_BASE - AFP_ERR_PARAM), API_MUST_BE_QUEUED, { FLD_DWRD, // User or Group Id FLD_NONE, FLD_NONE, FLD_NONE, FLD_NONE, FLD_NONE, FLD_NONE }, { TYP_NONE, TYP_NONE, TYP_NONE }, { 0, 0, 0, 0 } }, /* 0x09 */ { AfpFspDispMapName, (AFP_ERR_BASE - AFP_ERR_PARAM), API_MUST_BE_QUEUED, { FLD_NONE, FLD_NONE, FLD_NONE, FLD_NONE, FLD_NONE, FLD_NONE, FLD_NONE }, { TYP_STRING, // User or Group Name TYP_NONE, TYP_NONE }, { 0, 0, 0, 0 } }, /* 0x0A */ { AfpFspDispGetUserInfo, (AFP_ERR_BASE - AFP_ERR_PARAM), API_MUST_BE_QUEUED, { FLD_DWRD, // User Id FLD_WORD, // Bitmap FLD_NONE, FLD_NONE, FLD_NONE, FLD_NONE, FLD_NONE }, { TYP_NONE, TYP_NONE, TYP_NONE }, { 0, 0, 0, 0 } }, /* 0x0B */ { AfpFsdDispGetSrvrMsg, (AFP_ERR_BASE - AFP_ERR_PARAM), API_AFP21ONLY, { FLD_WORD, // Message Type FLD_WORD, // Mesage Bitmap FLD_NONE, FLD_NONE, FLD_NONE, FLD_NONE, FLD_NONE }, { TYP_NONE, TYP_NONE, TYP_NONE }, { 0, 0, 0, 0 } }, /* 0x0C */ { AfpFsdDispInvalidFunc, (AFP_ERR_BASE - AFP_ERR_PARAM), API_SKIPLOGONVALIDATION+API_MUST_BE_QUEUED, { FLD_NONE, FLD_NONE, FLD_NONE, FLD_NONE, FLD_NONE, FLD_NONE, FLD_NONE }, { TYP_NONE, TYP_NONE, TYP_NONE }, { 0, 0, 0, 0 } }, /* VOLUMEAPIs */ /* 0x0D */ { AfpFsdDispOpenVol, (AFP_ERR_BASE - AFP_ERR_PARAM), 0, { FLD_WORD+FLD_NON_ZERO+FLD_CHECK_MASK, // Bitmap FLD_NONE, FLD_NONE, FLD_NONE, FLD_NONE, FLD_NONE, FLD_NONE }, { TYP_STRING+TYP_NON_NULL, // Volume name TYP_BLOCK+TYP_OPTIONAL, // Volume password TYP_NONE }, { VOL_BITMAP_MASK, 0, 0, 0 } }, /* 0x0E */ { AfpFsdDispCloseVol, (AFP_ERR_BASE - AFP_ERR_PARAM), API_CHECK_VOLID, { FLD_WORD+FLD_NON_ZERO, // Volume Id FLD_NONE, FLD_NONE, FLD_NONE, FLD_NONE, FLD_NONE, FLD_NONE }, { TYP_NONE, TYP_NONE, TYP_NONE }, { 0, 0, 0, 0 } }, /* 0x0F */ { AfpFsdDispGetVolParms, (AFP_ERR_BASE - AFP_ERR_PARAM), API_CHECK_VOLID, { FLD_WORD+FLD_NON_ZERO, // Volume_Id FLD_WORD+FLD_NON_ZERO+FLD_CHECK_MASK, // Bitmap FLD_NONE, FLD_NONE, FLD_NONE, FLD_NONE, FLD_NONE }, { TYP_NONE, TYP_NONE, TYP_NONE }, { 0, VOL_BITMAP_MASK, 0, 0 } }, /* 0x10 */ { AfpFsdDispSetVolParms, (AFP_ERR_BASE - AFP_ERR_PARAM), API_CHECK_VOLID+API_TYPE_WRITE, { FLD_WORD+FLD_NON_ZERO, // Volume_Id FLD_WORD+FLD_NON_ZERO+FLD_CHECK_MASK, // Bitmap FLD_DWRD, // Backup date FLD_NONE, FLD_NONE, FLD_NONE, FLD_NONE }, { TYP_NONE, TYP_NONE, TYP_NONE }, { 0, VOL_BITMAP_BACKUPTIME, 0, 0 } }, /* 0x11 */ { AfpFsdDispFlush, (AFP_ERR_BASE - AFP_ERR_PARAM), API_CHECK_VOLID, { FLD_WORD+FLD_NON_ZERO, // Volume_Id FLD_NONE, FLD_NONE, FLD_NONE, FLD_NONE, FLD_NONE, FLD_NONE }, { TYP_NONE, TYP_NONE, TYP_NONE }, { 0, 0, 0, 0 } }, /* FILE-DIRECTORY APIs */ /* 0x12 */ { AfpFspDispGetFileDirParms, (AFP_ERR_BASE - AFP_ERR_PARAM), API_CHECK_VOLID+API_MUST_BE_QUEUED, { FLD_WORD+FLD_NON_ZERO, // Volume_Id FLD_DWRD+FLD_NON_ZERO, // Directory Id FLD_WORD+FLD_CHECK_MASK, // File Bitmap FLD_WORD+FLD_CHECK_MASK, // Directory Bitmap FLD_NONE, FLD_NONE, FLD_NONE }, { TYP_PATH, // Path TYP_NONE, TYP_NONE }, { 0, 0, FILE_BITMAP_MASK, DIR_BITMAP_MASK } }, /* 0x13 */ { AfpFspDispSetFileDirParms, (AFP_ERR_BASE - AFP_ERR_PARAM), API_CHECK_VOLID+API_TYPE_WRITE+API_MUST_BE_QUEUED, { FLD_WORD+FLD_NON_ZERO, // Volume_Id FLD_DWRD+FLD_NON_ZERO, // Directory Id FLD_WORD+FLD_NON_ZERO+FLD_CHECK_MASK, // File or Directory Bitmap FLD_NONE, FLD_NONE, FLD_NONE, FLD_NONE }, { TYP_PATH, // Path TYP_BLOCK+TYP_NON_NULL, // Parameters (packed) TYP_NONE }, { 0, 0, FD_VALID_SET_PARMS, 0 } }, /* 0x14 */ { AfpFspDispDelete, (AFP_ERR_BASE - AFP_ERR_PARAM), API_CHECK_VOLID+API_TYPE_WRITE+API_MUST_BE_QUEUED, { FLD_WORD+FLD_NON_ZERO, // Volume_Id FLD_DWRD+FLD_NON_ZERO, // Directory Id FLD_NONE, FLD_NONE, FLD_NONE, FLD_NONE, FLD_NONE }, { TYP_PATH, // Path TYP_NONE, TYP_NONE }, { 0, 0, 0, 0 } }, /* 0x15 */ { AfpFspDispRename, (AFP_ERR_BASE - AFP_ERR_PARAM), API_CHECK_VOLID+API_TYPE_WRITE+API_MUST_BE_QUEUED, { FLD_WORD+FLD_NON_ZERO, // Volume_Id FLD_DWRD+FLD_NON_ZERO, // Directory Id FLD_NONE, FLD_NONE, FLD_NONE, FLD_NONE, FLD_NONE }, { TYP_PATH+TYP_NOPAD, // Path TYP_PATH+TYP_NOPAD+TYP_NON_NULL, // New Name TYP_NONE }, { 0, 0, 0, 0 } }, /* 0x16 */ { AfpFspDispMoveAndRename, (AFP_ERR_BASE - AFP_ERR_PARAM), API_CHECK_VOLID+API_TYPE_WRITE+API_MUST_BE_QUEUED, { FLD_WORD+FLD_NON_ZERO, // Volume_Id FLD_DWRD+FLD_NON_ZERO, // Src Directory Id FLD_DWRD+FLD_NON_ZERO, // Dst Directory Id FLD_NONE, FLD_NONE, FLD_NONE, FLD_NONE }, { TYP_PATH+TYP_NOPAD, // Source path TYP_PATH+TYP_NOPAD, // Destination path TYP_PATH+TYP_NOPAD // New Name (optional) }, { 0, 0, 0, 0 } }, /* DIRECTORY APIs */ /* 0x17 */ { AfpFspDispOpenDir, (AFP_ERR_BASE - AFP_ERR_PARAM), API_CHECK_VOLID+API_MUST_BE_QUEUED, { FLD_WORD+FLD_NON_ZERO, // Volume_Id FLD_DWRD+FLD_NON_ZERO, // Directory Id FLD_NONE, FLD_NONE, FLD_NONE, FLD_NONE, FLD_NONE }, { TYP_PATH+TYP_NON_NULL, // Directory Name TYP_NONE, TYP_NONE }, { 0, 0, 0, 0 } }, /* 0x18 */ { AfpFspDispCloseDir, (AFP_ERR_BASE - AFP_ERR_PARAM), API_CHECK_VOLID+API_MUST_BE_QUEUED, { FLD_WORD+FLD_NON_ZERO, // Volume_Id FLD_DWRD+FLD_NON_ZERO, // Directory Id FLD_NONE, FLD_NONE, FLD_NONE, FLD_NONE, FLD_NONE }, { TYP_NONE, TYP_NONE, TYP_NONE }, { 0, 0, 0, 0 } }, /* 0x19 */ { AfpFspDispCreateDir, (AFP_ERR_BASE - AFP_ERR_PARAM), API_CHECK_VOLID+API_TYPE_WRITE+API_MUST_BE_QUEUED, { FLD_WORD+FLD_NON_ZERO, // Volume_Id FLD_DWRD+FLD_NON_ZERO, // Directory Id FLD_NONE, FLD_NONE, FLD_NONE, FLD_NONE, FLD_NONE }, { TYP_PATH+TYP_NON_NULL, // Directory Name TYP_NONE, TYP_NONE }, { 0, 0, 0, 0 } }, /* 0x1A */ { AfpFspDispEnumerate, (AFP_ERR_BASE - AFP_ERR_PARAM), API_CHECK_VOLID+API_MUST_BE_QUEUED, { FLD_WORD+FLD_NON_ZERO, // Volume_Id FLD_DWRD+FLD_NON_ZERO, // Directory Id FLD_WORD+FLD_CHECK_MASK, // File Bitmap FLD_WORD+FLD_CHECK_MASK, // Directory Bitmap FLD_WORD+FLD_SIGNED+FLD_NON_ZERO, // ReqCount FLD_WORD+FLD_SIGNED+FLD_NON_ZERO, // Start Index FLD_WORD+FLD_SIGNED+FLD_NON_ZERO, // ReplySize }, { TYP_PATH, // Path to directory TYP_NONE, TYP_NONE }, { 0, 0, FILE_BITMAP_MASK, DIR_BITMAP_MASK } }, /* 0x1B */ { AfpFspDispSetDirParms, (AFP_ERR_BASE - AFP_ERR_PARAM), API_CHECK_VOLID+API_TYPE_WRITE+API_MUST_BE_QUEUED, { FLD_WORD+FLD_NON_ZERO, // Volume_Id FLD_DWRD+FLD_NON_ZERO, // Directory Id FLD_WORD+FLD_NON_ZERO+FLD_CHECK_MASK, // Dir Bitmap FLD_NONE, FLD_NONE, FLD_NONE, FLD_NONE }, { TYP_PATH, // Path TYP_BLOCK+TYP_NON_NULL, // Parameters (packed) TYP_NONE }, { 0, 0, DIR_VALID_SET_PARMS, 0 } }, /* FILE APIs */ /* 0x1C */ { AfpFspDispCreateFile, (AFP_ERR_BASE - AFP_ERR_PARAM), API_CHECK_VOLID+API_TYPE_WRITE+API_MUST_BE_QUEUED, { FLD_WORD+FLD_NON_ZERO, // Volume_Id FLD_DWRD+FLD_NON_ZERO, // Directory Id FLD_NONE, FLD_NONE, FLD_NONE, FLD_NONE, FLD_NONE }, { TYP_PATH+TYP_NON_NULL, // Path TYP_NONE, TYP_NONE }, { 0, 0, 0, 0 } }, /* 0x1D */ { AfpFspDispCopyFile, (AFP_ERR_BASE - AFP_ERR_PARAM), API_CHECK_VOLID+API_MUST_BE_QUEUED, { FLD_WORD+FLD_NON_ZERO, // Src Volume_Id FLD_DWRD+FLD_NON_ZERO, // Src Directory Id FLD_WORD+FLD_NON_ZERO, // Dst Volume_Id FLD_DWRD+FLD_NON_ZERO, // Dst Directory Id FLD_NONE, FLD_NONE, FLD_NONE }, { TYP_PATH+TYP_NOPAD+TYP_NON_NULL, // Src Path TYP_PATH+TYP_NOPAD, TYP_PATH+TYP_NOPAD }, { 0, 0, 0, 0 } }, /* 0x1E */ { AfpFspDispCreateId, (AFP_ERR_BASE - AFP_ERR_OBJECT_TYPE), API_AFP21ONLY+API_CHECK_VOLID+API_MUST_BE_QUEUED, { FLD_WORD+FLD_NON_ZERO, // Volume_Id FLD_DWRD+FLD_NON_ZERO, // Directory Id FLD_NONE, FLD_NONE, FLD_NONE, FLD_NONE, FLD_NONE }, { TYP_PATH+TYP_NON_NULL, // Path TYP_NONE, TYP_NONE }, { 0, 0, 0, 0 } }, /* 0x1F */ { AfpFspDispDeleteId, (AFP_ERR_BASE - AFP_ERR_PARAM), API_AFP21ONLY+API_CHECK_VOLID+API_MUST_BE_QUEUED+API_TYPE_WRITE, { FLD_WORD+FLD_NON_ZERO, // Volume_Id FLD_DWRD+FLD_NON_ZERO, // File Id FLD_NONE, FLD_NONE, FLD_NONE, FLD_NONE, FLD_NONE }, { TYP_NONE, TYP_NONE, TYP_NONE }, { 0, 0, 0, 0 } }, /* 0x20 */ { AfpFspDispResolveId, (AFP_ERR_BASE - AFP_ERR_PARAM), API_AFP21ONLY+API_CHECK_VOLID+API_MUST_BE_QUEUED, { FLD_WORD+FLD_NON_ZERO, // Volume_Id FLD_DWRD, // File Id FLD_WORD+FLD_CHECK_MASK, // Bitmap FLD_NONE, FLD_NONE, FLD_NONE, FLD_NONE }, { TYP_NONE, TYP_NONE, TYP_NONE }, { 0, 0, FILE_BITMAP_MASK, 0 } }, /* 0x21 */ { AfpFspDispSetFileParms, (AFP_ERR_BASE - AFP_ERR_PARAM), API_CHECK_VOLID+API_TYPE_WRITE+API_MUST_BE_QUEUED, { FLD_WORD+FLD_NON_ZERO, // Volume_Id FLD_DWRD+FLD_NON_ZERO, // Directory Id FLD_WORD+FLD_NON_ZERO+FLD_CHECK_MASK, // File Bitmap FLD_NONE, FLD_NONE, FLD_NONE, FLD_NONE }, { TYP_PATH+TYP_NON_NULL, // Path TYP_BLOCK+TYP_NON_NULL, // Parameters (packed) TYP_NONE }, { 0, 0, FILE_VALID_SET_PARMS, 0 } }, /* 0x22 */ { AfpFspDispExchangeFiles, (AFP_ERR_BASE - AFP_ERR_PARAM), API_CHECK_VOLID+API_TYPE_WRITE+API_MUST_BE_QUEUED+API_AFP21ONLY, { FLD_WORD+FLD_NON_ZERO, // Volume_Id FLD_DWRD+FLD_NON_ZERO, // Srce. Directory Id FLD_DWRD+FLD_NON_ZERO, // Dest. Directory Id FLD_NONE, FLD_NONE, FLD_NONE, FLD_NONE }, { TYP_PATH+TYP_NOPAD+TYP_NON_NULL, // Srce. Path TYP_PATH+TYP_NOPAD+TYP_NON_NULL, // Dest. Path TYP_NONE }, { 0, 0, 0, 0 } }, /* FORK APIs */ /* 0x23 */ { AfpFspDispOpenFork, (AFP_ERR_BASE - AFP_ERR_PARAM), API_CHECK_VOLID+API_MUST_BE_QUEUED, { FLD_WORD+FLD_NON_ZERO, // Volume_Id FLD_DWRD+FLD_NON_ZERO, // Directory Id FLD_WORD+FLD_CHECK_MASK, // Bitmap FLD_WORD, // Access & Deny Modes FLD_NONE, FLD_NONE, FLD_NONE }, { TYP_PATH+TYP_NON_NULL, // Path TYP_NONE, TYP_NONE }, { 0, 0, FILE_BITMAP_MASK, 0 } }, /* 0x24 */ { AfpFspDispCloseFork, (AFP_ERR_BASE - AFP_ERR_PARAM), API_CHECK_OFORKREFNUM+API_MUST_BE_QUEUED, { FLD_WORD+FLD_NON_ZERO, // Fork_Id FLD_NONE, FLD_NONE, FLD_NONE, FLD_NONE, FLD_NONE, FLD_NONE }, { TYP_NONE, TYP_NONE, TYP_NONE }, { 0, 0, 0, 0 } }, /* 0x25 */ { AfpFspDispFlushFork, (AFP_ERR_BASE - AFP_ERR_PARAM), API_CHECK_OFORKREFNUM+API_MUST_BE_QUEUED, { FLD_WORD+FLD_NON_ZERO, // Fork_Id FLD_NONE, FLD_NONE, FLD_NONE, FLD_NONE, FLD_NONE, FLD_NONE }, { TYP_NONE, TYP_NONE, TYP_NONE }, { 0, 0, 0, 0 } }, /* 0x26 */ { AfpFspDispRead, (AFP_ERR_BASE - AFP_ERR_PARAM), API_CHECK_OFORKREFNUM+API_QUEUE_IF_DPC+API_MUST_BE_QUEUED, { FLD_WORD+FLD_NON_ZERO, // Fork_Id FLD_DWRD, // Offset FLD_DWRD, // ReqCount FLD_BYTE+FLD_NOPAD, // Newline Mask FLD_BYTE+FLD_NOPAD, // Newline Char FLD_NONE, FLD_NONE }, { TYP_NONE, TYP_NONE, TYP_NONE }, { 0, 0, 0, 0 } }, /* 0x27 */ { AfpFspDispWrite, (AFP_ERR_BASE - AFP_ERR_PARAM), API_CHECK_OFORKREFNUM+API_TYPE_WRITE+API_QUEUE_IF_DPC+API_MUST_BE_QUEUED, { FLD_WORD+FLD_NON_ZERO, // Fork_Id FLD_DWRD, // Offset FLD_DWRD, // Length FLD_NONE, FLD_NONE, FLD_NONE, FLD_NONE }, { TYP_NONE, TYP_NONE, TYP_NONE }, { 0, 0, 0, 0 } }, /* 0x28 */ { AfpFspDispByteRangeLock, (AFP_ERR_BASE - AFP_ERR_PARAM), API_CHECK_OFORKREFNUM+API_QUEUE_IF_DPC+API_MUST_BE_QUEUED, { FLD_WORD+FLD_NON_ZERO, // Fork_Id FLD_DWRD, // Offset FLD_DWRD, // Length FLD_NONE, FLD_NONE, FLD_NONE, FLD_NONE }, { TYP_NONE, TYP_NONE, TYP_NONE }, { 0, 0, 0, 0 } }, /* 0x29 */ { AfpFspDispGetForkParms, (AFP_ERR_BASE - AFP_ERR_PARAM), API_CHECK_OFORKREFNUM+API_MUST_BE_QUEUED, { FLD_WORD+FLD_NON_ZERO, // Fork_Id FLD_WORD+FLD_NON_ZERO+FLD_CHECK_MASK, // Bitmap FLD_NONE, FLD_NONE, FLD_NONE, FLD_NONE, FLD_NONE }, { TYP_NONE, TYP_NONE, TYP_NONE }, { 0, FILE_BITMAP_MASK, 0, 0 } }, /* 0x2A */ { AfpFspDispSetForkParms, (AFP_ERR_BASE - AFP_ERR_PARAM), API_CHECK_OFORKREFNUM+API_TYPE_WRITE+API_MUST_BE_QUEUED, { FLD_WORD+FLD_NON_ZERO, // Fork_Id FLD_WORD+FLD_NON_ZERO+FLD_CHECK_MASK, // Bitmap FLD_DWRD, // Fork Length FLD_NONE, FLD_NONE, FLD_NONE, FLD_NONE }, { TYP_NONE, TYP_NONE, TYP_NONE }, { 0, FILE_BITMAP_DATALEN+FILE_BITMAP_RESCLEN, 0, 0 } }, /* DESKTOP APIs */ /* 0x2B */ { AfpFsdDispOpenDT, (AFP_ERR_BASE - AFP_ERR_PARAM), API_CHECK_VOLID, { FLD_WORD+FLD_NON_ZERO, // Volume_Id FLD_NONE, FLD_NONE, FLD_NONE, FLD_NONE, FLD_NONE, FLD_NONE }, { TYP_NONE, TYP_NONE, TYP_NONE }, { 0, 0, 0, 0 } }, /* 0x2C */ { AfpFsdDispCloseDT, (AFP_ERR_BASE - AFP_ERR_PARAM), API_CHECK_VOLID, { FLD_WORD+FLD_NON_ZERO, // DTRefNum (same as VolId) FLD_NONE, FLD_NONE, FLD_NONE, FLD_NONE, FLD_NONE, FLD_NONE }, { TYP_NONE, TYP_NONE, TYP_NONE }, { 0, 0, 0, 0 } }, /* 0x2D */ { AfpFspDispAddAppl, (AFP_ERR_BASE - AFP_ERR_OBJECT_TYPE), API_CHECK_VOLID+API_TYPE_WRITE+API_MUST_BE_QUEUED, { FLD_WORD+FLD_NON_ZERO, // DTRefNum (same as VolId) FLD_DWRD+FLD_NON_ZERO, // Directory Id FLD_DWRD+FLD_NOCONV, // Creator FLD_DWRD, // Appl Tag FLD_NONE, FLD_NONE, FLD_NONE }, { TYP_PATH+TYP_NON_NULL, // Path TYP_NONE, TYP_NONE }, { 0, 0, 0, 0 } }, /* 0x2E */ { AfpFspDispGetAppl, (AFP_ERR_BASE - AFP_ERR_PARAM), API_CHECK_VOLID+API_MUST_BE_QUEUED, { FLD_WORD+FLD_NON_ZERO, // DTRefNum (same as VolId) FLD_DWRD+FLD_NOCONV, // Creator FLD_WORD, // Appl Index FLD_WORD+FLD_CHECK_MASK, // Bitmap FLD_NONE, FLD_NONE, FLD_NONE }, { TYP_NONE, TYP_NONE, TYP_NONE }, { 0, 0, 0, FILE_BITMAP_MASK } }, /* 0x2F */ { AfpFspDispRemoveAppl, (AFP_ERR_BASE - AFP_ERR_ITEM_NOT_FOUND), API_CHECK_VOLID+API_TYPE_WRITE+API_MUST_BE_QUEUED, { FLD_WORD+FLD_NON_ZERO, // DTRefNum (same as VolId) FLD_DWRD+FLD_NON_ZERO, // Directory Id FLD_DWRD+FLD_NOCONV, // Creator FLD_NONE, FLD_NONE, FLD_NONE, FLD_NONE }, { TYP_PATH+TYP_NON_NULL, // Path TYP_NONE, TYP_NONE }, { 0, 0, 0, 0 } }, /* 0x30 */ { AfpFspDispAddComment, (AFP_ERR_BASE - AFP_ERR_PARAM), API_CHECK_VOLID+API_TYPE_WRITE+API_MUST_BE_QUEUED, { FLD_WORD+FLD_NON_ZERO, // DTRefNum (same as VolId) FLD_DWRD+FLD_NON_ZERO, // Directory Id FLD_NONE, FLD_NONE, FLD_NONE, FLD_NONE, FLD_NONE }, { TYP_PATH, TYP_STRING, TYP_NONE }, { 0, 0, 0, 0 } }, /* 0x31 */ { AfpFspDispGetComment, (AFP_ERR_BASE - AFP_ERR_PARAM), API_CHECK_VOLID+API_MUST_BE_QUEUED, { FLD_WORD+FLD_NON_ZERO, // DTRefNum (same as VolId) FLD_DWRD+FLD_NON_ZERO, // Directory Id FLD_NONE, FLD_NONE, FLD_NONE, FLD_NONE, FLD_NONE }, { TYP_PATH, TYP_NONE, TYP_NONE }, { 0, 0, 0, 0 } }, /* 0x32 */ { AfpFspDispRemoveComment, (AFP_ERR_BASE - AFP_ERR_PARAM), API_CHECK_VOLID+API_TYPE_WRITE+API_MUST_BE_QUEUED, { FLD_WORD+FLD_NON_ZERO, // DTRefNum (same as VolId) FLD_DWRD+FLD_NON_ZERO, // Directory Id FLD_NONE, FLD_NONE, FLD_NONE, FLD_NONE, FLD_NONE }, { TYP_PATH, TYP_NONE, TYP_NONE }, { 0, 0, 0, 0 } }, /* 0x33 */ { AfpFspDispAddIcon, (AFP_ERR_BASE - AFP_ERR_PARAM), API_CHECK_VOLID+API_MUST_BE_QUEUED, { FLD_WORD+FLD_NON_ZERO, // DTRefNum (same as VolId) FLD_DWRD+FLD_NOCONV, // Creator FLD_DWRD+FLD_NOCONV, // Type FLD_BYTE, // IconType FLD_DWRD, // IconTag FLD_WORD+FLD_SIGNED, // Icon Size FLD_NONE, }, { TYP_NONE, TYP_NONE, TYP_NONE }, { 0, 0, 0, 0 } }, /* 0x34 */ { AfpFspDispGetIcon, (AFP_ERR_BASE - AFP_ERR_PARAM), API_CHECK_VOLID+API_MUST_BE_QUEUED, { FLD_WORD+FLD_NON_ZERO, // DTRefNum (same as VolId) FLD_DWRD+FLD_NOCONV, // Creator FLD_DWRD+FLD_NOCONV, // Type FLD_BYTE, // IconType FLD_WORD+FLD_SIGNED, // Length FLD_NONE, FLD_NONE }, { TYP_NONE, TYP_NONE, TYP_NONE }, { 0, 0, 0, 0 } }, /* 0x35 */ { AfpFspDispGetIconInfo, (AFP_ERR_BASE - AFP_ERR_PARAM), API_CHECK_VOLID+API_MUST_BE_QUEUED, { FLD_WORD+FLD_NON_ZERO, // DTRefNum (same as VolId) FLD_DWRD+FLD_NOCONV, // Creator FLD_WORD, // IconIndex FLD_NONE, FLD_NONE, FLD_NONE, FLD_NONE }, { TYP_NONE, TYP_NONE, TYP_NONE }, { 0, 0, 0, 0 } }, /* 0x36 */ { AfpFspDispCatSearch, (AFP_ERR_BASE - AFP_ERR_PARAM), API_CHECK_VOLID+API_MUST_BE_QUEUED+API_AFP21ONLY, { FLD_WORD+FLD_NON_ZERO, // Volume_Id FLD_DWRD+FLD_NON_ZERO, // Requested # of matches FLD_DWRD, // Reserved FLD_NONE, FLD_NONE, FLD_NONE, FLD_NONE }, { TYP_BLK16+TYP_NON_NULL, // Catalog position TYP_BLOCK+TYP_NON_NULL, // The rest of the stuff TYP_NONE }, { 0, 0, 0, 0 } } }; /*** AfpFsdDispInvalidFunc * * This handles invalid AFP functions. */ AFPSTATUS FASTCALL AfpFsdDispInvalidFunc( IN PSDA pSda ) { return AFP_ERR_PARAM; } /*** AfpFsdDispUnsupportedFunc * * This handles un-supported AFP functions. */ AFPSTATUS FASTCALL AfpFsdDispUnsupportedFunc( IN PSDA pSda ) { return AFP_ERR_CALL_NOT_SUPPORTED; } /*** AfpUnmarshallReq * * The request completion routine has determined the session that this * request initiated from. Determine if this session is currently being * serviced. If not, the request packet is then broken down as follows. * * Afp function code -> pSda->sda_AfpFunc * Afp SubFunc code -> pSda->sda_AfpSubFunc * Fixed part of the * Api request parms -> pSda->sda_ReqBlock each field is converted to a * dword from the on-the-wire format to the host * format. Dictated by the table above. * Variable part -> pSda->sda_Name1-3 as appropriate. Dictated by the * table above. AFPPATH, BLOCK and PASCALSTR are * all converted to ANSI_STRING. * * Buffers for sda_Namex is allocated out of NonPagedPool, if it cannot * fit into sda_NameXSpace. * * A whole lot of book keeping is also done here. API statistics are maintained * here and when the reply is posted. * * If there is no error, then the following possible error codes result: * AFP_ERR_NONE The dispatch level worker can be called * AFP_ERR_QUEUE The request must be queued * AFP_ERR_DEFER The request must be deferred * AFP_ERR_xxxxx Appropriate error code * * NOTE: This is called within ReceiveCompletion and hence at DISPATCH_LEVEL. */ VOID FASTCALL AfpUnmarshallReq( IN PSDA pSda ) { LONG StrSize, Offset, i; LONG NameOff = 0, SpaceLeft; PREQUEST pRequest; LONG RequestSize; PBYTE pRequestBuf; USHORT WriteSize = 0; PBYTE pWriteBuf = NULL; AFPSTATUS Status; BYTE ApiCode; LONG BytesToCopy; struct _DispatchTable *pDispTab; struct _RequestPacket { BYTE _Function; BYTE _SubFunc; BYTE _OtherParms; } *pRqPkt; #ifdef PROFILING static TIME TimeLastRequest = { 0, 0 }; TIME TimeS, TimeD, TimeE; AfpGetPerfCounter(&TimeS); #endif ASSERT (VALID_SDA(pSda)); ASSERT (pSda->sda_Flags & SDA_REQUEST_IN_PROCESS); ASSERT (pSda->sda_Request != NULL); pRequest = pSda->sda_Request; RequestSize = pRequest->rq_RequestSize; pRequestBuf = pRequest->rq_RequestBuf; ASSERT (pRequestBuf != NULL); pRqPkt = (struct _RequestPacket *)pRequestBuf; if (pRequest->rq_WriteMdl != NULL) { // if Mdl (and the buffer) was allocated by us, find the buffer if (pRequest->rq_CacheMgrContext == NULL) { pWriteBuf = MmGetSystemAddressForMdlSafe( pRequest->rq_WriteMdl, NormalPagePriority); if (pWriteBuf == NULL) { Status = AFP_ERR_MISC; ASSERT(0); goto AfpUnmarshallReq_ErrExit; } } WriteSize = (USHORT)AfpMdlChainSize(pRequest->rq_WriteMdl); } else { ASSERT(pRequest->rq_CacheMgrContext == NULL); } ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL); #ifdef PROFILING ACQUIRE_SPIN_LOCK_AT_DPC(&AfpStatisticsLock); if (TimeLastRequest.QuadPart != 0) { TimeD.QuadPart = TimeS.QuadPart - TimeLastRequest.QuadPart; AfpServerProfile->perf_InterReqTime.QuadPart += TimeD.QuadPart; AfpServerProfile->perf_ReqCount ++; } TimeLastRequest.QuadPart = TimeS.QuadPart; RELEASE_SPIN_LOCK_FROM_DPC(&AfpStatisticsLock); #endif do { Offset = FIELD_OFFSET(struct _RequestPacket, _OtherParms); #ifdef PROFILING AfpGetPerfCounter(&pSda->sda_ApiStartTime); #endif INTERLOCKED_ADD_STATISTICS(&AfpServerStatistics.stat_DataIn, RequestSize + WriteSize, &AfpStatisticsLock); ACQUIRE_SPIN_LOCK_AT_DPC(&pSda->sda_Lock); // Send a dummy reply if we are shutting down the server or the session // Also the request better be atleast the minimum size if ((pSda->sda_Flags & SDA_CLOSING) || (AfpServerState & AFP_STATE_STOP_PENDING) || (RequestSize < sizeof(pRqPkt->_Function))) { // Set a function code so that we know what statictics to update at // reply time pSda->sda_AfpFunc = _AFP_INVALID_OPCODE; RELEASE_SPIN_LOCK_FROM_DPC(&pSda->sda_Lock); Status = AFP_ERR_PARAM; break; } ApiCode = AfpOpCodeTable[pRqPkt->_Function]; // Translate the function code to what we understand pDispTab = &AfpDispatchTable[ApiCode]; DBGPRINT(DBG_COMP_AFPAPI, DBG_LEVEL_INFO, ("AfpUnmarshallRequest: <%s>\n", afpApiNames[ApiCode])); if (!(pSda->sda_Flags & SDA_USER_LOGGEDIN)) { if (!(pDispTab->ApiOptions & API_SKIPLOGONVALIDATION)) { Status = AFP_ERR_USER_NOT_AUTH; if (pSda->sda_Flags & SDA_LOGIN_FAILED) Status = AFP_ERR_PWD_NEEDS_CHANGE; RELEASE_SPIN_LOCK_FROM_DPC(&pSda->sda_Lock); break; } } ASSERT (pDispTab->AfpWorkerRoutine != NULL); // Initialize the worker routine pSda->sda_WorkerRoutine = pDispTab->AfpWorkerRoutine; // Check if this is an AFP 2.1 request and if we are in a position to honor it. if ((pDispTab->ApiOptions & API_AFP21ONLY) && (pSda->sda_ClientVersion < AFP_VER_21)) { RELEASE_SPIN_LOCK_FROM_DPC(&pSda->sda_Lock); Status = AFP_ERR_CALL_NOT_SUPPORTED; break; } Status = AFP_ERR_NONE; pSda->sda_AfpFunc = ApiCode; if (RequestSize >= FIELD_OFFSET(struct _RequestPacket, _SubFunc)) { pSda->sda_AfpSubFunc = pRqPkt->_SubFunc; } pSda->sda_PathType = 0; // Invalid till we actually encounter one pSda->sda_IOBuf = pWriteBuf; pSda->sda_IOSize = WriteSize; if (pDispTab->ApiOptions & API_QUEUE_IF_DPC) { pSda->sda_Flags |= SDA_QUEUE_IF_DPC; } RELEASE_SPIN_LOCK_FROM_DPC(&pSda->sda_Lock); // Get all the fields from the request buffer to the sda_ReqBlock structure. if (RequestSize >= FIELD_OFFSET(struct _RequestPacket, _OtherParms)) { pRequestBuf = &pRqPkt->_OtherParms; } // Do this for APIs which do not provide a sub-function or a pad. // Currently the only culprit is FPLogin if (pDispTab->ApiOptions & API_NOSUBFUNCTION) { pSda->sda_AfpSubFunc = 0; pRequestBuf --; Offset --; } // Account for the function and subfunction (if any) from the request packet RequestSize -= Offset; // // for the Apple native UAM's (Randnum Exchange, and 2-Way Randnum exchange), // we special case and 'unmarshal' the parms directly (the Afp function code // being the same for AfpLoginCont regardless of the UAM used, it would be a // major hack if we had to 'unmarshal' the parms the regular way) // if ((ApiCode == _AFP_LOGIN_CONT) && ((pSda->sda_ClientType == SDA_CLIENT_RANDNUM) || (pSda->sda_ClientType == SDA_CLIENT_TWOWAY))) { // 8 bytes of Response, 2 bytes of LogonId if (pSda->sda_ClientType == SDA_CLIENT_RANDNUM) { BytesToCopy = (RANDNUM_RESP_LEN+sizeof(USHORT)); } // 8 bytes of Response, 8 bytes of Mac's challeng, 2 bytes of LogonId else { BytesToCopy = (TWOWAY_RESP_LEN+sizeof(USHORT)); } if (RequestSize < BytesToCopy) { ASSERT(0); Status = AFP_ERR_PARAM; break; } RtlCopyMemory((PBYTE)&pSda->sda_ReqBlock[0], pRequestBuf, BytesToCopy); // // skip everything else, now that we got what we wanted // Status = AFP_ERR_QUEUE; break; } for (i = 0; (i < MAX_REQ_ENTRIES) && (pDispTab->ReqPktDesc[i] != FLD_NONE); i++) { // Check alignment if (((pDispTab->ReqPktDesc[i] & FLD_NOPAD) == 0) && ((Offset % 2) != 0)) { Offset ++; RequestSize --; pRequestBuf ++; } if (RequestSize < (pDispTab->ReqPktDesc[i] & ~FLD_PROP_MASK)) { Status = AFP_ERR_PARAM; break; } switch (pDispTab->ReqPktDesc[i] & ~FLD_PROP_MASK) { case FLD_BYTE: ASSERT ((pDispTab->ReqPktDesc[i] & FLD_NOCONV) == 0); GETBYTE2DWORD(&pSda->sda_ReqBlock[i], pRequestBuf); break; case FLD_WORD: ASSERT ((pDispTab->ReqPktDesc[i] & FLD_NOCONV) == 0); GETSHORT2DWORD(&pSda->sda_ReqBlock[i], pRequestBuf); if (pDispTab->ReqPktDesc[i] & FLD_SIGNED) pSda->sda_ReqBlock[i] = (LONG)((SHORT)pSda->sda_ReqBlock[i]); break; case FLD_DWRD: if (pDispTab->ReqPktDesc[i] & FLD_NOCONV) { GETDWORD2DWORD_NOCONV(&pSda->sda_ReqBlock[i], pRequestBuf); } else { GETDWORD2DWORD(&pSda->sda_ReqBlock[i], pRequestBuf); } break; default: // How did we get here ? KeBugCheck(0); break; } if ((pDispTab->ReqPktDesc[i] & FLD_NON_ZERO) && (pSda->sda_ReqBlock[i] == 0)) { if (pDispTab->ReqPktDesc[i] & FLD_CHECK_MASK) { ASSERT ( i < MAX_MASK_ENTRIES); Status = AFP_ERR_BITMAP; } else { Status = AFP_ERR_PARAM; } break; } if ((pDispTab->ReqPktDesc[i] & FLD_CHECK_MASK) && (((USHORT)(pSda->sda_ReqBlock[i]) & ~pDispTab->ReqPktMask[i]) != 0)) { ASSERT (i < MAX_MASK_ENTRIES); Status = AFP_ERR_BITMAP; break; } pRequestBuf += (pDispTab->ReqPktDesc[i] & ~FLD_PROP_MASK); Offset += (pDispTab->ReqPktDesc[i] & ~FLD_PROP_MASK); RequestSize -= (pDispTab->ReqPktDesc[i] & ~FLD_PROP_MASK); } if (Status != AFP_ERR_NONE) { break; } // Before we go any further, check for volume/fork references and such // // NOTE: The VolId and OForkRefNum are always the first parameter and // hence referenced as such via the request packet structure if (pDispTab->ApiOptions & API_CHECK_VOLID) { PCONNDESC pConnDesc; struct _RequestPacket { DWORD _VolId; }; struct _ModifiedPacket { ULONG_PTR _VolId; }; if ((pReqPkt->_VolId == 0) || ((pConnDesc = AfpConnectionReferenceAtDpc(pSda, (ULONG)(pReqPkt->_VolId))) == NULL)) { Status = AFP_ERR_PARAM; break; } ACQUIRE_SPIN_LOCK_AT_DPC(&pSda->sda_Lock); pSda->sda_Flags |= SDA_DEREF_VOLUME; RELEASE_SPIN_LOCK_FROM_DPC(&pSda->sda_Lock); //if (sizeof(DWORD) != sizeof(ULONG_PTR)) #ifdef _WIN64 // Create 64-bit space to hold VolDesc pointer // Push array 1 DWORD down { for (i = MAX_REQ_ENTRIES; i > 0; i--) { pSda->sda_ReqBlock[i+1] = pSda->sda_ReqBlock[i]; } } #endif pModPkt->_VolId = (ULONG_PTR)pConnDesc; if ((pDispTab->ApiOptions & API_TYPE_WRITE) && (pConnDesc->cds_pVolDesc->vds_Flags & AFP_VOLUME_READONLY)) { DBGPRINT(DBG_COMP_AFPAPI_FORK, DBG_LEVEL_WARN, ("AfpUnmarshallReq: Write operation on a RO volume\n")); Status = AFP_ERR_VOLUME_LOCKED; break; } if (pConnDesc->cds_pVolDesc->vds_Flags & VOLUME_CDFS_INVALID) { ASSERT(!IS_VOLUME_NTFS(pConnDesc->cds_pVolDesc)); DBGPRINT(DBG_COMP_AFPAPI, DBG_LEVEL_WARN, ("AfpUnmarshallReq: Access to a defunct CD-Volume\n")); Status = AFP_ERR_MISC; break; } } else if (pDispTab->ApiOptions & API_CHECK_OFORKREFNUM) { POPENFORKENTRY pOpenForkEntry; struct _RequestPacket { DWORD _OForkRefNum; }; struct _ModifiedPacket { ULONG_PTR _OForkRefNum; }; if ((pReqPkt->_OForkRefNum == 0) || ((pOpenForkEntry = AfpForkReferenceByRefNum(pSda, (ULONG)(pReqPkt->_OForkRefNum))) == NULL)) { Status = AFP_ERR_PARAM; break; } ACQUIRE_SPIN_LOCK_AT_DPC(&pSda->sda_Lock); pSda->sda_Flags |= SDA_DEREF_OFORK; RELEASE_SPIN_LOCK_FROM_DPC(&pSda->sda_Lock); //if (sizeof(DWORD) != sizeof(ULONG_PTR)) #ifdef _WIN64 // Create 64-bit space to hold VolDesc pointer // Push array 1 DWORD down { for (i = MAX_REQ_ENTRIES; i > 0; i--) { pSda->sda_ReqBlock[i+1] = pSda->sda_ReqBlock[i]; } } #endif pModPkt->_OForkRefNum = (ULONG_PTR)pOpenForkEntry; if ((pDispTab->ApiOptions & API_TYPE_WRITE) && !(pOpenForkEntry->ofe_OpenMode & FORK_OPEN_WRITE)) { DBGPRINT(DBG_COMP_AFPAPI_FORK, DBG_LEVEL_WARN, ("AfpUnmarshallReq: AfpWrite on a Fork not opened for write\n")); Status = AFP_ERR_ACCESS_DENIED; break; } } // Now get the sda_NameX fields. Allocate one chunk of memory for // copying all the variable size data. Use sda_NameXSpace if it fits there if ((pDispTab->NameXType[0] != TYP_NONE) && (RequestSize > 0)) { SpaceLeft = RequestSize; ACQUIRE_SPIN_LOCK_AT_DPC(&pSda->sda_Lock); pSda->sda_NameBuf = NULL; if ((RequestSize <= pSda->sda_SizeNameXSpace) && ((pSda->sda_Flags & SDA_NAMEXSPACE_IN_USE) == 0)) { pSda->sda_NameBuf = pSda->sda_NameXSpace; pSda->sda_Flags |= SDA_NAMEXSPACE_IN_USE; } RELEASE_SPIN_LOCK_FROM_DPC(&pSda->sda_Lock); if ((pSda->sda_NameBuf == NULL) && (pSda->sda_NameBuf = AfpAllocNonPagedMemory(RequestSize)) == NULL) { Status = AFP_ERR_MISC; break; } } for (i = 0; (i < MAX_VAR_ENTRIES) && (pDispTab->NameXType[i] != TYP_NONE) && (RequestSize > 0); i++) { if (((pDispTab->NameXType[i] & TYP_NOPAD) == 0) && (RequestSize > 0) && ((Offset % 2) != 0)) { Offset ++; RequestSize --; pRequestBuf ++; } switch (pDispTab->NameXType[i] & ~TYP_PROP_MASK) { case TYP_PATH: // TYP_PATH is almost like TYP_STRING except that there is a // leading PathType which should be valid. Just validate that // and fall through to the TYP_STRING case. Validate the size // to hold atleast the pathtype and the string length ASSERT (!(pDispTab->NameXType[i] & TYP_OPTIONAL)); if ((RequestSize < 2*sizeof(BYTE)) || !VALIDPATHTYPE(*pRequestBuf)|| (VALIDPATHTYPE(pSda->sda_PathType) && (pSda->sda_PathType != *pRequestBuf))) { Status = AFP_ERR_PARAM; break; } // Save the PathType and account for it pSda->sda_PathType = *pRequestBuf++; Offset ++; RequestSize --; case TYP_STRING: // A TYP_STRING has a leading size byte and a string of that // size. A null string is then atleast one byte long. // Allow an optional string to be absent if ((pDispTab->NameXType[i] & TYP_OPTIONAL) && (RequestSize == 0)) continue; if ((RequestSize < sizeof(BYTE)) || ((StrSize = (LONG)pRequestBuf[0]) > (RequestSize - (LONG)sizeof(BYTE)))) { Status = AFP_ERR_PARAM; break; } // Consume the string length pRequestBuf++; Offset ++; RequestSize --; break; case TYP_BLK16: if (RequestSize < 16) { Status = AFP_ERR_PARAM; ASSERT(0); break; } StrSize = 16; break; case TYP_BLOCK: StrSize = RequestSize; break; default: // How did we get here ? KeBugCheck(0); break; } if (Status != AFP_ERR_NONE) { break; } if (StrSize > 0) { ASSERT (StrSize <= SpaceLeft); pSda->sda_Name[i].Buffer = (pSda->sda_NameBuf + NameOff); SpaceLeft -= StrSize; NameOff += StrSize; pSda->sda_Name[i].Length = pSda->sda_Name[i].MaximumLength = (USHORT)StrSize; RtlCopyMemory(pSda->sda_Name[i].Buffer, pRequestBuf, StrSize); pRequestBuf += StrSize; Offset += StrSize; RequestSize -= StrSize; } if ((pDispTab->NameXType[i] & TYP_NON_NULL) && (pSda->sda_Name[i].Length == 0)) Status = (AFP_ERR_BASE - pDispTab->AfpStatus); } // Change the status if we have no worker at dispatch level if ((Status == AFP_ERR_NONE) && (pDispTab->ApiOptions & API_MUST_BE_QUEUED)) { Status = AFP_ERR_QUEUE; } DBGPRINT(DBG_COMP_AFPAPI, DBG_LEVEL_INFO, ("AfpUnmarshallReq: <%s> returning Status %ld\n", afpApiNames[ApiCode], Status)); } while (False); AfpUnmarshallReq_ErrExit: // // Kill the write buffer Mdl since we do not need it anymore. Of course, // if the Mdl belongs to cache mgr, don't touch it! // if ((pRequest->rq_WriteMdl != NULL) && (pRequest->rq_CacheMgrContext == NULL)) { AfpFreeMdl(pRequest->rq_WriteMdl); pRequest->rq_WriteMdl = NULL; } if ((Status != AFP_ERR_NONE) && (Status != AFP_ERR_QUEUE)) { if (pWriteBuf != NULL) { AfpIOFreeBuffer(pWriteBuf); } pSda->sda_IOBuf = NULL; pSda->sda_IOSize = 0; } #ifdef PROFILING AfpGetPerfCounter(&TimeE); TimeD.QuadPart = TimeE.QuadPart - TimeS.QuadPart; INTERLOCKED_INCREMENT_LONG(&AfpServerProfile->perf_UnmarshallCount); INTERLOCKED_ADD_LARGE_INTGR_DPC(&AfpServerProfile->perf_UnmarshallTime, TimeD, &AfpStatisticsLock); #endif AfpDisposeRequest(pSda, Status); } /*** AfpCompleteApiProcessing * * Called in when the API processing is complete. Book-keeping is performed * and a reply sent. If any buffers were allocated during un-marshalling, * then they are freed up. * * LOCKS: sda_Lock (SPIN), AfpStatisticsLock (SPIN) * */ VOID FASTCALL AfpCompleteApiProcessing( IN PSDA pSda, IN AFPSTATUS RetCode ) { POPENFORKENTRY pOpenForkEntry = NULL; PCONNDESC pConnDesc = NULL; PDFRDREQQ pDfrdReq = NULL; PLIST_ENTRY pList; KIRQL OldIrql; PMDL ReplyMdl; PREQUEST pRequest; struct _RequestPacket { union { PCONNDESC _pConnDesc; POPENFORKENTRY _pOpenForkEntry; }; }; DBGPRINT(DBG_COMP_AFPAPI, DBG_LEVEL_INFO, ("AfpCompleteApiProcessing: Completed <%s>\n", afpApiNames[pSda->sda_AfpFunc])); ACQUIRE_SPIN_LOCK(&pSda->sda_Lock, &OldIrql); // If there is a deferred request, dequeue it now while we have the lock if (!IsListEmpty(&pSda->sda_DeferredQueue)) { pList = RemoveHeadList(&pSda->sda_DeferredQueue); pDfrdReq = CONTAINING_RECORD(pList, DFRDREQQ, drq_Link); } ASSERT (pSda->sda_Flags & SDA_REQUEST_IN_PROCESS); pSda->sda_Flags &= ~SDA_QUEUE_IF_DPC; if (pSda->sda_Flags & SDA_DEREF_VOLUME) { pConnDesc = pReqPkt->_pConnDesc; pReqPkt->_pConnDesc = NULL; ASSERT(VALID_CONNDESC(pConnDesc)); pSda->sda_Flags &= ~SDA_DEREF_VOLUME; // If we have a enumerated directory context, free it up // but only if we are not in the middle of an enumerate // and we are not doing the periodic GetVolParms either if ((pConnDesc->cds_pEnumDir != NULL) && (pSda->sda_AfpFunc != _AFP_ENUMERATE) && (pSda->sda_AfpFunc != _AFP_GET_VOL_PARMS)) { AfpFreeMemory(pConnDesc->cds_pEnumDir); pConnDesc->cds_pEnumDir = NULL; } } if (pSda->sda_Flags & SDA_DEREF_OFORK) { pOpenForkEntry = pReqPkt->_pOpenForkEntry; ASSERT(VALID_OPENFORKENTRY(pOpenForkEntry)); pSda->sda_Flags &= ~SDA_DEREF_OFORK; } if (pSda->sda_NameBuf != NULL) { if (pSda->sda_NameBuf != pSda->sda_NameXSpace) { AfpFreeMemory(pSda->sda_NameBuf); } else { pSda->sda_Flags &= ~SDA_NAMEXSPACE_IN_USE; } pSda->sda_NameBuf = NULL; } // Clear these fields. We do not want left-overs from previous api lying around. ASSERT((FIELD_OFFSET(SDA, sda_Name) - FIELD_OFFSET(SDA, sda_ReqBlock)) == sizeof(DWORD)*(MAX_REQ_ENTRIES_PLUS_1)); RtlZeroMemory(&pSda->sda_ReqBlock[0], (sizeof(ANSI_STRING)*MAX_VAR_ENTRIES) + (sizeof(DWORD)*(MAX_REQ_ENTRIES_PLUS_1))); pSda->sda_SecUtilResult = STATUS_SUCCESS; ASSERT(pSda->sda_AfpFunc < _AFP_MAX_ENTRIES); #ifdef PROFILING { TIME ApiEndTime, FuncTime; ACQUIRE_SPIN_LOCK_AT_DPC(&AfpStatisticsLock); // Update profile info AfpGetPerfCounter(&ApiEndTime); FuncTime.QuadPart = ApiEndTime.QuadPart - pSda->sda_ApiStartTime.QuadPart; AfpServerProfile->perf_ApiCounts[pSda->sda_AfpFunc] ++; AfpServerProfile->perf_ApiCumTimes[pSda->sda_AfpFunc].QuadPart += FuncTime.QuadPart; // Do not make this completely useless by recording times // for apis that do not succeed. They detect an error early // and hence make the Best Time fairly bogus if (RetCode == AFP_ERR_NONE) { if ((FuncTime.QuadPart > AfpServerProfile->perf_ApiWorstTime[pSda->sda_AfpFunc].QuadPart) || (AfpServerProfile->perf_ApiWorstTime[pSda->sda_AfpFunc].QuadPart == 0)) AfpServerProfile->perf_ApiWorstTime[pSda->sda_AfpFunc].QuadPart = FuncTime.QuadPart; if ((FuncTime.QuadPart < AfpServerProfile->perf_ApiBestTime[pSda->sda_AfpFunc].QuadPart) || (AfpServerProfile->perf_ApiBestTime[pSda->sda_AfpFunc].QuadPart == 0)) AfpServerProfile->perf_ApiBestTime[pSda->sda_AfpFunc].QuadPart = FuncTime.QuadPart; } RELEASE_SPIN_LOCK_FROM_DPC(&AfpStatisticsLock); } #endif INTERLOCKED_ADD_STATISTICS(&AfpServerStatistics.stat_DataOut, (LONG)pSda->sda_ReplySize + (LONG)sizeof(RetCode), &AfpStatisticsLock); pRequest = pSda->sda_Request; // We are done with the request. Do not reset if we have a deferred request to process if (pDfrdReq == NULL) { pSda->sda_Flags &= ~SDA_REQUEST_IN_PROCESS; } else { pSda->sda_Request = pDfrdReq->drq_pRequest; } // We are done with the request. Setup for reply. pSda->sda_Flags |= SDA_REPLY_IN_PROCESS; ReplyMdl = NULL; // // if we got Read Mdl from cache mgr, we don't allocate a new Mdl // if (pRequest->rq_CacheMgrContext) { ASSERT(pSda->sda_ReplyBuf == NULL); ReplyMdl = ((PDELAYEDALLOC)(pRequest->rq_CacheMgrContext))->pMdl; } // // nope, we are using our own buffer (if any). We must allocate our // Mdl too // else { if (pSda->sda_ReplyBuf != NULL) { ASSERT ((pSda->sda_ReplySize > 0) && (pSda->sda_ReplySize <= pSda->sda_MaxWriteSize)); if ((ReplyMdl = AfpAllocMdl( (pSda->sda_ReplyBuf - DSI_BACKFILL_OFFSET(pSda)), (pSda->sda_ReplySize + DSI_BACKFILL_OFFSET(pSda)), NULL)) == NULL) { RetCode = AFP_ERR_MISC; AfpFreeReplyBuf(pSda, TRUE); } } } pSda->sda_ReplyBuf = NULL; pSda->sda_ReplySize = 0; RELEASE_SPIN_LOCK(&pSda->sda_Lock, OldIrql); // Dereference the connection descriptor and the fork descriptor (from // above where we cannot call dereference as we are holding the SDA lock. if (pOpenForkEntry != NULL) AfpForkDereference(pOpenForkEntry); if (pConnDesc != NULL) AfpConnectionDereference(pConnDesc); pRequest->rq_ReplyMdl = ReplyMdl; AfpSpReplyClient(pRequest, RetCode, pSda->sda_XportTable); // Handle any deferred requests if (pDfrdReq != NULL) { KIRQL OldIrql; // Note that AfpUnmarshallReq expects to be called at DISPATCH_LEVEL KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); #ifdef PROFILING ACQUIRE_SPIN_LOCK_AT_DPC(&AfpStatisticsLock); AfpServerProfile->perf_CurDfrdReqCount --; RELEASE_SPIN_LOCK_FROM_DPC(&AfpStatisticsLock); #endif AfpUnmarshallReq(pSda); KeLowerIrql(OldIrql); AfpFreeMemory(pDfrdReq); } } /*** AfpStartApiProcessing * * This is called when an API is queued up to the worker thread. This calls * the real worker and then adjusts the count of outstanding worker requests. */ VOID FASTCALL AfpStartApiProcessing( IN PSDA pSda ) { AFPSTATUS RetCode; #ifdef PROFILING TIME TimeE; #endif ASSERT(VALID_SDA(pSda) && (pSda->sda_WorkerRoutine != NULL)); DBGPRINT(DBG_COMP_AFPAPI, DBG_LEVEL_INFO, ("AfpStartApiProcessing: Calling Fsp Worker for <%s>\n", afpApiNames[pSda->sda_AfpFunc])); #ifdef PROFILING AfpGetPerfCounter(&TimeE); TimeE.QuadPart -= pSda->sda_QueueTime.QuadPart; INTERLOCKED_ADD_LARGE_INTGR(&AfpServerProfile->perf_QueueTime, TimeE, &AfpStatisticsLock); #endif // Call the real worker RetCode = (*pSda->sda_WorkerRoutine)(pSda); DBGPRINT(DBG_COMP_AFPAPI, DBG_LEVEL_INFO, ("AfpStartApiProcessing: Fsp Worker returned %ld\n", RetCode)); ASSERT ((RetCode != AFP_ERR_QUEUE) && (RetCode != AFP_ERR_DEFER)); if (RetCode != AFP_ERR_EXTENDED) { AfpCompleteApiProcessing(pSda, RetCode); } } /*** AfpDisposeRequest * * The request has been un-marshalled. Determine what to do with it. The * return code determines the possible course of action. */ VOID FASTCALL AfpDisposeRequest( IN PSDA pSda, IN AFPSTATUS Status ) { DBGPRINT(DBG_COMP_AFPAPI, DBG_LEVEL_INFO, ("AfpDisposeRequest: %ld\n", Status)); if ((Status == AFP_ERR_NONE) || (Status == AFP_ERR_QUEUE)) { ASSERT(VALID_SDA(pSda) && (pSda->sda_WorkerRoutine != NULL)); } else { ASSERT(VALID_SDA(pSda)); } ASSERT (Status != AFP_ERR_DEFER); // Now see if must call the worker or queue it or respond if (Status == AFP_ERR_NONE) { Status = (*pSda->sda_WorkerRoutine)(pSda); DBGPRINT(DBG_COMP_AFPAPI, DBG_LEVEL_INFO, ("AfpDisposeRequest: Fsd Worker returned %ld\n", Status)); ASSERT (Status != AFP_ERR_DEFER); } if (Status == AFP_ERR_QUEUE) { if ((pSda->sda_Flags & SDA_QUEUE_IF_DPC) && (KeGetCurrentIrql() != DISPATCH_LEVEL)) { Status = (*pSda->sda_WorkerRoutine)(pSda); ASSERT ((Status != AFP_ERR_QUEUE) && (Status != AFP_ERR_DEFER)); if (Status != AFP_ERR_EXTENDED) { AfpCompleteApiProcessing(pSda, Status); } } else { #ifdef PROFILING AfpGetPerfCounter(&pSda->sda_QueueTime); #endif AfpQueueWorkItem(&pSda->sda_WorkItem); } } else if ((Status != AFP_ERR_QUEUE) && (Status != AFP_ERR_EXTENDED)) { AfpCompleteApiProcessing(pSda, Status); } } /*** afpQueueDeferredRequest * * Queue a request in the deferred queue. The request is queued at the tail * of the queue and dequeued at the head. * * LOCKS_ASSUMED: sda_Lock (SPIN) */ VOID FASTCALL afpQueueDeferredRequest( IN PSDA pSda, IN PREQUEST pRequest ) { PDFRDREQQ pDfrdReq; ASSERT (KeGetCurrentIrql() == DISPATCH_LEVEL); DBGPRINT(DBG_COMP_AFPAPI, DBG_LEVEL_INFO, ("afpQueueDeferredRequest: Deferring Request\n")); #ifdef PROFILING ACQUIRE_SPIN_LOCK_AT_DPC(&AfpStatisticsLock); AfpServerProfile->perf_CurDfrdReqCount ++; if (AfpServerProfile->perf_CurDfrdReqCount > AfpServerProfile->perf_MaxDfrdReqCount) AfpServerProfile->perf_MaxDfrdReqCount = AfpServerProfile->perf_CurDfrdReqCount; RELEASE_SPIN_LOCK_FROM_DPC(&AfpStatisticsLock); #endif pDfrdReq = (PDFRDREQQ)AfpAllocNonPagedMemory(sizeof(DFRDREQQ) + pRequest->rq_RequestSize); if (pDfrdReq == NULL) { // Should we respond to this request ? How ? Should we drop this session ? AFPLOG_DDERROR(AFPSRVMSG_DFRD_REQUEST, STATUS_INSUFFICIENT_RESOURCES, NULL, 0, NULL); DBGPRINT(DBG_COMP_AFPAPI, DBG_LEVEL_ERR, ("afpQueueDeferredRequest: Unable to allocate DfrdReq packet, dropping request\n")); DBGBRK(DBG_LEVEL_FATAL); return; } RtlCopyMemory((PBYTE)pDfrdReq + sizeof(DFRDREQQ), pRequest->rq_RequestBuf, pRequest->rq_RequestSize); pDfrdReq->drq_pRequest = pRequest; pDfrdReq->drq_pRequest->rq_RequestBuf = (PBYTE)pDfrdReq + sizeof(DFRDREQQ); InsertTailList(&pSda->sda_DeferredQueue, &pDfrdReq->drq_Link); } /*** AfpGetWriteBuffer * * This is called directly by the appletalk stack when a WRITE command is encountered. * The request is examined for either FpWrite or FpAddIcon. These are the only reqs * which uses a write command. If a request other than this is specified or if the * size specified is 0 or if we fail to allocate memory or MDl, then a NULL is returned * for the Mdl else a valid Mdl is returned. */ NTSTATUS FASTCALL AfpGetWriteBuffer( IN PSDA pSda, IN PREQUEST pRequest ) { PMDL pMdl = NULL; PBYTE pBuf; LONG BufSize = 0; DWORD Offset; USHORT ReqLen; PDELAYEDALLOC pDelAlloc; POPENFORKENTRY pOpenForkEntry; DWORD OForkRefNum; NTSTATUS status=STATUS_SUCCESS; KIRQL OldIrql; PFILE_OBJECT pFileObject; PFAST_IO_DISPATCH pFastIoDisp; struct _FuncHdr { BYTE _Func; BYTE _SubFunc; }; union _ReqHdr { struct _WriteReq { struct _FuncHdr _FuncHdr; BYTE _ForkRefNum[2]; BYTE _Offset[4]; BYTE _Size[4]; } WriteReq; struct _AddIconReq { struct _FuncHdr _FuncHdr; BYTE _DTRefNum[2]; BYTE _Creator[4]; BYTE _Type[4]; BYTE _IconType; BYTE _Reserved; BYTE _IconTag[4]; BYTE _BitmapSize[2]; } AddIconReq; } *pReqHdr; ReqLen = (USHORT)pRequest->rq_RequestSize; pReqHdr = (union _ReqHdr *)(pRequest->rq_RequestBuf); ASSERT(pRequest->rq_WriteMdl == NULL); pRequest->rq_WriteMdl = NULL; if ((pReqHdr != NULL) && (ReqLen >= sizeof(struct _FuncHdr))) { if ((pReqHdr->WriteReq._FuncHdr._Func == AFP_WRITE) && (ReqLen >= sizeof(struct _WriteReq))) { GETDWORD2DWORD(&BufSize, pReqHdr->WriteReq._Size); if (BufSize > (LONG)pSda->sda_MaxWriteSize) { BufSize = (LONG)pSda->sda_MaxWriteSize; } // // if the Write is big enough, get an Mdl directly from cache mgr // if (BufSize >= CACHEMGR_WRITE_THRESHOLD) { // get the fork number from the request GETSHORT2DWORD(&OForkRefNum, pReqHdr->WriteReq._ForkRefNum); // get the offset at which to write GETDWORD2DWORD(&Offset, pReqHdr->WriteReq._Offset); KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); pOpenForkEntry = AfpForkReferenceByRefNum(pSda, OForkRefNum); KeLowerIrql(OldIrql); if (pOpenForkEntry == NULL) { DBGPRINT(DBG_COMP_AFPAPI, DBG_LEVEL_ERR, ("AfpGetWriteBuffer: couldn't ref fork on %lx\n", pSda)); return(STATUS_CONNECTION_DISCONNECTED); } pFileObject = AfpGetRealFileObject(pOpenForkEntry->ofe_pFileObject); pFastIoDisp = pOpenForkEntry->ofe_pDeviceObject->DriverObject->FastIoDispatch; if ((pFileObject->Flags & FO_CACHE_SUPPORTED) && (pFastIoDisp->PrepareMdlWrite != NULL)) { pDelAlloc = AfpAllocDelAlloc(); if (pDelAlloc == NULL) { DBGPRINT(DBG_COMP_AFPAPI, DBG_LEVEL_ERR, ("AfpGetWriteBuffer: malloc for pDelAlloc failed\n")); // remove the refcount we put before checking FO_CACHE_SUPPORTED AfpForkDereference(pOpenForkEntry); return(STATUS_INSUFFICIENT_RESOURCES); } // put DelayAlloc refcount if (AfpSdaReferenceSessionByPointer(pSda) == NULL) { DBGPRINT(DBG_COMP_AFPAPI, DBG_LEVEL_ERR, ("AfpGetWriteBuffer: session closing, rejecting request\n")); AfpFreeDelAlloc(pDelAlloc); // remove the refcount we put before checking FO_CACHE_SUPPORTED AfpForkDereference(pOpenForkEntry); return(STATUS_CONNECTION_DISCONNECTED); } pRequest->rq_CacheMgrContext = pDelAlloc; AfpInitializeWorkItem(&pDelAlloc->WorkItem, AfpAllocWriteMdl, pDelAlloc); pDelAlloc->pSda = pSda; pDelAlloc->pRequest = pRequest; pDelAlloc->Offset.QuadPart = Offset; pDelAlloc->BufSize = BufSize; pDelAlloc->pOpenForkEntry = pOpenForkEntry; // DELALLOCQUEUE: unrem the #if 0 part and delete the AfpQueueWorkItem line #if 0 KeInsertQueue(&AfpDelAllocQueue, &(pDelAlloc->WorkItem.wi_List)); #endif AfpQueueWorkItem(&pDelAlloc->WorkItem); return(STATUS_PENDING); } else { // remove the refcount we put before checking FO_CACHE_SUPPORTED AfpForkDereference(pOpenForkEntry); } } } else if ((pReqHdr->AddIconReq._FuncHdr._Func == AFP_ADD_ICON) && (ReqLen >= sizeof(struct _AddIconReq))) { GETSHORT2DWORD(&BufSize, pReqHdr->AddIconReq._BitmapSize); if ((BufSize < 0) || (BufSize > (LONG)pSda->sda_MaxWriteSize)) { BufSize = 0; } } if (BufSize > 0) { pBuf = AfpIOAllocBuffer(BufSize); if (pBuf != NULL) { pMdl = AfpAllocMdl(pBuf, BufSize, NULL); if (pMdl == NULL) { AfpIOFreeBuffer(pBuf); status = STATUS_INSUFFICIENT_RESOURCES; } } else { status = STATUS_INSUFFICIENT_RESOURCES; } } } pRequest->rq_WriteMdl = pMdl; return (status); }