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