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

788 lines
19 KiB
C
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
Copyright (c) 1992 Microsoft Corporation
Module Name:
afpinfo.c
Abstract:
This module contains the routines for manipulating the afpinfo stream.
Author:
Jameel Hyder (microsoft!jameelh)
Revision History:
19 Jun 1992 Initial Version
Notes: Tab stop: 4
--*/
#define FILENUM FILE_AFPINFO
#include <afp.h>
#include <fdparm.h>
#include <pathmap.h>
#include <afpinfo.h>
#include <afpadmin.h>
#ifdef ALLOC_PRAGMA
#pragma alloc_text( PAGE, AfpSetAfpInfo)
#pragma alloc_text( PAGE, AfpReadAfpInfo)
#pragma alloc_text( PAGE, AfpSetFinderInfoByExtension)
#pragma alloc_text( PAGE, AfpProDosInfoFromFinderInfo)
#pragma alloc_text( PAGE, AfpFinderInfoFromProDosInfo)
#pragma alloc_text( PAGE, AfpSlapOnAfpInfoStream)
#pragma alloc_text( PAGE, AfpCreateAfpInfoStream)
#pragma alloc_text( PAGE, AfpExamineAndClearROAttr)
#pragma alloc_text( PAGE, AfpQueryProDos)
#endif
/*** AfpSetAfpInfo
*
* Sets the values specified by Bitmap in the AFP_AfpInfo stream of a file
* or directory. If FinderInfo is specified without ProDosInfo, or
* vice-versa, the one not specified is deduced from the other and also set.
* If the file/dir is marked ReadOnly, we must clear the readonly bit in order
* to write to the Afp_AfpInfo stream, and then set the RO bit back again.
* If pVolDesc is specified, then also update the cached AfpInfo in the
* IdDb DFENTRY.
*
*/
AFPSTATUS
AfpSetAfpInfo(
IN PFILESYSHANDLE pfshData, // handle to data stream of object
IN DWORD Bitmap,
IN PFILEDIRPARM pFDParms,
IN PVOLDESC pVolDesc OPTIONAL, // if present, update cached afpinfo
IN PDFENTRY * ppDFE OPTIONAL // pVolDesc must also be specified
)
{
NTSTATUS Status;
DWORD crinfo, NTAttr = 0;
AFPINFO afpinfo;
FILESYSHANDLE fshAfpInfo;
BOOLEAN isdir, WriteBackROAttr = False, mapprodos = False;
PDFENTRY pDfEntry = NULL;
PAGED_CODE( );
fshAfpInfo.fsh_FileHandle = NULL;
isdir = IsDir(pFDParms);
if (ARGUMENT_PRESENT(pVolDesc))
{
ASSERT(AfpSwmrLockedExclusive(&pVolDesc->vds_IdDbAccessLock));
pDfEntry = AfpFindDfEntryById(pVolDesc,
pFDParms->_fdp_AfpId,
isdir ? DFE_DIR : DFE_FILE);
if (pDfEntry == NULL)
{
return AFP_ERR_OBJECT_NOT_FOUND;
}
}
do
{
if (!NT_SUCCESS(Status = AfpCreateAfpInfo(pfshData, &fshAfpInfo, &crinfo)))
{
if (Status == STATUS_ACCESS_DENIED)
{
// We may have failed to open the AFP_Afpinfo stream because
// the file/dir is marked ReadOnly. Clear the ReadOnly bit
// and try to open it again.
Status = AfpExamineAndClearROAttr(pfshData,
&WriteBackROAttr,
NULL,
NULL);
if (NT_SUCCESS(Status))
{
if (!NT_SUCCESS(Status = AfpCreateAfpInfo(pfshData, &fshAfpInfo, &crinfo)))
{
AfpPutBackROAttr(pfshData, WriteBackROAttr);
Status = AfpIoConvertNTStatusToAfpStatus(Status);
break;
}
}
else
{
Status = AFP_ERR_MISC;
break;
}
}
else
{
Status = AfpIoConvertNTStatusToAfpStatus(Status);
break;
}
}
// If it was newly created or it existed but was corrupted, then initialize
// it with default data. Otherwise read in the current data
if ((crinfo == FILE_CREATED) ||
(!NT_SUCCESS(AfpReadAfpInfo(&fshAfpInfo, &afpinfo))))
{
UNICODE_STRING UName;
WCHAR NameBuf[AFP_LONGNAME_LEN+1];
if (crinfo != FILE_CREATED)
{
AFPLOG_HERROR(AFPSRVMSG_AFPINFO,
0,
NULL,
0,
pfshData->fsh_FileHandle);
}
if (!isdir)
{
AfpSetEmptyUnicodeString(&UName, sizeof(NameBuf), NameBuf);
AfpConvertStringToMungedUnicode(&pFDParms->_fdp_LongName, &UName);
}
// All callers of this routine must have the FD_BITMAP_LONGNAME
// bit forced in their bitmap to pathmap, so that in this case
// where the afpinfo stream must be recreated for a *file*, we
// will always have a valid _fdp_Longname set in FDParm and can
// deduce the type/creator
if (!NT_SUCCESS(AfpSlapOnAfpInfoStream(NULL,
NULL,
pfshData,
&fshAfpInfo,
pFDParms->_fdp_AfpId,
isdir,
isdir ? NULL : &UName,
&afpinfo)))
{
Status = AFP_ERR_MISC;
break;
}
else if (pDfEntry != NULL)
DFE_UPDATE_CACHED_AFPINFO(pDfEntry, &afpinfo);
}
if (Bitmap & FD_BITMAP_BACKUPTIME)
{
afpinfo.afpi_BackupTime = pFDParms->_fdp_BackupTime;
if (pDfEntry != NULL)
pDfEntry->dfe_BackupTime = afpinfo.afpi_BackupTime;
}
if (Bitmap & FD_BITMAP_FINDERINFO)
{ // Only map new ProDOS info if there has been a change in the
// type/creator, and FD_BITMAP_PRODOSINFO is not set (files only)
if (!(Bitmap & FD_BITMAP_PRODOSINFO) &&
!isdir &&
((RtlCompareMemory(afpinfo.afpi_FinderInfo.fd_Type,
pFDParms->_fdp_FinderInfo.fd_Type,
AFP_TYPE_LEN) != AFP_TYPE_LEN) ||
(RtlCompareMemory(afpinfo.afpi_FinderInfo.fd_Creator,
pFDParms->_fdp_FinderInfo.fd_Creator,
AFP_CREATOR_LEN) != AFP_CREATOR_LEN)))
{
mapprodos = True;
}
afpinfo.afpi_FinderInfo = pFDParms->_fdp_FinderInfo;
if (mapprodos)
{
AfpProDosInfoFromFinderInfo(&afpinfo.afpi_FinderInfo,
&afpinfo.afpi_ProDosInfo);
}
if (pDfEntry != NULL)
pDfEntry->dfe_FinderInfo = afpinfo.afpi_FinderInfo;
}
if (Bitmap & FD_BITMAP_PRODOSINFO)
{
if ((IsDir(pFDParms)) &&
(pFDParms->_fdp_ProDosInfo.pd_FileType[0] != PRODOS_TYPE_DIR))
{
Status = AFP_ERR_ACCESS_DENIED;
break;
}
afpinfo.afpi_ProDosInfo = pFDParms->_fdp_ProDosInfo;
if (!(Bitmap & FD_BITMAP_FINDERINFO) && !isdir)
{
AfpFinderInfoFromProDosInfo(&afpinfo.afpi_ProDosInfo,
&afpinfo.afpi_FinderInfo);
if (pDfEntry != NULL)
pDfEntry->dfe_FinderInfo = afpinfo.afpi_FinderInfo;
}
}
if (Bitmap & FD_BITMAP_ATTR)
{
afpinfo.afpi_Attributes =
pFDParms->_fdp_EffectiveAttr & ~FD_BITMAP_ATTR_SET;
if (pDfEntry != NULL)
pDfEntry->dfe_AfpAttr = afpinfo.afpi_Attributes;
}
if (Bitmap & DIR_BITMAP_ACCESSRIGHTS)
{
ASSERT(isdir == True);
afpinfo.afpi_AccessOwner = pFDParms->_fdp_OwnerRights;
afpinfo.afpi_AccessGroup = pFDParms->_fdp_GroupRights;
afpinfo.afpi_AccessWorld = pFDParms->_fdp_WorldRights;
if (pDfEntry != NULL)
{
DFE_OWNER_ACCESS(pDfEntry) = afpinfo.afpi_AccessOwner;
DFE_GROUP_ACCESS(pDfEntry) = afpinfo.afpi_AccessGroup;
DFE_WORLD_ACCESS(pDfEntry) = afpinfo.afpi_AccessWorld;
}
}
// FILE_BITMAP_FILENUM can ONLY be set by the internal CopyFile code
// and internal ExchangeFiles code
if (Bitmap & FILE_BITMAP_FILENUM)
{
ASSERT(isdir == False);
afpinfo.afpi_Id = pFDParms->_fdp_AfpId;
}
Status = AfpWriteAfpInfo(&fshAfpInfo, &afpinfo);
if (!NT_SUCCESS(Status))
Status = AfpIoConvertNTStatusToAfpStatus(Status);
} while (False);
AfpPutBackROAttr(pfshData, WriteBackROAttr);
if (fshAfpInfo.fsh_FileHandle != NULL)
AfpIoClose(&fshAfpInfo);
if (ARGUMENT_PRESENT(ppDFE))
{
ASSERT(ARGUMENT_PRESENT(pVolDesc));
*ppDFE = pDfEntry;
}
return Status;
}
/*** AfpReadAfpInfo
*
* When discovering a file/dir that has the AfpInfo stream, read it in
*
*/
NTSTATUS FASTCALL
AfpReadAfpInfo(
IN PFILESYSHANDLE pfshAfpInfo,
OUT PAFPINFO pAfpInfo
)
{
NTSTATUS Status;
LONG sizeRead;
PAGED_CODE( );
Status = AfpIoRead(pfshAfpInfo,
&LIZero,
sizeof(AFPINFO),
&sizeRead,
(PBYTE)pAfpInfo);
if (!NT_SUCCESS(Status) ||
(sizeRead != sizeof(AFPINFO)) ||
(pAfpInfo->afpi_Signature != AFP_SERVER_SIGNATURE) ||
(pAfpInfo->afpi_Version != AFP_SERVER_VERSION))
{
if (NT_SUCCESS(Status) &&
(sizeRead != 0) &&
((pAfpInfo->afpi_Signature != AFP_SERVER_SIGNATURE) ||
(pAfpInfo->afpi_Version != AFP_SERVER_VERSION)))
{
AFPLOG_HERROR(AFPSRVMSG_AFPINFO,
Status,
NULL,
0,
pfshAfpInfo->fsh_FileHandle);
}
if ((sizeRead != sizeof(AFPINFO)) && (sizeRead != 0))
{
DBGPRINT(DBG_COMP_AFPINFO, DBG_LEVEL_ERR,
("AfpReadAfpInfo: sizeRead (%d) != sizeof AFPINFO (%d)",
sizeRead, sizeof(AFPINFO)));
}
AfpIoSetSize(pfshAfpInfo, 0);
Status = STATUS_UNSUCCESSFUL;
}
return Status;
}
/*** AfpSetFinderInfoByExtension
*
* Set the finder info (type/creator) based on the file extension. Only long
* name is used for this mapping.
*
* LOCKS: AfpEtcMapLock (SWMR, Shared)
*/
VOID FASTCALL
AfpSetFinderInfoByExtension(
IN PUNICODE_STRING pFileName,
OUT PFINDERINFO pFinderInfo
)
{
PETCMAPINFO pEtcMap = NULL;
PWCHAR pch;
DWORD len, i = AFP_EXTENSION_LEN;
UCHAR ext[AFP_EXTENSION_LEN+1];
WCHAR wext[AFP_EXTENSION_LEN+1];
ANSI_STRING aext;
UNICODE_STRING uext;
PAGED_CODE( );
RtlZeroMemory(ext, sizeof(ext));
ASSERT(pFileName != NULL);
// Find the last character of the filename
pch = pFileName->Buffer + (pFileName->Length - sizeof(WCHAR))/sizeof(WCHAR);
len = pFileName->Length/sizeof(WCHAR);
AfpSwmrAcquireShared(&AfpEtcMapLock);
while ((AFP_EXTENSION_LEN - i) < len)
{
if (*pch == L'.')
{
if (i < AFP_EXTENSION_LEN)
{
AfpSetEmptyAnsiString(&aext, sizeof(ext), ext);
AfpInitUnicodeStringWithNonNullTerm(&uext,
(USHORT)((AFP_EXTENSION_LEN - i)*sizeof(WCHAR)),
&wext[i]);
AfpConvertMungedUnicodeToAnsi(&uext, &aext);
pEtcMap = AfpLookupEtcMapEntry(ext);
}
break;
}
if (i == 0)
break;
wext[--i] = *(pch--);
}
if (pEtcMap == NULL)
pEtcMap = &AfpDefaultEtcMap;
RtlCopyMemory(&pFinderInfo->fd_Type, &pEtcMap->etc_type, AFP_TYPE_LEN);
RtlCopyMemory(&pFinderInfo->fd_Creator, &pEtcMap->etc_creator, AFP_CREATOR_LEN);
AfpSwmrRelease(&AfpEtcMapLock);
}
/*** AfpProDosInfoFromFinderInfo
*
* Given finder info, deduce the corresponding prodos info. It is up to the
* caller to decide whether or not FinderInfo type/creator is actually
* changing (if client is just resetting the same values or not), in which
* case the prodos info should be left untouched. (Inside Appletalk p. 13-19)
* NOTE: see layout of ProDOS info on p. 13-18 of Inside Appletalk, 2nd Ed.)
*/
VOID FASTCALL
AfpProDosInfoFromFinderInfo(
IN PFINDERINFO pFinderInfo,
OUT PPRODOSINFO pProDosInfo
)
{
CHAR buf[3];
ULONG filetype;
NTSTATUS Status;
PAGED_CODE( );
RtlZeroMemory(pProDosInfo, sizeof(PRODOSINFO));
if (RtlCompareMemory(pFinderInfo->fd_Type, "TEXT", AFP_TYPE_LEN) == AFP_TYPE_LEN)
{
pProDosInfo->pd_FileType[0] = PRODOS_TYPE_FILE;
}
else if (RtlCompareMemory(pFinderInfo->fd_Creator,
"pdos",
AFP_CREATOR_LEN) == AFP_CREATOR_LEN)
{
if (RtlCompareMemory(pFinderInfo->fd_Type,
"PSYS",
AFP_TYPE_LEN) == AFP_TYPE_LEN)
{
pProDosInfo->pd_FileType[0] = PRODOS_FILETYPE_PSYS;
}
else if (RtlCompareMemory(pFinderInfo->fd_Type,
"PS16",
AFP_TYPE_LEN) == AFP_TYPE_LEN)
{
pProDosInfo->pd_FileType[0] = PRODOS_FILETYPE_PS16;
}
else if (pFinderInfo->fd_Type[0] == 'p')
{
pProDosInfo->pd_FileType[0] = pFinderInfo->fd_Type[1];
pProDosInfo->pd_AuxType[0] = pFinderInfo->fd_Type[3];
pProDosInfo->pd_AuxType[1] = pFinderInfo->fd_Type[2];
}
else if ((pFinderInfo->fd_Type[2] == ' ') &&
(pFinderInfo->fd_Type[3] == ' ') &&
(isxdigit(pFinderInfo->fd_Type[0])) &&
(isxdigit(pFinderInfo->fd_Type[1])))
{
buf[0] = pFinderInfo->fd_Type[0];
buf[1] = pFinderInfo->fd_Type[1];
buf[2] = 0;
Status = RtlCharToInteger(buf, 16, &filetype);
ASSERT(NT_SUCCESS(Status));
pProDosInfo->pd_FileType[0] = (BYTE)filetype;
}
}
}
/*** AfpFinderInfoFromProDosInfo
*
* Given the prodos info, deduce the corresponding finder info.
*/
VOID FASTCALL
AfpFinderInfoFromProDosInfo(
IN PPRODOSINFO pProDosInfo,
OUT PFINDERINFO pFinderInfo
)
{
PAGED_CODE( );
RtlCopyMemory(pFinderInfo->fd_Creator,"pdos",AFP_CREATOR_LEN);
if ((pProDosInfo->pd_FileType[0] == PRODOS_TYPE_FILE) &&
(pProDosInfo->pd_AuxType[0] == 0) &&
(pProDosInfo->pd_AuxType[1] == 0))
{
RtlCopyMemory(&pFinderInfo->fd_Type,"TEXT",AFP_TYPE_LEN);
}
else if (pProDosInfo->pd_FileType[0] == PRODOS_FILETYPE_PSYS)
{
RtlCopyMemory(&pFinderInfo->fd_Type,"PSYS",AFP_TYPE_LEN);
}
else if (pProDosInfo->pd_FileType[0] == PRODOS_FILETYPE_PS16)
{
RtlCopyMemory(&pFinderInfo->fd_Type,"PS16",AFP_TYPE_LEN);
}
else if (pProDosInfo->pd_FileType[0] == 0)
{
RtlCopyMemory(&pFinderInfo->fd_Type,"BINA",AFP_TYPE_LEN);
}
else
{
pFinderInfo->fd_Type[0] = 'p';
pFinderInfo->fd_Type[1] = pProDosInfo->pd_FileType[0];
pFinderInfo->fd_Type[2] = pProDosInfo->pd_AuxType[1];
pFinderInfo->fd_Type[3] = pProDosInfo->pd_AuxType[0];
}
}
/*** AfpSlapOnAfpInfoStream
*
* When creating a file or directory, this is called to add the AFP_AfpInfo
* stream. No client impersonation is done to open/read/write this stream.
* If pfshAfpInfoStream is supplied, that handle is used, else a handle is
* opened (and pfshData MUST be supplied);
*/
NTSTATUS
AfpSlapOnAfpInfoStream(
IN PVOLDESC pVolDesc OPTIONAL, // only if catching
IN PUNICODE_STRING pNotifyPath OPTIONAL, // changes to size of
// Afpinfo stream
IN PFILESYSHANDLE pfshData OPTIONAL,
IN PFILESYSHANDLE pfshAfpInfoStream OPTIONAL,
IN DWORD AfpId,
IN BOOLEAN IsDirectory,
IN PUNICODE_STRING pName OPTIONAL, // needed for files
OUT PAFPINFO pAfpInfo
)
{
NTSTATUS Status;
FILESYSHANDLE fshAfpInfo;
BOOLEAN WriteBackROAttr = False;
PAGED_CODE( );
ASSERT((pfshData != NULL) || (pfshAfpInfoStream != NULL));
if (!ARGUMENT_PRESENT(pfshAfpInfoStream))
{
if (!NT_SUCCESS(Status = AfpCreateAfpInfo(pfshData, &fshAfpInfo, NULL)))
{
if (Status == STATUS_ACCESS_DENIED)
{
// We may have failed to open the AFP_Afpinfo stream because
// the file/dir is marked ReadOnly. Clear the ReadOnly bit
// and try to open it again.
Status = AfpExamineAndClearROAttr(pfshData,
&WriteBackROAttr,
pVolDesc,
pNotifyPath);
if (NT_SUCCESS(Status))
{
if (!NT_SUCCESS(Status = AfpCreateAfpInfo(pfshData,
&fshAfpInfo,
NULL)))
{
AfpPutBackROAttr(pfshData, WriteBackROAttr);
}
}
}
if (!NT_SUCCESS(Status))
return Status;
}
}
else fshAfpInfo = *pfshAfpInfoStream;
AfpInitAfpInfo(pAfpInfo, AfpId, IsDirectory, BEGINNING_OF_TIME);
if (!IsDirectory)
{
ASSERT(pName != NULL);
AfpSetFinderInfoByExtension(pName,
&pAfpInfo->afpi_FinderInfo);
AfpProDosInfoFromFinderInfo(&pAfpInfo->afpi_FinderInfo,
&pAfpInfo->afpi_ProDosInfo);
}
AfpIoSetSize(&fshAfpInfo, 0);
Status = AfpWriteAfpInfo(&fshAfpInfo, pAfpInfo);
if (NT_SUCCESS(Status) &&
ARGUMENT_PRESENT(pVolDesc) &&
ARGUMENT_PRESENT(pNotifyPath))
{
// Do both FILE_ACTION_MODIFIED_STREAM and FILE_ACTION_MODIFIED in one go
AfpQueueOurChange(pVolDesc,
FILE_ACTION_MODIFIED_STREAM,
pNotifyPath,
pNotifyPath);
}
if (!ARGUMENT_PRESENT(pfshAfpInfoStream))
{
AfpIoClose(&fshAfpInfo);
AfpPutBackROAttr(pfshData, WriteBackROAttr);
}
return Status;
}
/*** AfpCreateAfpInfoStream
*
* Similar to AfpSlapOnAfpInfoStream but tuned to Create file/directory case.
*/
NTSTATUS
AfpCreateAfpInfoStream(
IN PVOLDESC pVolDesc,
IN PFILESYSHANDLE pfshData,
IN DWORD AfpId,
IN BOOLEAN IsDirectory,
IN PUNICODE_STRING pName OPTIONAL, // only needed for files
IN PUNICODE_STRING pNotifyPath,
OUT PAFPINFO pAfpInfo,
OUT PFILESYSHANDLE pfshAfpInfo
)
{
NTSTATUS Status;
BOOLEAN WriteBackROAttr = False;
DWORD crinfo;
PAGED_CODE( );
ASSERT((pfshData != NULL) && (pfshAfpInfo != NULL));
do
{
if (!NT_SUCCESS(Status = AfpCreateAfpInfo(pfshData, pfshAfpInfo, &crinfo)))
{
if (Status == STATUS_ACCESS_DENIED)
{
// We may have failed to open the AFP_Afpinfo stream because
// the file/dir is marked ReadOnly. Clear the ReadOnly bit
// and try to open it again.
Status = AfpExamineAndClearROAttr(pfshData,
&WriteBackROAttr,
pVolDesc,
pNotifyPath);
if (NT_SUCCESS(Status))
{
if (!NT_SUCCESS(Status = AfpCreateAfpInfo(pfshData,
pfshAfpInfo,
&crinfo)))
{
AfpPutBackROAttr(pfshData, WriteBackROAttr);
}
}
}
if (!NT_SUCCESS(Status))
break;
}
AfpInitAfpInfo(pAfpInfo, AfpId, IsDirectory, BEGINNING_OF_TIME);
if (!IsDirectory)
{
ASSERT(pName != NULL);
AfpSetFinderInfoByExtension(pName,
&pAfpInfo->afpi_FinderInfo);
AfpProDosInfoFromFinderInfo(&pAfpInfo->afpi_FinderInfo,
&pAfpInfo->afpi_ProDosInfo);
}
Status = AfpWriteAfpInfo(pfshAfpInfo, pAfpInfo);
if (NT_SUCCESS(Status) && (crinfo == FILE_CREATED))
{
// Do both FILE_ACTION_MODIFIED_STREAM and FILE_ACTION_MODIFIED in one go
AfpQueueOurChange(pVolDesc,
FILE_ACTION_MODIFIED_STREAM,
pNotifyPath,
pNotifyPath);
}
AfpPutBackROAttr(pfshData, WriteBackROAttr);
} while (False);
return Status;
}
/*** AfpExamineAndClearROAttr
*
* If the ReadOnly attribute is set on a file or directory, clear it.
* pWriteBackROAttr is a boolean indicating whether or not the caller must
* subsequently reset the Readonly bit on the file/dir. (see AfpPutBackROAttr)
*/
NTSTATUS FASTCALL
AfpExamineAndClearROAttr(
IN PFILESYSHANDLE pfshData,
OUT PBOOLEAN pWriteBackROAttr,
IN PVOLDESC pVolDesc OPTIONAL,
IN PUNICODE_STRING pPath OPTIONAL
)
{
NTSTATUS Status;
DWORD NTAttr = 0;
PAGED_CODE( );
ASSERT(VALID_FSH(pfshData));
*pWriteBackROAttr = False;
if (NT_SUCCESS(Status = AfpIoQueryTimesnAttr(pfshData, NULL, NULL, &NTAttr)) &&
(NTAttr & FILE_ATTRIBUTE_READONLY))
{
// We need to clear the readonly bit.
if (NT_SUCCESS(Status = AfpIoSetTimesnAttr(pfshData,
NULL,
NULL,
0,
FILE_ATTRIBUTE_READONLY,
pVolDesc,
pPath)))
{
*pWriteBackROAttr = True;
}
}
return Status;
}
/*** AfpQueryProDos
*
* Open the afpinfo stream relative to the file's Data handle, and
* read the ProDOS info out of it. If the AfpInfo stream does not
* exist, return an error.
*
*/
AFPSTATUS FASTCALL
AfpQueryProDos(
IN PFILESYSHANDLE pfshData,
OUT PPRODOSINFO pProDosInfo
)
{
AFPSTATUS Status = AFP_ERR_NONE;
FILESYSHANDLE hAfpInfo;
AFPINFO afpinfo;
Status = AfpIoOpen(pfshData,
AFP_STREAM_INFO,
FILEIO_OPEN_FILE,
&UNullString,
FILEIO_ACCESS_READ,
FILEIO_DENY_NONE,
False,
&hAfpInfo);
if (NT_SUCCESS(Status))
{
if (NT_SUCCESS(AfpReadAfpInfo(&hAfpInfo, &afpinfo)))
{
*pProDosInfo = afpinfo.afpi_ProDosInfo;
}
else
{
Status = AFP_ERR_MISC;
}
AfpIoClose(&hAfpInfo);
}
else
Status = AfpIoConvertNTStatusToAfpStatus(Status);
return Status;
}
/*** AfpUpdateIdInAfpInfo
*
* Update the afpid in the afpinfo stream.
*
*/
AFPSTATUS FASTCALL
AfpUpdateIdInAfpInfo(
IN PVOLDESC pVolDesc,
IN PDFENTRY pDfEntry
)
{
FILESYSHANDLE fshAfpInfo;
AFPINFO AfpInfo;
AFPSTATUS Status;
UNICODE_STRING Path;
AfpSetEmptyUnicodeString(&Path, 0, NULL);
Status = AfpHostPathFromDFEntry(pDfEntry, 0, &Path);
if (NT_SUCCESS(Status))
{
// Open the afpinfo stream
Status = AfpIoOpen(&pVolDesc->vds_hRootDir,
AFP_STREAM_INFO,
FILEIO_OPEN_FILE,
&Path,
FILEIO_ACCESS_READWRITE,
FILEIO_DENY_NONE,
False,
&fshAfpInfo);
if (NT_SUCCESS(Status))
{
Status = AfpReadAfpInfo(&fshAfpInfo, &AfpInfo);
if (NT_SUCCESS(Status))
{
AfpInfo.afpi_Id = pDfEntry->dfe_AfpId;
AfpWriteAfpInfo(&fshAfpInfo, &AfpInfo);
}
AfpIoClose(&fshAfpInfo);
}
AfpFreeMemory(Path.Buffer);
}
return Status;
}