Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

2946 lines
67 KiB

/*
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 <afp.h>
#include <gendisp.h>
#include <client.h>
#include <fdparm.h>
#include <forkio.h>
#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);
}