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
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);
|
|
}
|
|
|