mirror of https://github.com/tongzx/nt5src
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.
1241 lines
32 KiB
1241 lines
32 KiB
/*
|
|
|
|
Copyright (c) 1992 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
fsp_fd.c
|
|
|
|
Abstract:
|
|
|
|
This module contains the entry points for the AFP file-dir APIs queued to
|
|
the FSP. These are all callable from FSP Only.
|
|
|
|
Author:
|
|
|
|
Jameel Hyder (microsoft!jameelh)
|
|
|
|
|
|
Revision History:
|
|
25 Apr 1992 Initial Version
|
|
|
|
Notes: Tab stop: 4
|
|
--*/
|
|
|
|
#define FILENUM FILE_FSP_FD
|
|
|
|
#include <afp.h>
|
|
#include <gendisp.h>
|
|
#include <fdparm.h>
|
|
#include <pathmap.h>
|
|
#include <client.h>
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text( PAGE, AfpFspDispGetFileDirParms)
|
|
#pragma alloc_text( PAGE, AfpFspDispSetFileDirParms)
|
|
#pragma alloc_text( PAGE, AfpFspDispDelete)
|
|
#pragma alloc_text( PAGE, AfpFspDispRename)
|
|
#pragma alloc_text( PAGE, AfpFspDispMoveAndRename)
|
|
#pragma alloc_text( PAGE, AfpFspDispCatSearch)
|
|
#endif
|
|
|
|
/*** AfpFspDispGetFileDirParms
|
|
*
|
|
* This is the worker routine for the AfpGetFileDirParms API.
|
|
*
|
|
* The request packet is represented below
|
|
*
|
|
* sda_ReqBlock PCONNDESC pConnDesc
|
|
* sda_ReqBlock DWORD ParentId
|
|
* sda_ReqBlock DWORD File Bitmap
|
|
* sda_ReqBlock DWORD Dir Bitmap
|
|
* sda_Name1 ANSI_STRING Path
|
|
*/
|
|
AFPSTATUS FASTCALL
|
|
AfpFspDispGetFileDirParms(
|
|
IN PSDA pSda
|
|
)
|
|
{
|
|
FILEDIRPARM FDParm;
|
|
PATHMAPENTITY PME;
|
|
BOOLEAN NeedHandle = False;
|
|
PVOLDESC pVolDesc;
|
|
DWORD BitmapF, BitmapD, BitmapI = 0;
|
|
AFPSTATUS Status = AFP_ERR_PARAM;
|
|
struct _RequestPacket
|
|
{
|
|
PCONNDESC _pConnDesc;
|
|
DWORD _ParentId;
|
|
DWORD _FileBitmap;
|
|
DWORD _DirBitmap;
|
|
};
|
|
struct _ResponsePacket
|
|
{
|
|
BYTE __FileBitmap[2];
|
|
BYTE __DirBitmap[2];
|
|
BYTE __FileDirFlag;
|
|
BYTE __Pad;
|
|
};
|
|
|
|
PAGED_CODE();
|
|
|
|
DBGPRINT(DBG_COMP_AFPAPI_FD, DBG_LEVEL_INFO,
|
|
("AfpFspDispGetFileDirParms: Entered\n"));
|
|
|
|
ASSERT(VALID_CONNDESC(pReqPkt->_pConnDesc));
|
|
|
|
pVolDesc = pReqPkt->_pConnDesc->cds_pVolDesc;
|
|
|
|
ASSERT(VALID_VOLDESC(pVolDesc));
|
|
|
|
BitmapF = pReqPkt->_FileBitmap;
|
|
BitmapD = pReqPkt->_DirBitmap;
|
|
|
|
do
|
|
{
|
|
AfpInitializeFDParms(&FDParm);
|
|
AfpInitializePME(&PME, 0, NULL);
|
|
if (IS_VOLUME_NTFS(pVolDesc) &&
|
|
(BitmapD & (DIR_BITMAP_ACCESSRIGHTS |
|
|
DIR_BITMAP_OWNERID |
|
|
DIR_BITMAP_GROUPID)))
|
|
{
|
|
NeedHandle = True;
|
|
}
|
|
|
|
if (BitmapD & DIR_BITMAP_ACCESSRIGHTS)
|
|
{
|
|
BitmapI = FD_INTERNAL_BITMAP_OPENACCESS_READCTRL;
|
|
}
|
|
|
|
|
|
if ((Status = AfpMapAfpPathForLookup(pReqPkt->_pConnDesc,
|
|
pReqPkt->_ParentId,
|
|
&pSda->sda_Name1,
|
|
pSda->sda_PathType,
|
|
DFE_ANY,
|
|
BitmapF | BitmapD | BitmapI,
|
|
NeedHandle ? &PME : NULL,
|
|
&FDParm)) != AFP_ERR_NONE)
|
|
{
|
|
PME.pme_Handle.fsh_FileHandle = NULL;
|
|
break;
|
|
}
|
|
|
|
pSda->sda_ReplySize = SIZE_RESPPKT +
|
|
EVENALIGN(AfpGetFileDirParmsReplyLength(&FDParm,
|
|
IsDir(&FDParm) ? BitmapD : BitmapF));
|
|
|
|
if ((Status = AfpAllocReplyBuf(pSda)) == AFP_ERR_NONE)
|
|
{
|
|
AfpPackFileDirParms(&FDParm,
|
|
IsDir(&FDParm) ? BitmapD : BitmapF,
|
|
pSda->sda_ReplyBuf + SIZE_RESPPKT);
|
|
PUTDWORD2SHORT(&pRspPkt->__FileBitmap, BitmapF);
|
|
PUTDWORD2SHORT(&pRspPkt->__DirBitmap, BitmapD);
|
|
pRspPkt->__FileDirFlag = IsDir(&FDParm) ?
|
|
FILEDIR_FLAG_DIR : FILEDIR_FLAG_FILE;
|
|
pRspPkt->__Pad = 0;
|
|
}
|
|
} while (False);
|
|
|
|
// Return before we close thus saving some time
|
|
AfpCompleteApiProcessing(pSda, Status);
|
|
|
|
if (NeedHandle && (PME.pme_Handle.fsh_FileHandle != NULL))
|
|
AfpIoClose(&PME.pme_Handle); // Close the handle to the entity
|
|
|
|
return AFP_ERR_EXTENDED;
|
|
}
|
|
|
|
|
|
|
|
/*** AfpFspDispSetFileDirParms
|
|
*
|
|
* This is the worker routine for the AfpSetFileDirParms API.
|
|
*
|
|
* The request packet is represented below
|
|
*
|
|
* sda_ReqBlock PCONNDESC pConnDesc
|
|
* sda_ReqBlock DWORD ParentId
|
|
* sda_ReqBlock DWORD File or Directory Bitmap
|
|
* sda_Name1 ANSI_STRING Path
|
|
* sda_Name2 BLOCK File or Directory parameters
|
|
*/
|
|
AFPSTATUS FASTCALL
|
|
AfpFspDispSetFileDirParms(
|
|
IN PSDA pSda
|
|
)
|
|
{
|
|
PATHMAPENTITY PME;
|
|
PVOLDESC pVolDesc;
|
|
FILEDIRPARM FDParm;
|
|
DWORD Bitmap, BitmapI;
|
|
AFPSTATUS Status = AFP_ERR_PARAM;
|
|
WCHAR PathBuf[BIG_PATH_LEN];
|
|
struct _RequestPacket
|
|
{
|
|
PCONNDESC _pConnDesc;
|
|
DWORD _ParentId;
|
|
DWORD _Bitmap;
|
|
};
|
|
|
|
PAGED_CODE();
|
|
|
|
DBGPRINT(DBG_COMP_AFPAPI_FD, DBG_LEVEL_INFO,
|
|
("AfpFspDispSetFileDirParms: Entered\n"));
|
|
|
|
ASSERT(VALID_CONNDESC(pReqPkt->_pConnDesc));
|
|
|
|
pVolDesc = pReqPkt->_pConnDesc->cds_pVolDesc;
|
|
|
|
ASSERT(VALID_VOLDESC(pVolDesc));
|
|
|
|
Bitmap = pReqPkt->_Bitmap;
|
|
|
|
// Force the FD_BITMAP_LONGNAME in case a *file* is missing the afpinfo
|
|
// stream we will be able to generate the correct type/creator in
|
|
// AfpSetAfpInfo
|
|
BitmapI = FD_INTERNAL_BITMAP_OPENACCESS_RW_ATTR |
|
|
FD_BITMAP_LONGNAME |
|
|
FD_INTERNAL_BITMAP_RETURN_PMEPATHS;
|
|
|
|
// For a directory only the owner can change certain attributes like the
|
|
// various inhibit bits. Check for access if an attempt is made to modify
|
|
// any of these bits. We do not know at this point whether any of these
|
|
// attributes are being set/cleared yet !!!
|
|
if (Bitmap & FD_BITMAP_ATTR)
|
|
BitmapI = FD_INTERNAL_BITMAP_OPENACCESS_READCTRL|
|
|
FD_BITMAP_LONGNAME |
|
|
DIR_BITMAP_OWNERID |
|
|
DIR_BITMAP_GROUPID |
|
|
DIR_BITMAP_ACCESSRIGHTS |
|
|
FD_INTERNAL_BITMAP_RETURN_PMEPATHS;
|
|
|
|
AfpInitializeFDParms(&FDParm);
|
|
AfpInitializePME(&PME, sizeof(PathBuf), PathBuf);
|
|
|
|
do
|
|
{
|
|
Status = AfpMapAfpPathForLookup(pReqPkt->_pConnDesc,
|
|
pReqPkt->_ParentId,
|
|
&pSda->sda_Name1,
|
|
pSda->sda_PathType,
|
|
DFE_ANY,
|
|
Bitmap | BitmapI,
|
|
&PME,
|
|
&FDParm);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
PME.pme_Handle.fsh_FileHandle = NULL;
|
|
break;
|
|
}
|
|
|
|
if ((Status = AfpUnpackFileDirParms(pSda->sda_Name2.Buffer,
|
|
(LONG)pSda->sda_Name2.Length,
|
|
&Bitmap,
|
|
&FDParm)) != AFP_ERR_NONE)
|
|
break;
|
|
|
|
if (Bitmap != 0)
|
|
{
|
|
// Make sure they are not trying to set/clear any attributes
|
|
// that are not common to both files and directories
|
|
if ((Bitmap & FD_BITMAP_ATTR) &&
|
|
(FDParm._fdp_Attr & ~(FD_BITMAP_ATTR_SET |
|
|
FD_BITMAP_ATTR_INVISIBLE |
|
|
FD_BITMAP_ATTR_DELETEINH |
|
|
FILE_BITMAP_ATTR_WRITEINH |
|
|
FD_BITMAP_ATTR_RENAMEINH |
|
|
FD_BITMAP_ATTR_SYSTEM)))
|
|
{
|
|
Status = AFP_ERR_PARAM;
|
|
break;
|
|
}
|
|
Status = AfpSetFileDirParms(pVolDesc,
|
|
&PME,
|
|
Bitmap,
|
|
&FDParm);
|
|
}
|
|
} while (False);
|
|
|
|
// Return before we close thus saving some time
|
|
AfpCompleteApiProcessing(pSda, Status);
|
|
|
|
if (PME.pme_Handle.fsh_FileHandle != NULL)
|
|
AfpIoClose(&PME.pme_Handle);
|
|
|
|
if ((PME.pme_FullPath.Buffer != NULL) &&
|
|
(PME.pme_FullPath.Buffer != PathBuf))
|
|
{
|
|
AfpFreeMemory(PME.pme_FullPath.Buffer);
|
|
}
|
|
|
|
return AFP_ERR_EXTENDED;
|
|
}
|
|
|
|
|
|
|
|
/*** AfpFspDispDelete
|
|
*
|
|
* This is the worker routine for the AfpDelete API. Deleting an open file
|
|
* or a directory that is not empty is not permitted under AFP.
|
|
*
|
|
* The request packet is represented below
|
|
*
|
|
* sda_ReqBlock PCONNDESC pConnDesc
|
|
* sda_ReqBlock DWORD ParentId
|
|
* sda_Name1 ANSI_STRING Path
|
|
*/
|
|
AFPSTATUS FASTCALL
|
|
AfpFspDispDelete(
|
|
IN PSDA pSda
|
|
)
|
|
{
|
|
PATHMAPENTITY PME;
|
|
PVOLDESC pVolDesc;
|
|
PCONNDESC pConnDesc;
|
|
FILEDIRPARM FDParm;
|
|
DWORD Bitmap, NTAttr;
|
|
AFPSTATUS Status = AFP_ERR_PARAM;
|
|
FILESYSHANDLE hParent;
|
|
WCHAR PathBuf[BIG_PATH_LEN];
|
|
BOOLEAN InRoot;
|
|
struct _RequestPacket
|
|
{
|
|
PCONNDESC _pConnDesc;
|
|
DWORD _ParentId;
|
|
};
|
|
|
|
PAGED_CODE();
|
|
|
|
DBGPRINT(DBG_COMP_AFPAPI_FD, DBG_LEVEL_INFO,
|
|
("AfpFspDispDelete: Entered\n"));
|
|
|
|
ASSERT(VALID_CONNDESC(pReqPkt->_pConnDesc));
|
|
pConnDesc = pReqPkt->_pConnDesc;
|
|
|
|
pVolDesc = pReqPkt->_pConnDesc->cds_pVolDesc;
|
|
|
|
ASSERT(VALID_VOLDESC(pVolDesc));
|
|
|
|
AfpInitializeFDParms(&FDParm);
|
|
AfpInitializePME(&PME, sizeof(PathBuf), PathBuf);
|
|
Bitmap = FD_BITMAP_ATTR | FD_INTERNAL_BITMAP_OPENACCESS_DELETE;
|
|
|
|
AfpSwmrAcquireExclusive(&pVolDesc->vds_IdDbAccessLock);
|
|
|
|
do
|
|
{
|
|
hParent.fsh_FileHandle = NULL;
|
|
if (!NT_SUCCESS(Status = AfpMapAfpPath(pReqPkt->_pConnDesc,
|
|
pReqPkt->_ParentId,
|
|
&pSda->sda_Name1,
|
|
pSda->sda_PathType,
|
|
Lookup,
|
|
DFE_ANY,
|
|
Bitmap,
|
|
&PME,
|
|
&FDParm)))
|
|
{
|
|
PME.pme_Handle.fsh_FileHandle = NULL;
|
|
break;
|
|
}
|
|
|
|
if ((FDParm._fdp_AfpId == AFP_ID_ROOT) ||
|
|
(FDParm._fdp_AfpId == AFP_ID_NETWORK_TRASH))
|
|
{
|
|
Status = AFP_ERR_ACCESS_DENIED;
|
|
break;
|
|
}
|
|
|
|
if (FDParm._fdp_Attr & (FILE_BITMAP_ATTR_DATAOPEN | FILE_BITMAP_ATTR_RESCOPEN))
|
|
{
|
|
ASSERT(!(FDParm._fdp_Flags & DFE_FLAGS_DIR));
|
|
Status = AFP_ERR_FILE_BUSY; // Cannot delete an open file
|
|
break;
|
|
}
|
|
|
|
if (!NT_SUCCESS(Status = AfpCheckForInhibit(&PME.pme_Handle,
|
|
FD_BITMAP_ATTR_DELETEINH,
|
|
FDParm._fdp_Attr,
|
|
&NTAttr)))
|
|
{
|
|
break;
|
|
}
|
|
|
|
// Check for SeeFiles or SeeFolders on the parent dir
|
|
if (!NT_SUCCESS(Status = AfpCheckParentPermissions(pReqPkt->_pConnDesc,
|
|
FDParm._fdp_ParentId,
|
|
&PME.pme_ParentPath,
|
|
(FDParm._fdp_Flags & DFE_FLAGS_DIR) ?
|
|
DIR_ACCESS_SEARCH : DIR_ACCESS_READ,
|
|
&hParent,
|
|
NULL)))
|
|
{
|
|
break;
|
|
}
|
|
|
|
if (NTAttr & FILE_ATTRIBUTE_READONLY)
|
|
{
|
|
// We must remove the ReadOnly attribute to delete the file/dir
|
|
Status = AfpIoSetTimesnAttr(&PME.pme_Handle,
|
|
NULL,
|
|
NULL,
|
|
0,
|
|
FILE_ATTRIBUTE_READONLY,
|
|
pVolDesc,
|
|
&PME.pme_FullPath);
|
|
}
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
InRoot = (PME.pme_ParentPath.Length == 0) ? True : False;
|
|
Status = AfpIoMarkFileForDelete(&PME.pme_Handle,
|
|
pVolDesc,
|
|
&PME.pme_FullPath,
|
|
InRoot ? NULL : &PME.pme_ParentPath);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
Status = AfpIoConvertNTStatusToAfpStatus(Status);
|
|
}
|
|
|
|
// !!! HACK ALERT !!!
|
|
// At this point we are pretty much done i.e. the delete has either
|
|
// succeeded or failed and we can return doing the rest of the work
|
|
// post-reply. Any errors from now on SHOULD BE IGNORED. Also NO
|
|
// REFERENCE SHOULD BE MADE TO the pSda & pConnDesc. Status should
|
|
// not be changed either. Also reference the Volume for good measure.
|
|
// It cannot fail !!!
|
|
AfpVolumeReference(pVolDesc);
|
|
|
|
AfpCompleteApiProcessing(pSda, Status);
|
|
|
|
if (NT_SUCCESS(Status)) // Delete succeeded
|
|
{
|
|
ASSERT(VALID_DFE(PME.pme_pDfEntry));
|
|
ASSERT(PME.pme_pDfEntry->dfe_AfpId == FDParm._fdp_AfpId);
|
|
AfpDeleteDfEntry(pVolDesc, PME.pme_pDfEntry);
|
|
AfpIoClose(&PME.pme_Handle);
|
|
AfpCacheParentModTime(pVolDesc,
|
|
&hParent,
|
|
NULL,
|
|
NULL,
|
|
FDParm._fdp_ParentId);
|
|
}
|
|
else if (NTAttr & FILE_ATTRIBUTE_READONLY) // Delete failed
|
|
{
|
|
// Set the ReadOnly attribute back on the file/dir if need be
|
|
Status = AfpIoSetTimesnAttr(&PME.pme_Handle,
|
|
NULL,
|
|
NULL,
|
|
FILE_ATTRIBUTE_READONLY,
|
|
0,
|
|
pVolDesc,
|
|
&PME.pme_FullPath);
|
|
ASSERT(NT_SUCCESS(Status));
|
|
}
|
|
Status = AFP_ERR_EXTENDED;
|
|
}
|
|
ASSERT (Status == AFP_ERR_EXTENDED);
|
|
AfpVolumeDereference(pVolDesc);
|
|
} while (False);
|
|
|
|
// Close file handle so file really gets deleted before mac can come
|
|
// back in with another request using same filename (like create)
|
|
if (PME.pme_Handle.fsh_FileHandle != NULL)
|
|
AfpIoClose(&PME.pme_Handle);
|
|
|
|
AfpSwmrRelease(&pVolDesc->vds_IdDbAccessLock);
|
|
|
|
if (hParent.fsh_FileHandle != NULL)
|
|
AfpIoClose(&hParent);
|
|
|
|
if ((PME.pme_FullPath.Buffer != NULL) &&
|
|
(PME.pme_FullPath.Buffer != PathBuf))
|
|
{
|
|
AfpFreeMemory(PME.pme_FullPath.Buffer);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
|
|
/*** AfpFspDispRename
|
|
*
|
|
* This is the worker routine for the AfpRename API. Renaming a file does
|
|
* NOT provoke a new Extension-Type/Creator mapping. Renaming an open file
|
|
* is permitted under AFP.
|
|
*
|
|
* The request packet is represented below
|
|
*
|
|
* sda_ReqBlock PCONNDESC pConnDesc
|
|
* sda_ReqBlock DWORD ParentId
|
|
* sda_Name1 ANSI_STRING Path
|
|
* sda_Name2 ANSI_STRING New name
|
|
*/
|
|
AFPSTATUS FASTCALL
|
|
AfpFspDispRename(
|
|
IN PSDA pSda
|
|
)
|
|
{
|
|
PATHMAPENTITY PME;
|
|
PVOLDESC pVolDesc;
|
|
FILEDIRPARM FDParm;
|
|
DWORD Bitmap, NTAttr;
|
|
AFPSTATUS Status = AFP_ERR_PARAM;
|
|
UNICODE_STRING uNewName;
|
|
WCHAR wcbuf[AFP_FILENAME_LEN+1];
|
|
WCHAR PathBuf[BIG_PATH_LEN];
|
|
PDFENTRY pDfEntry;
|
|
FILESYSHANDLE hParent;
|
|
BOOLEAN InRoot;
|
|
struct _RequestPacket
|
|
{
|
|
PCONNDESC _pConnDesc;
|
|
DWORD _ParentId;
|
|
};
|
|
|
|
PAGED_CODE();
|
|
|
|
DBGPRINT(DBG_COMP_AFPAPI_FD, DBG_LEVEL_INFO,
|
|
("AfpFspDispRename: Entered\n"));
|
|
|
|
ASSERT(VALID_CONNDESC(pReqPkt->_pConnDesc));
|
|
|
|
pVolDesc = pReqPkt->_pConnDesc->cds_pVolDesc;
|
|
|
|
ASSERT(VALID_VOLDESC(pVolDesc));
|
|
|
|
AfpInitializeFDParms(&FDParm);
|
|
AfpInitializePME(&PME, sizeof(PathBuf), PathBuf);
|
|
AfpSetEmptyUnicodeString(&uNewName, sizeof(wcbuf), wcbuf);
|
|
|
|
Bitmap = FD_BITMAP_ATTR | FD_INTERNAL_BITMAP_OPENACCESS_DELETE;
|
|
hParent.fsh_FileHandle = NULL;
|
|
|
|
AfpSwmrAcquireExclusive(&pVolDesc->vds_IdDbAccessLock);
|
|
|
|
do
|
|
{
|
|
// Make sure the new name is not a null string or too long
|
|
if ((pSda->sda_Name2.Length == 0) ||
|
|
(pSda->sda_Name2.Length > AFP_FILENAME_LEN) ||
|
|
((pSda->sda_PathType == AFP_SHORTNAME) &&
|
|
!AfpIsLegalShortname(&pSda->sda_Name2)) ||
|
|
(!NT_SUCCESS(AfpConvertStringToMungedUnicode(&pSda->sda_Name2,
|
|
&uNewName))))
|
|
break;
|
|
|
|
if (!NT_SUCCESS(Status = AfpMapAfpPath(pReqPkt->_pConnDesc,
|
|
pReqPkt->_ParentId,
|
|
&pSda->sda_Name1,
|
|
pSda->sda_PathType,
|
|
Lookup,
|
|
DFE_ANY,
|
|
Bitmap,
|
|
&PME,
|
|
&FDParm)))
|
|
{
|
|
PME.pme_Handle.fsh_FileHandle = NULL;
|
|
break;
|
|
}
|
|
|
|
if ((FDParm._fdp_AfpId == AFP_ID_ROOT) ||
|
|
(FDParm._fdp_AfpId == AFP_ID_NETWORK_TRASH))
|
|
{
|
|
Status = AFP_ERR_CANT_RENAME;
|
|
break;
|
|
}
|
|
|
|
// Check if the RO bit is on & retain the mod time
|
|
if (!NT_SUCCESS(Status = AfpCheckForInhibit(&PME.pme_Handle,
|
|
FD_BITMAP_ATTR_RENAMEINH,
|
|
FDParm._fdp_Attr,
|
|
&NTAttr)))
|
|
{
|
|
break;
|
|
}
|
|
|
|
// Check for SeeFiles or SeeFolders on the parent dir
|
|
if (!NT_SUCCESS(Status = AfpCheckParentPermissions(pReqPkt->_pConnDesc,
|
|
FDParm._fdp_ParentId,
|
|
&PME.pme_ParentPath,
|
|
(FDParm._fdp_Flags & DFE_FLAGS_DIR) ?
|
|
DIR_ACCESS_SEARCH : DIR_ACCESS_READ,
|
|
&hParent,
|
|
NULL)))
|
|
{
|
|
break;
|
|
}
|
|
|
|
if (NTAttr & FILE_ATTRIBUTE_READONLY)
|
|
{
|
|
// We must temporarily remove the ReadOnly attribute so that
|
|
// we can rename the file/dir
|
|
Status = AfpIoSetTimesnAttr(&PME.pme_Handle,
|
|
NULL,
|
|
NULL,
|
|
0,
|
|
FILE_ATTRIBUTE_READONLY,
|
|
pVolDesc,
|
|
&PME.pme_FullPath);
|
|
}
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
// We must impersonate to do the rename since it is name based
|
|
AfpImpersonateClient(pSda);
|
|
|
|
InRoot = (PME.pme_ParentPath.Length == 0) ? True : False;
|
|
Status = AfpIoMoveAndOrRename(&PME.pme_Handle,
|
|
NULL,
|
|
&uNewName,
|
|
pVolDesc,
|
|
&PME.pme_FullPath,
|
|
InRoot ? NULL : &PME.pme_ParentPath,
|
|
NULL,
|
|
NULL);
|
|
|
|
AfpRevertBack();
|
|
|
|
if (NT_SUCCESS(Status)) // Rename succeeded
|
|
{
|
|
if ((pDfEntry = AfpFindDfEntryById(pVolDesc,
|
|
FDParm._fdp_AfpId,
|
|
DFE_ANY)) != NULL)
|
|
{
|
|
ASSERT(((pDfEntry->dfe_Flags & DFE_FLAGS_DFBITS) &
|
|
FDParm._fdp_Flags) != 0);
|
|
pDfEntry = AfpRenameDfEntry(pVolDesc,
|
|
pDfEntry,
|
|
&uNewName);
|
|
if (pDfEntry == NULL)
|
|
{
|
|
// We could not rename the id entry, so
|
|
// just delete it, and hope the parent dir
|
|
// gets enumerated again
|
|
// NOTE: How will the parent directory
|
|
// get re-enumerated now ?
|
|
ASSERT(VALID_DFE(PME.pme_pDfEntry));
|
|
ASSERT(PME.pme_pDfEntry->dfe_AfpId == FDParm._fdp_AfpId);
|
|
AfpDeleteDfEntry(pVolDesc, PME.pme_pDfEntry);
|
|
Status = AFP_ERR_MISC; // Out of memory
|
|
}
|
|
else
|
|
{
|
|
AfpCacheParentModTime(pVolDesc,
|
|
&hParent,
|
|
NULL,
|
|
pDfEntry->dfe_Parent,
|
|
0);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Status = AFP_ERR_MISC; // Could not delete ReadOnly attribute
|
|
break;
|
|
}
|
|
|
|
// Set the ReadOnly attribute back on the file/dir if need be.
|
|
if (NTAttr & FILE_ATTRIBUTE_READONLY)
|
|
AfpIoSetTimesnAttr(&PME.pme_Handle,
|
|
NULL,
|
|
NULL,
|
|
FILE_ATTRIBUTE_READONLY,
|
|
0,
|
|
pVolDesc,
|
|
&PME.pme_FullPath);
|
|
} while (False);
|
|
|
|
// Return before we close thus saving some time
|
|
AfpCompleteApiProcessing(pSda, Status);
|
|
|
|
if (PME.pme_Handle.fsh_FileHandle != NULL)
|
|
AfpIoClose(&PME.pme_Handle);
|
|
|
|
if (hParent.fsh_FileHandle != NULL)
|
|
{
|
|
AfpIoClose(&hParent);
|
|
}
|
|
|
|
AfpSwmrRelease(&pVolDesc->vds_IdDbAccessLock);
|
|
|
|
if ((PME.pme_FullPath.Buffer != NULL) &&
|
|
(PME.pme_FullPath.Buffer != PathBuf))
|
|
{
|
|
AfpFreeMemory(PME.pme_FullPath.Buffer);
|
|
}
|
|
|
|
return AFP_ERR_EXTENDED;
|
|
}
|
|
|
|
|
|
|
|
/*** AfpFspDispMoveAndRename
|
|
*
|
|
* This is the worker routine for the AfpMoveAndRename API. Note that
|
|
* in AFP 2.x, a FILE (not a dir) CAN BE MOVED when its RenameInhibit bit
|
|
* is set if it is NOT BEING RENAMED.
|
|
*
|
|
* The request packet is represented below
|
|
*
|
|
* sda_ReqBlock PCONNDESC pConnDesc
|
|
* sda_ReqBlock DWORD Source ParentId
|
|
* sda_ReqBlock DWORD Dest ParentId
|
|
* sda_Name1 ANSI_STRING Source Path
|
|
* sda_Name2 ANSI_STRING Dest Path
|
|
* sda_Name3 ANSI_STRING New Name
|
|
*/
|
|
AFPSTATUS FASTCALL
|
|
AfpFspDispMoveAndRename(
|
|
IN PSDA pSda
|
|
)
|
|
{
|
|
PATHMAPENTITY PMEsrc, PMEdst;
|
|
PVOLDESC pVolDesc;
|
|
FILEDIRPARM FDParmsrc, FDParmdst;
|
|
DWORD Bitmap, NTAttr;
|
|
AFPSTATUS Status = AFP_ERR_PARAM;
|
|
UNICODE_STRING uNewName;
|
|
WCHAR wcbuf[AFP_FILENAME_LEN+1];
|
|
BOOLEAN Rename = True, Move = True, SrcInRoot, DstInRoot;
|
|
PDFENTRY pDfesrc, pDfedst, pDfeParentsrc;
|
|
FILESYSHANDLE hSrcParent;
|
|
struct _RequestPacket
|
|
{
|
|
PCONNDESC _pConnDesc;
|
|
DWORD _SrcParentId;
|
|
DWORD _DstParentId;
|
|
};
|
|
|
|
PAGED_CODE();
|
|
|
|
DBGPRINT(DBG_COMP_AFPAPI_FD, DBG_LEVEL_INFO,
|
|
("AfpFspDispMoveAndRename: Entered\n"));
|
|
|
|
ASSERT(VALID_CONNDESC(pReqPkt->_pConnDesc));
|
|
|
|
pVolDesc = pReqPkt->_pConnDesc->cds_pVolDesc;
|
|
|
|
ASSERT(VALID_VOLDESC(pVolDesc));
|
|
|
|
AfpInitializeFDParms(&FDParmsrc);
|
|
AfpInitializeFDParms(&FDParmdst);
|
|
AfpInitializePME(&PMEsrc, 0, NULL);
|
|
AfpInitializePME(&PMEdst, 0, NULL);
|
|
|
|
Bitmap = FD_BITMAP_ATTR | FD_BITMAP_LONGNAME | FD_INTERNAL_BITMAP_OPENACCESS_DELETE;
|
|
AfpSetEmptyUnicodeString(&uNewName, sizeof(wcbuf), wcbuf);
|
|
hSrcParent.fsh_FileHandle = NULL;
|
|
|
|
AfpSwmrAcquireExclusive(&pVolDesc->vds_IdDbAccessLock);
|
|
|
|
do
|
|
{
|
|
// Make sure the new name is not too long
|
|
if ((pSda->sda_Name3.Length > 0) &&
|
|
((pSda->sda_Name3.Length > AFP_FILENAME_LEN) ||
|
|
((pSda->sda_PathType == AFP_SHORTNAME) &&
|
|
!AfpIsLegalShortname(&pSda->sda_Name3)) ||
|
|
(!NT_SUCCESS(AfpConvertStringToMungedUnicode(&pSda->sda_Name3,
|
|
&uNewName)))))
|
|
break;
|
|
|
|
// Map source path for lookup (could be file or dir).
|
|
// We ask for the finderinfo in case the user is moving an
|
|
// application file to another directory, we can update its
|
|
// parent dirid in the APPL desktop database
|
|
if (!NT_SUCCESS(Status = AfpMapAfpPath(pReqPkt->_pConnDesc,
|
|
pReqPkt->_SrcParentId,
|
|
&pSda->sda_Name1,
|
|
pSda->sda_PathType,
|
|
Lookup,
|
|
DFE_ANY,
|
|
Bitmap | FD_BITMAP_FINDERINFO,
|
|
&PMEsrc,
|
|
&FDParmsrc)))
|
|
{
|
|
PMEsrc.pme_Handle.fsh_FileHandle = NULL;
|
|
break;
|
|
}
|
|
|
|
// Map the destination parent directory path for lookup
|
|
if (!NT_SUCCESS(Status = AfpMapAfpPath(pReqPkt->_pConnDesc,
|
|
pReqPkt->_DstParentId,
|
|
&pSda->sda_Name2,
|
|
pSda->sda_PathType,
|
|
Lookup,
|
|
DFE_DIR,
|
|
0,
|
|
&PMEdst,
|
|
&FDParmdst)))
|
|
{
|
|
PMEdst.pme_Handle.fsh_FileHandle = NULL;
|
|
break;
|
|
}
|
|
|
|
if ((FDParmsrc._fdp_AfpId == AFP_ID_ROOT) ||
|
|
(FDParmsrc._fdp_AfpId == AFP_ID_NETWORK_TRASH))
|
|
{
|
|
Status = AFP_ERR_CANT_MOVE;
|
|
break;
|
|
}
|
|
|
|
if (!NT_SUCCESS(Status = AfpCheckForInhibit(&PMEsrc.pme_Handle,
|
|
FD_BITMAP_ATTR_RENAMEINH,
|
|
FDParmsrc._fdp_Attr,
|
|
&NTAttr)))
|
|
{
|
|
// Files (not dirs) marked RenameInhibit that are NOT being
|
|
// renamed are allowed to be moved in AFP 2.x
|
|
if (!((Status == AFP_ERR_OBJECT_LOCKED) &&
|
|
(!IsDir(&FDParmsrc)) &&
|
|
(pSda->sda_Name3.Length == 0)))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (FDParmsrc._fdp_ParentId == FDParmdst._fdp_AfpId)
|
|
{
|
|
// if the parent directories are the same, we are not
|
|
// moving anything to a new directory, so the change
|
|
// notify we expect will be a rename in the source dir.
|
|
Move = False;
|
|
|
|
//
|
|
// Trying to move a file onto itself. Just return success.
|
|
// (some apps move files onto
|
|
// themselves for who knows what reason)
|
|
//
|
|
if ((pSda->sda_Name3.Length == 0) ||
|
|
RtlEqualString(&pSda->sda_Name3,
|
|
&FDParmsrc._fdp_LongName,
|
|
False))
|
|
{
|
|
Status = AFP_ERR_NONE;
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
// Check for SeeFiles or SeeFolders on the source parent dir
|
|
if (!NT_SUCCESS(Status = AfpCheckParentPermissions(pReqPkt->_pConnDesc,
|
|
FDParmsrc._fdp_ParentId,
|
|
&PMEsrc.pme_ParentPath,
|
|
(FDParmsrc._fdp_Flags & DFE_FLAGS_DIR) ?
|
|
DIR_ACCESS_SEARCH : DIR_ACCESS_READ,
|
|
&hSrcParent,
|
|
NULL)))
|
|
{
|
|
break;
|
|
}
|
|
|
|
if (NTAttr & FILE_ATTRIBUTE_READONLY)
|
|
{
|
|
// We must temporarily remove the ReadOnly attribute so that
|
|
// we can move the file/dir
|
|
Status = AfpIoSetTimesnAttr(&PMEsrc.pme_Handle,
|
|
NULL,
|
|
NULL,
|
|
0,
|
|
FILE_ATTRIBUTE_READONLY,
|
|
pVolDesc,
|
|
&PMEsrc.pme_FullPath);
|
|
}
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
// If no new name was supplied, we need to use the
|
|
// current name
|
|
if (pSda->sda_Name3.Length == 0)
|
|
{
|
|
Rename = False;
|
|
uNewName = PMEsrc.pme_UTail;
|
|
}
|
|
|
|
// We must impersonate to do the move since it is name based
|
|
AfpImpersonateClient(pSda);
|
|
|
|
if (Move)
|
|
{
|
|
// if we are moving, we will also get an ADDED notification
|
|
// for the destination directory. Since we have the path
|
|
// of the parent dir, but we really want the name of the
|
|
// thing we are about to move and/or rename, munge the
|
|
// destination paths to reflect the new name of the thing
|
|
// we are moving/renaming
|
|
|
|
PMEdst.pme_ParentPath = PMEdst.pme_FullPath;
|
|
if (PMEdst.pme_FullPath.Length > 0)
|
|
{
|
|
PMEdst.pme_FullPath.Buffer[PMEdst.pme_FullPath.Length / sizeof(WCHAR)] = L'\\';
|
|
PMEdst.pme_FullPath.Length += sizeof(WCHAR);
|
|
}
|
|
Status = RtlAppendUnicodeStringToString(&PMEdst.pme_FullPath,
|
|
&uNewName);
|
|
ASSERT(NT_SUCCESS(Status));
|
|
}
|
|
|
|
SrcInRoot = (PMEsrc.pme_ParentPath.Length == 0) ? True : False;
|
|
DstInRoot = (PMEdst.pme_ParentPath.Length == 0) ? True : False;
|
|
Status = AfpIoMoveAndOrRename(&PMEsrc.pme_Handle,
|
|
Move ? &PMEdst.pme_Handle : NULL,
|
|
&uNewName,
|
|
pVolDesc,
|
|
&PMEsrc.pme_FullPath,
|
|
SrcInRoot ? NULL : &PMEsrc.pme_ParentPath,
|
|
Move ? &PMEdst.pme_FullPath : NULL,
|
|
(Move && !DstInRoot) ? &PMEdst.pme_ParentPath : NULL);
|
|
AfpRevertBack();
|
|
|
|
if (NT_SUCCESS(Status)) // Move succeeded
|
|
{
|
|
if (((pDfesrc = AfpFindDfEntryById(pVolDesc,
|
|
FDParmsrc._fdp_AfpId,
|
|
DFE_ANY)) != NULL) &&
|
|
((pDfedst = AfpFindDfEntryById(pVolDesc,
|
|
FDParmdst._fdp_AfpId,
|
|
DFE_DIR)) != NULL))
|
|
|
|
{
|
|
ASSERT(((pDfesrc->dfe_Flags & DFE_FLAGS_DFBITS) &
|
|
FDParmsrc._fdp_Flags) != 0);
|
|
pDfeParentsrc = pDfesrc->dfe_Parent;
|
|
pDfesrc = AfpMoveDfEntry(pVolDesc,
|
|
pDfesrc,
|
|
pDfedst,
|
|
Rename ? &uNewName : NULL);
|
|
if (pDfesrc == NULL)
|
|
{
|
|
// We could not move the id entry, so
|
|
// just delete it.
|
|
ASSERT(VALID_DFE(PMEsrc.pme_pDfEntry));
|
|
ASSERT(PMEsrc.pme_pDfEntry->dfe_AfpId == FDParmsrc._fdp_AfpId);
|
|
AfpDeleteDfEntry(pVolDesc, PMEsrc.pme_pDfEntry);
|
|
Status = AFP_ERR_MISC; // Out of memory
|
|
}
|
|
|
|
// update cached mod time of source parent directory
|
|
AfpCacheParentModTime(pVolDesc,
|
|
&hSrcParent,
|
|
NULL,
|
|
pDfeParentsrc,
|
|
0);
|
|
if (Move)
|
|
{
|
|
// update cached mod time of destination directory
|
|
AfpCacheParentModTime(pVolDesc,
|
|
&PMEdst.pme_Handle,
|
|
NULL,
|
|
pDfedst,
|
|
0);
|
|
//
|
|
// if we just moved an application program, update
|
|
// the parentID in the corresponding APPL mapping.
|
|
//
|
|
if ((!IsDir(&FDParmsrc)) &&
|
|
(FDParmsrc._fdp_FinderInfo.fd_TypeD == *(PDWORD)"APPL"))
|
|
{
|
|
AfpAddAppl(pVolDesc,
|
|
FDParmsrc._fdp_FinderInfo.fd_CreatorD,
|
|
0,
|
|
FDParmsrc._fdp_AfpId,
|
|
True,
|
|
FDParmdst._fdp_AfpId);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Status = AFP_ERR_MISC; // Could not delete ReadOnly attribute
|
|
break;
|
|
}
|
|
|
|
// Set the ReadOnly attribute back on the file/dir if need be
|
|
if (NTAttr & FILE_ATTRIBUTE_READONLY)
|
|
AfpIoSetTimesnAttr(&PMEsrc.pme_Handle,
|
|
NULL,
|
|
NULL,
|
|
FILE_ATTRIBUTE_READONLY,
|
|
0,
|
|
pVolDesc,
|
|
&PMEsrc.pme_FullPath);
|
|
} while (False);
|
|
|
|
// Return before we close thus saving some time
|
|
AfpCompleteApiProcessing(pSda, Status);
|
|
|
|
AfpSwmrRelease(&pVolDesc->vds_IdDbAccessLock);
|
|
|
|
if (PMEsrc.pme_Handle.fsh_FileHandle != NULL)
|
|
AfpIoClose(&PMEsrc.pme_Handle);
|
|
|
|
if (PMEdst.pme_Handle.fsh_FileHandle != NULL)
|
|
AfpIoClose(&PMEdst.pme_Handle);
|
|
|
|
if (hSrcParent.fsh_FileHandle != NULL)
|
|
AfpIoClose(&hSrcParent);
|
|
|
|
if (PMEsrc.pme_FullPath.Buffer != NULL)
|
|
AfpFreeMemory(PMEsrc.pme_FullPath.Buffer);
|
|
|
|
if (PMEdst.pme_FullPath.Buffer != NULL)
|
|
AfpFreeMemory(PMEdst.pme_FullPath.Buffer);
|
|
|
|
return AFP_ERR_EXTENDED;
|
|
}
|
|
|
|
|
|
/*** AfpFspDispCatSearch
|
|
*
|
|
* This is the worker routine for the AfpCatSearch API.
|
|
*
|
|
* The request packet is represented below
|
|
*
|
|
* sda_ReqBlock PCONNDESC pConnDesc
|
|
* sda_ReqBlock DWORD RequestedMatches
|
|
* sda_Name1 ANSI_STRING Catalog Position - 16 bytes
|
|
* sda_Name2 ANSI_STRING Everything else - needs unmarshalling
|
|
*
|
|
* The reason we could not unmarshall all the parameters is because this
|
|
* API's parameters do not conform to the common way all the other APIs'
|
|
* parameters do, and therefore we cannot use the common code and table
|
|
* structures in afpapi.c.
|
|
*/
|
|
AFPSTATUS FASTCALL
|
|
AfpFspDispCatSearch(
|
|
IN PSDA pSda
|
|
)
|
|
{
|
|
AFPSTATUS Status = AFP_ERR_PARAM;
|
|
PBYTE pEndOfBuffer;
|
|
USHORT Flags;
|
|
SHORT SizeLeft = 0;
|
|
PVOLDESC pVolDesc;
|
|
DWORD FileResultBitmap;
|
|
DWORD DirResultBitmap;
|
|
DWORD RequestBitmap;
|
|
DWORD Count;
|
|
BOOLEAN fPartialName = False, FreeReplyBuf = False;
|
|
FILEDIRPARM FDPLowerAndValue, FDPUpperAndMask;
|
|
PCATSEARCHSPEC pSpec1, pSpec2;
|
|
UNICODE_STRING MatchString;
|
|
WCHAR strbuf[AFP_LONGNAME_LEN+1];
|
|
|
|
struct _RequestPacket
|
|
{
|
|
PCONNDESC _pConnDesc;
|
|
DWORD _RequestedMatches;
|
|
};
|
|
|
|
// The part of the request buffer that could not be unmarshalled into
|
|
// fields in the Sda because they don't conform to any of the other APIs.
|
|
// These will be unmarshalled here into local variables, the sda_Name2
|
|
// can be cast to this structure for easy access.
|
|
struct _RestOfRawRequest
|
|
{
|
|
USHORT _FileResultBitmap;
|
|
USHORT _DirResultBitmap;
|
|
BYTE _fPartialName;
|
|
BYTE _Pad1;
|
|
USHORT _RequestBitmap;
|
|
// Spec1 and Spec2 follow
|
|
};
|
|
|
|
#define pRawPkt ((struct _RestOfRawRequest *)(pSda->sda_Name2.Buffer))
|
|
|
|
struct _ResponsePacket
|
|
{
|
|
BYTE __CatPosition[16];
|
|
BYTE __FileBitmap[2];
|
|
BYTE __DirBitmap[2];
|
|
BYTE __ActualCount[4];
|
|
};
|
|
|
|
PAGED_CODE();
|
|
|
|
DBGPRINT(DBG_COMP_AFPAPI_FD, DBG_LEVEL_INFO,
|
|
("AfpFspDispCatSearch: Entered\n"));
|
|
|
|
ASSERT(VALID_CONNDESC(pReqPkt->_pConnDesc));
|
|
|
|
do
|
|
{
|
|
if (pSda->sda_Name2.Length < (sizeof(struct _RestOfRawRequest) +
|
|
(2 * sizeof(CATSEARCHSPEC))))
|
|
{
|
|
// The request buffer must be at least as big as the rest of the
|
|
// parameters that weren't yet unmarshalled, plus 2 Spec structs
|
|
break;
|
|
}
|
|
|
|
GETSHORT2DWORD(&FileResultBitmap, &pRawPkt->_FileResultBitmap);
|
|
GETSHORT2DWORD(&DirResultBitmap, &pRawPkt->_DirResultBitmap);
|
|
GETSHORT2DWORD(&RequestBitmap, &pRawPkt->_RequestBitmap);
|
|
|
|
if ( (pRawPkt->_fPartialName & 0x80) != 0 )
|
|
{
|
|
fPartialName = True;
|
|
}
|
|
|
|
//
|
|
// Validate the bitmaps
|
|
//
|
|
if (((FileResultBitmap | DirResultBitmap) == 0) ||
|
|
((FileResultBitmap | DirResultBitmap) & ~FD_VALID_SEARCH_RESULT) ||
|
|
(RequestBitmap == 0))
|
|
{
|
|
Status = AFP_ERR_BITMAP;
|
|
break;
|
|
}
|
|
|
|
// make sure CatSearch is enabled: if it's disabled, reject the call
|
|
if (!(pReqPkt->_pConnDesc->cds_pVolDesc->vds_Flags & AFP_VOLUME_SUPPORTS_CATSRCH))
|
|
{
|
|
DBGPRINT(DBG_COMP_AFPAPI_FD, DBG_LEVEL_ERR,
|
|
("AfpFspDispCatSearch: CATSRCH not supported by volume\n"));
|
|
|
|
Status = AFP_ERR_CALL_NOT_SUPPORTED;
|
|
break;
|
|
}
|
|
|
|
AfpInitializeFDParms(&FDPLowerAndValue);
|
|
AfpInitializeFDParms(&FDPUpperAndMask);
|
|
|
|
if (DirResultBitmap == 0)
|
|
{
|
|
FDPLowerAndValue._fdp_Flags = FDPUpperAndMask._fdp_Flags = DFE_FLAGS_FILE_WITH_ID;
|
|
if (RequestBitmap & ~FILE_VALID_SEARCH_CRITERIA)
|
|
{
|
|
Status = AFP_ERR_BITMAP;
|
|
break;
|
|
}
|
|
}
|
|
else if (FileResultBitmap == 0)
|
|
{
|
|
FDPLowerAndValue._fdp_Flags = FDPUpperAndMask._fdp_Flags = DFE_FLAGS_DIR;
|
|
if (RequestBitmap & ~DIR_VALID_SEARCH_CRITERIA)
|
|
{
|
|
Status = AFP_ERR_BITMAP;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
FDPLowerAndValue._fdp_Flags = FDPUpperAndMask._fdp_Flags = DFE_FLAGS_FILE_WITH_ID | DFE_FLAGS_DIR;
|
|
if (RequestBitmap & ~FD_VALID_SEARCH_CRITERIA)
|
|
{
|
|
Status = AFP_ERR_BITMAP;
|
|
break;
|
|
}
|
|
}
|
|
|
|
Flags = ((PCATALOGPOSITION)pSda->sda_Name1.Buffer)->cp_Flags;
|
|
// The caller should not muck with the catalog position at all
|
|
if ((Flags & ~CATFLAGS_VALID) ||
|
|
// Writelock should only be required if we were about to search files
|
|
((Flags & CATFLAGS_WRITELOCK_REQUIRED) && !(Flags & CATFLAGS_SEARCHING_FILES)))
|
|
// NOTE: also should make sure ONLY ONE of the SEARCHING bits is on
|
|
break;
|
|
|
|
//
|
|
// Now unpack the search criteria
|
|
//
|
|
MatchString.Length = 0;
|
|
MatchString.MaximumLength = sizeof(strbuf);
|
|
MatchString.Buffer = strbuf;
|
|
|
|
Status = AfpUnpackCatSearchSpecs((PBYTE)pSda->sda_Name2.Buffer + sizeof(struct _RestOfRawRequest),
|
|
(USHORT)(pSda->sda_Name2.Length - sizeof(struct _RestOfRawRequest)),
|
|
RequestBitmap,
|
|
&FDPLowerAndValue,
|
|
&FDPUpperAndMask,
|
|
&MatchString);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Allocate the reply buffer. Estimate the required size by using
|
|
// the maximum possible filename length plus potential pad bytes for
|
|
// even alignment of each entry plus the length of the parent dirid.
|
|
//
|
|
pSda->sda_ReplySize = (USHORT)(SIZE_RESPPKT + (pReqPkt->_RequestedMatches *
|
|
((2 * sizeof(BYTE)) + sizeof(DWORD) + sizeof(USHORT) + sizeof(BYTE) + AFP_LONGNAME_LEN + 1)));
|
|
|
|
if (pSda->sda_ReplySize > MAX_CATSEARCH_REPLY)
|
|
{
|
|
pSda->sda_ReplySize = MAX_CATSEARCH_REPLY;
|
|
}
|
|
|
|
AfpIOAllocBackFillBuffer(pSda);
|
|
|
|
if (pSda->sda_ReplyBuf == NULL)
|
|
{
|
|
pSda->sda_ReplySize = 0;
|
|
Status = AFP_ERR_MISC;
|
|
break;
|
|
}
|
|
|
|
#if DBG
|
|
AfpPutGuardSignature(pSda);
|
|
#endif
|
|
|
|
FreeReplyBuf = True;
|
|
|
|
//
|
|
// Perform the search
|
|
//
|
|
|
|
FDPUpperAndMask._fdp_fPartialName = fPartialName;
|
|
|
|
Count = pReqPkt->_RequestedMatches;
|
|
Status = AfpCatSearch(pReqPkt->_pConnDesc,
|
|
(PCATALOGPOSITION)pSda->sda_Name1.Buffer, // CatalogPosition
|
|
RequestBitmap,
|
|
FileResultBitmap,
|
|
DirResultBitmap,
|
|
&FDPLowerAndValue,
|
|
&FDPUpperAndMask,
|
|
&MatchString,
|
|
&Count, // IN OUT
|
|
(SHORT)(pSda->sda_ReplySize - SIZE_RESPPKT),
|
|
&SizeLeft,
|
|
pSda->sda_ReplyBuf + SIZE_RESPPKT,
|
|
(PCATALOGPOSITION)pSda->sda_ReplyBuf);
|
|
|
|
if (!NT_SUCCESS(Status) && ((Status != AFP_ERR_EOF) &&
|
|
(Status != AFP_ERR_CATALOG_CHANGED)))
|
|
{
|
|
break;
|
|
}
|
|
|
|
PUTSHORT2SHORT(&pRspPkt->__FileBitmap, FileResultBitmap);
|
|
PUTSHORT2SHORT(&pRspPkt->__DirBitmap, DirResultBitmap);
|
|
PUTDWORD2DWORD(&pRspPkt->__ActualCount, Count);
|
|
pSda->sda_ReplySize -= SizeLeft;
|
|
ASSERT(pSda->sda_ReplySize <= MAX_CATSEARCH_REPLY);
|
|
FreeReplyBuf = False;
|
|
|
|
|
|
|
|
} while (False);
|
|
|
|
if (FreeReplyBuf)
|
|
{
|
|
AfpIOFreeBackFillBuffer(pSda);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|