windows-nt/Source/XPSP1/NT/net/sfm/afp/server/fsp_fd.c
2020-09-26 16:20:57 +08:00

1242 lines
32 KiB
C

/*
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;
}