Windows: Direct IO for AFS Redirector
[openafs.git] / src / WINNT / afsrdr / user / RDRFunction.c
1 /*
2  * Copyright (c) 2008 Secure Endpoints, Inc.
3  * Copyright (c) 2009-2011 Your File System, Inc.
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are met:
8  *
9  * - Redistributions of source code must retain the above copyright notice,
10  *   this list of conditions and the following disclaimer.
11  * - Redistributions in binary form must reproduce the above copyright notice,
12  *   this list of conditions and the following disclaimer in the documentation
13  *   and/or other materials provided with the distribution.
14  * - Neither the name of Secure Endpoints Inc. nor the names of its contributors
15  *   may be used to endorse or promote products derived from this software without
16  *   specific prior written permission from Secure Endpoints, Inc. and
17  *   Your File System, Inc.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
22  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
23  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
26  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
27  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
28  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
29  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31
32 #include <afsconfig.h>
33 #include <afs/param.h>
34
35 #ifndef _WIN32_WINNT
36 #define _WIN32_WINNT 0x0500
37 #endif
38 #define _CRT_SECURE_NO_DEPRECATE
39 #define _CRT_NON_CONFORMING_SWPRINTFS
40 #define INITGUID        /* define AFS_AUTH_GUID_NO_PAG */
41
42 #include <ntstatus.h>
43 #define WIN32_NO_STATUS
44 #include <windows.h>
45
46 #include <roken.h>
47
48 #include <afs/stds.h>
49
50 #include <ntsecapi.h>
51 #include <sddl.h>
52 #pragma warning(push)
53 #pragma warning(disable: 4005)
54
55 #include <devioctl.h>
56
57 #include "..\\Common\\AFSUserDefines.h"
58 #include "..\\Common\\AFSUserStructs.h"
59
60 #pragma warning(pop)
61
62 #include <tchar.h>
63 #include <wchar.h>
64 #include <winbase.h>
65 #include <winreg.h>
66
67 #include <stdio.h>
68 #include <stdlib.h>
69 #include <stdarg.h>
70 #include <strsafe.h>
71
72 #include "afsd.h"
73 #include "smb.h"
74 #include "cm_btree.h"
75 #include "msrpc.h"
76 #include <RDRPrototypes.h>
77 #include <RDRIoctl.h>
78 #include <RDRPipe.h>
79
80 static CHAR * RDR_extentBaseAddress = NULL;
81
82 void
83 RDR_InitReq(cm_req_t *reqp, BOOL bWow64)
84 {
85     cm_InitReq(reqp);
86     reqp->flags |= CM_REQ_SOURCE_REDIR;
87     if (bWow64)
88         reqp->flags |= CM_REQ_WOW64;
89 }
90
91 void
92 RDR_fid2FID( cm_fid_t *fid, AFSFileID *FileId)
93 {
94     FileId->Cell = fid->cell;
95     FileId->Volume = fid->volume;
96     FileId->Vnode = fid->vnode;
97     FileId->Unique = fid->unique;
98     FileId->Hash = fid->hash;
99 }
100
101 void
102 RDR_FID2fid( AFSFileID *FileId, cm_fid_t *fid)
103 {
104     fid->cell = FileId->Cell;
105     fid->volume = FileId->Volume;
106     fid->vnode = FileId->Vnode;
107     fid->unique = FileId->Unique;
108     fid->hash = FileId->Hash;
109 }
110
111 DWORD
112 RDR_SetInitParams( OUT AFSRedirectorInitInfo **ppRedirInitInfo, OUT DWORD * pRedirInitInfoLen )
113 {
114     extern char cm_CachePath[];
115     extern cm_config_data_t cm_data;
116     extern int smb_hideDotFiles;
117     size_t CachePathLen;
118     DWORD TempPathLen;
119     size_t err;
120     MEMORYSTATUSEX memStatus;
121     DWORD maxMemoryCacheSize;
122     char FullCachePath[MAX_PATH];
123     char TempPath[MAX_PATH];
124     char FullTempPath[MAX_PATH];
125
126     /*
127      * The %TEMP% environment variable may be relative instead
128      * of absolute which can result in the redirector referring
129      * to a different directory than the service.  The full path
130      * must therefore be obtained first.
131      */
132
133     CachePathLen = GetFullPathNameA(cm_CachePath, MAX_PATH, FullCachePath, NULL);
134     if (CachePathLen == 0) {
135         osi_Log0(afsd_logp, "RDR_SetInitParams Unable to obtain Full Cache Path");
136         return STATUS_OBJECT_NAME_NOT_FOUND;
137     }
138
139     TempPathLen = ExpandEnvironmentStringsA("%TEMP%", TempPath, MAX_PATH);
140     if (TempPathLen == 0) {
141         osi_Log0(afsd_logp, "RDR_SetInitParams Unable to expand %%TEMP%%");
142         return STATUS_OBJECT_NAME_NOT_FOUND;
143     }
144
145     TempPathLen = GetFullPathNameA(TempPath, MAX_PATH, FullTempPath, NULL);
146     if (TempPathLen == 0) {
147         osi_Log0(afsd_logp, "RDR_SetInitParams Unable to obtain Full Temp Path");
148         return STATUS_OBJECT_NAME_NOT_FOUND;
149     }
150
151     memStatus.dwLength = sizeof(memStatus);
152     if (GlobalMemoryStatusEx(&memStatus)) {
153         /*
154          * Use the memory extent interface in the afs redirector
155          * whenever the cache size is less than equal to 10% of
156          * physical memory.  Do not use too much because this memory
157          * will be locked by the redirector so it can't be swapped
158          * out.
159          */
160         maxMemoryCacheSize = (DWORD)(memStatus.ullTotalPhys / 1024 / 10);
161     } else {
162         /*
163          * If we can't determine the amount of physical memory
164          * in the system, be conservative and limit the use of
165          * memory extent interface to 64MB data caches.
166          */
167         maxMemoryCacheSize = 65536;
168     }
169
170     *pRedirInitInfoLen = (DWORD) (sizeof(AFSRedirectorInitInfo) + (CachePathLen + TempPathLen) * sizeof(WCHAR));
171     *ppRedirInitInfo = (AFSRedirectorInitInfo *)malloc(*pRedirInitInfoLen);
172     (*ppRedirInitInfo)->Flags = smb_hideDotFiles ? AFS_REDIR_INIT_FLAG_HIDE_DOT_FILES : 0;
173     (*ppRedirInitInfo)->Flags |= cm_shortNames ? 0 : AFS_REDIR_INIT_FLAG_DISABLE_SHORTNAMES;
174     (*ppRedirInitInfo)->MaximumChunkLength = cm_data.chunkSize;
175     (*ppRedirInitInfo)->GlobalFileId.Cell   = cm_data.rootFid.cell;
176     (*ppRedirInitInfo)->GlobalFileId.Volume = cm_data.rootFid.volume;
177     (*ppRedirInitInfo)->GlobalFileId.Vnode  = cm_data.rootFid.vnode;
178     (*ppRedirInitInfo)->GlobalFileId.Unique = cm_data.rootFid.unique;
179     (*ppRedirInitInfo)->GlobalFileId.Hash   = cm_data.rootFid.hash;
180     (*ppRedirInitInfo)->ExtentCount.QuadPart = cm_data.buf_nbuffers;
181     (*ppRedirInitInfo)->CacheBlockSize = cm_data.blockSize;
182     (*ppRedirInitInfo)->MaxPathLinkCount = MAX_FID_COUNT;
183     (*ppRedirInitInfo)->NameArrayLength = MAX_FID_COUNT;
184     if (cm_virtualCache || cm_data.bufferSize <= maxMemoryCacheSize) {
185         osi_Log0(afsd_logp, "RDR_SetInitParams Initializing Memory Extent Interface");
186         (*ppRedirInitInfo)->MemoryCacheOffset.QuadPart = (LONGLONG)cm_data.bufDataBaseAddress;
187         (*ppRedirInitInfo)->MemoryCacheLength.QuadPart = cm_data.bufEndOfData - cm_data.bufDataBaseAddress;
188         (*ppRedirInitInfo)->CacheFileNameLength = 0;
189         RDR_extentBaseAddress = cm_data.bufDataBaseAddress;
190     } else {
191         (*ppRedirInitInfo)->MemoryCacheOffset.QuadPart = 0;
192         (*ppRedirInitInfo)->MemoryCacheLength.QuadPart = 0;
193         (*ppRedirInitInfo)->CacheFileNameLength = (ULONG) (CachePathLen * sizeof(WCHAR));
194         err = mbstowcs((*ppRedirInitInfo)->CacheFileName, FullCachePath, (CachePathLen + 1) *sizeof(WCHAR));
195         if (err == -1) {
196             free(*ppRedirInitInfo);
197             osi_Log0(afsd_logp, "RDR_SetInitParams Invalid Object Name");
198             return STATUS_OBJECT_NAME_INVALID;
199         }
200         RDR_extentBaseAddress = cm_data.baseAddress;
201     }
202     (*ppRedirInitInfo)->DumpFileLocationOffset = FIELD_OFFSET(AFSRedirectorInitInfo, CacheFileName) + (*ppRedirInitInfo)->CacheFileNameLength;
203     (*ppRedirInitInfo)->DumpFileLocationLength = (TempPathLen - 1) * sizeof(WCHAR);
204
205     err = mbstowcs((((PBYTE)(*ppRedirInitInfo)) + (*ppRedirInitInfo)->DumpFileLocationOffset),
206                    FullTempPath, (TempPathLen + 1) *sizeof(WCHAR));
207     if (err == -1) {
208         free(*ppRedirInitInfo);
209         osi_Log0(afsd_logp, "RDR_SetInitParams Invalid Object Name");
210         return STATUS_OBJECT_NAME_INVALID;
211     }
212
213     osi_Log0(afsd_logp,"RDR_SetInitParams Success");
214     return 0;
215 }
216
217 static wchar_t cname[MAX_COMPUTERNAME_LENGTH+1] = L"";
218
219 cm_user_t *
220 RDR_GetLocalSystemUser( void)
221 {
222     smb_username_t *unp;
223     cm_user_t *userp = NULL;
224
225     if ( cname[0] == '\0') {
226         int len = MAX_COMPUTERNAME_LENGTH+1;
227         GetComputerNameW(cname, &len);
228         _wcsupr(cname);
229     }
230     unp = smb_FindUserByName(NTSID_LOCAL_SYSTEM, cname, SMB_FLAG_CREATE);
231     lock_ObtainMutex(&unp->mx);
232     if (!unp->userp)
233         unp->userp = cm_NewUser();
234     unp->flags |= SMB_USERNAMEFLAG_SID;
235     lock_ReleaseMutex(&unp->mx);
236     userp = unp->userp;
237     cm_HoldUser(userp);
238     smb_ReleaseUsername(unp);
239
240     if (!userp) {
241         userp = cm_rootUserp;
242         cm_HoldUser(userp);
243     }
244
245     return userp;
246 }
247
248 cm_user_t *
249 RDR_UserFromCommRequest( IN AFSCommRequest *RequestBuffer)
250 {
251
252     return RDR_UserFromAuthGroup( &RequestBuffer->AuthGroup);
253 }
254
255 cm_user_t *
256 RDR_UserFromAuthGroup( IN GUID *pGuid)
257 {
258     smb_username_t *unp;
259     cm_user_t * userp = NULL;
260     RPC_WSTR UuidString = NULL;
261
262     if (UuidToStringW((UUID *)pGuid, &UuidString) != RPC_S_OK)
263         goto done;
264
265     if ( cname[0] == '\0') {
266         int len = MAX_COMPUTERNAME_LENGTH+1;
267         GetComputerNameW(cname, &len);
268         _wcsupr(cname);
269     }
270
271     unp = smb_FindUserByName(UuidString, cname, SMB_FLAG_CREATE);
272     lock_ObtainMutex(&unp->mx);
273     if (!unp->userp) {
274         unp->userp = cm_NewUser();
275         memcpy(&unp->userp->authgroup, pGuid, sizeof(GUID));
276     }
277     unp->flags |= SMB_USERNAMEFLAG_SID;
278     lock_ReleaseMutex(&unp->mx);
279     userp = unp->userp;
280     cm_HoldUser(userp);
281     smb_ReleaseUsername(unp);
282
283   done:
284     if (!userp) {
285         userp = cm_rootUserp;
286         cm_HoldUser(userp);
287     }
288
289     osi_Log2(afsd_logp, "RDR_UserFromCommRequest Guid %S userp = 0x%p",
290              osi_LogSaveStringW(afsd_logp, UuidString),
291              userp);
292
293     if (UuidString)
294         RpcStringFreeW(&UuidString);
295
296     return userp;
297 }
298
299 void
300 RDR_ReleaseUser( IN cm_user_t *userp )
301 {
302     osi_Log1(afsd_logp, "RDR_ReleaseUser userp = 0x%p", userp);
303     cm_ReleaseUser(userp);
304 }
305
306
307 /*
308  * RDR_FlagScpInUse flags the scp with CM_SCACHEFLAG_RDR_IN_USE
309  */
310 static void
311 RDR_FlagScpInUse( IN cm_scache_t *scp, IN BOOL bLocked )
312 {
313     if (!bLocked)
314         lock_ObtainWrite(&scp->rw);
315
316     lock_AssertWrite(&scp->rw);
317     scp->flags |= CM_SCACHEFLAG_RDR_IN_USE;
318
319     if (!bLocked)
320         lock_ReleaseWrite(&scp->rw);
321 }
322
323 /*
324  * Obtain the status information for the specified object using
325  * an inline bulk status rpc.  cm_BPlusDirEnumBulkStatOne() will
326  * obtain current status for the directory object, the object
327  * which is the focus of the inquiry and as many other objects
328  * in the directory for which there are not callbacks registered
329  * since we are likely to be asked for other objects in the directory.
330  */
331 static afs_uint32
332 RDR_BulkStatLookup( cm_scache_t *dscp,
333                     cm_scache_t *scp,
334                     cm_user_t   *userp,
335                     cm_req_t    *reqp)
336 {
337     cm_direnum_t *      enump = NULL;
338     afs_uint32  code = 0;
339     cm_dirOp_t    dirop;
340
341     code = cm_BeginDirOp(dscp, userp, reqp, CM_DIRLOCK_READ, CM_DIROP_FLAG_NONE, &dirop);
342     if (code == 0) {
343         code = cm_BPlusDirEnumerate(dscp, userp, reqp, TRUE, NULL, TRUE, &enump);
344         if (code) {
345             osi_Log1(afsd_logp, "RDR_BulkStatLookup cm_BPlusDirEnumerate failure code=0x%x",
346                       code);
347         }
348         cm_EndDirOp(&dirop);
349     } else {
350         osi_Log1(afsd_logp, "RDR_BulkStatLookup cm_BeginDirOp failure code=0x%x",
351                   code);
352     }
353
354     if (enump)
355     {
356         code = cm_BPlusDirEnumBulkStatOne(enump, scp);
357         if (code) {
358             osi_Log1(afsd_logp, "RDR_BulkStatLookup cm_BPlusDirEnumBulkStatOne failure code=0x%x",
359                       code);
360         }
361         cm_BPlusDirFreeEnumeration(enump);
362     }
363
364     return code;
365 }
366
367
368 #define RDR_POP_FOLLOW_MOUNTPOINTS 0x01
369 #define RDR_POP_EVALUATE_SYMLINKS  0x02
370 #define RDR_POP_WOW64              0x04
371 #define RDR_POP_NO_GETSTATUS       0x08
372
373 static afs_uint32
374 RDR_PopulateCurrentEntry( IN  AFSDirEnumEntry * pCurrentEntry,
375                           IN  DWORD             dwMaxEntryLength,
376                           IN  cm_scache_t     * dscp,
377                           IN  cm_scache_t     * scp,
378                           IN  cm_user_t       * userp,
379                           IN  cm_req_t        * reqp,
380                           IN  wchar_t         * name,
381                           IN  wchar_t         * shortName,
382                           IN  DWORD             dwFlags,
383                           IN  afs_uint32        cmError,
384                           OUT AFSDirEnumEntry **ppNextEntry,
385                           OUT DWORD           * pdwRemainingLength)
386 {
387     FILETIME ft;
388     WCHAR *  wname, *wtarget;
389     size_t   len;
390     DWORD      dwEntryLength;
391     afs_uint32 code = 0, code2 = 0;
392     BOOL          bMustFake = FALSE;
393
394     osi_Log5(afsd_logp, "RDR_PopulateCurrentEntry dscp=0x%p scp=0x%p name=%S short=%S flags=0x%x",
395              dscp, scp, osi_LogSaveStringW(afsd_logp, name),
396              osi_LogSaveStringW(afsd_logp, shortName), dwFlags);
397     osi_Log1(afsd_logp, "... maxLength=%d", dwMaxEntryLength);
398
399     if (dwMaxEntryLength < sizeof(AFSDirEnumEntry) + (MAX_PATH + MOUNTPOINTLEN) * sizeof(wchar_t)) {
400         if (ppNextEntry)
401             *ppNextEntry = pCurrentEntry;
402         if (pdwRemainingLength)
403             *pdwRemainingLength = dwMaxEntryLength;
404         osi_Log2(afsd_logp, "RDR_PopulateCurrentEntry Not Enough Room for Entry %d < %d",
405                  dwMaxEntryLength, sizeof(AFSDirEnumEntry) + (MAX_PATH + MOUNTPOINTLEN) * sizeof(wchar_t));
406         return CM_ERROR_TOOBIG;
407     }
408
409     if (!name)
410         name = L"";
411     if (!shortName)
412         shortName = L"";
413
414     dwEntryLength = sizeof(AFSDirEnumEntry);
415
416     lock_ObtainWrite(&scp->rw);
417     if (dwFlags & RDR_POP_NO_GETSTATUS) {
418         if (!cm_HaveCallback(scp))
419             bMustFake = TRUE;
420     } else {
421 #ifdef AFS_FREELANCE_CLIENT
422         if (scp->fid.cell == AFS_FAKE_ROOT_CELL_ID && scp->fid.volume == AFS_FAKE_ROOT_VOL_ID) {
423             /*
424              * If the FID is from the Freelance Local Root always perform
425              * a single item status check.
426              */
427             code = cm_SyncOp( scp, NULL, userp, reqp, 0,
428                               CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
429             if (code) {
430                 lock_ReleaseWrite(&scp->rw);
431                 osi_Log2(afsd_logp, "RDR_PopulateCurrentEntry cm_SyncOp failed for scp=0x%p code=0x%x",
432                          scp, code);
433                 return code;
434             }
435         } else
436 #endif
437         {
438             /*
439              * For non-Freelance objects, check to see if we have current
440              * status information.  If not, perform a bulk status lookup of multiple
441              * entries in order to reduce the number of RPCs issued to the file server.
442              */
443             if (cm_EAccesFindEntry(userp, &scp->fid))
444                 bMustFake = TRUE;
445             else if (!cm_HaveCallback(scp)) {
446                 lock_ReleaseWrite(&scp->rw);
447                 code = RDR_BulkStatLookup(dscp, scp, userp, reqp);
448                 if (code) {
449                     osi_Log2(afsd_logp, "RDR_PopulateCurrentEntry RDR_BulkStatLookup failed for scp=0x%p code=0x%x",
450                              scp, code);
451                     return code;
452                 }
453                 lock_ObtainWrite(&scp->rw);
454                 /*
455                  * RDR_BulkStatLookup can succeed but it may be the case that there
456                  * still is not valid status info.  If we get this far, generate fake
457                  * status info.
458                  */
459                 if (!cm_HaveCallback(scp))
460                     bMustFake = TRUE;
461             }
462         }
463     }
464
465     /* Populate the error code */
466     smb_MapNTError(cmError, &pCurrentEntry->NTStatus, TRUE);
467
468     /* Populate the real or fake data */
469     pCurrentEntry->FileId.Cell = scp->fid.cell;
470     pCurrentEntry->FileId.Volume = scp->fid.volume;
471     pCurrentEntry->FileId.Vnode = scp->fid.vnode;
472     pCurrentEntry->FileId.Unique = scp->fid.unique;
473     pCurrentEntry->FileId.Hash = scp->fid.hash;
474
475     pCurrentEntry->FileType = scp->fileType;
476
477     pCurrentEntry->DataVersion.QuadPart = scp->dataVersion;
478
479     if (scp->fid.cell==AFS_FAKE_ROOT_CELL_ID &&
480         scp->fid.volume==AFS_FAKE_ROOT_VOL_ID) {
481         cm_LargeSearchTimeFromUnixTime(&ft, MAX_AFS_UINT32);
482     } else {
483         cm_LargeSearchTimeFromUnixTime(&ft, scp->cbExpires);
484     }
485     pCurrentEntry->Expiration.LowPart = ft.dwLowDateTime;
486     pCurrentEntry->Expiration.HighPart = ft.dwHighDateTime;
487
488     if (bMustFake) {
489         /* 1969-12-31 23:59:59 +00 */
490         ft.dwHighDateTime = 0x19DB200;
491         ft.dwLowDateTime = 0x5BB78980;
492     } else
493         cm_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
494     pCurrentEntry->CreationTime.LowPart = ft.dwLowDateTime;
495     pCurrentEntry->CreationTime.HighPart = ft.dwHighDateTime;
496     pCurrentEntry->LastAccessTime = pCurrentEntry->CreationTime;
497     pCurrentEntry->LastWriteTime = pCurrentEntry->CreationTime;
498     pCurrentEntry->ChangeTime = pCurrentEntry->CreationTime;
499
500     pCurrentEntry->EndOfFile = scp->length;
501     pCurrentEntry->AllocationSize = scp->length;
502
503     if (bMustFake) {
504         switch (scp->fileType) {
505         case CM_SCACHETYPE_DIRECTORY:
506             pCurrentEntry->FileAttributes = SMB_ATTR_DIRECTORY;
507             break;
508         case CM_SCACHETYPE_MOUNTPOINT:
509         case CM_SCACHETYPE_INVALID:
510             pCurrentEntry->FileAttributes = SMB_ATTR_DIRECTORY | SMB_ATTR_REPARSE_POINT;
511             break;
512         case CM_SCACHETYPE_SYMLINK:
513             if (cm_TargetPerceivedAsDirectory(scp->mountPointStringp))
514                 pCurrentEntry->FileAttributes = SMB_ATTR_DIRECTORY | SMB_ATTR_REPARSE_POINT;
515             else
516                 pCurrentEntry->FileAttributes = SMB_ATTR_REPARSE_POINT;
517             break;
518         default:
519             /* if we get here we either have a normal file
520             * or we have a file for which we have never
521             * received status info.  In this case, we can
522             * check the even/odd value of the entry's vnode.
523             * odd means it is to be treated as a directory
524             * and even means it is to be treated as a file.
525             */
526             if (scp->fid.vnode & 0x1)
527                 pCurrentEntry->FileAttributes = SMB_ATTR_DIRECTORY;
528             else
529                 pCurrentEntry->FileAttributes = SMB_ATTR_NORMAL;
530         }
531     } else
532         pCurrentEntry->FileAttributes = smb_ExtAttributes(scp);
533     pCurrentEntry->EaSize = 0;
534     pCurrentEntry->Links = scp->linkCount;
535
536     len = wcslen(shortName);
537     wcsncpy(pCurrentEntry->ShortName, shortName, len);
538     pCurrentEntry->ShortNameLength = (CCHAR)(len * sizeof(WCHAR));
539
540     pCurrentEntry->FileNameOffset = sizeof(AFSDirEnumEntry);
541     len = wcslen(name);
542     wname = (WCHAR *)((PBYTE)pCurrentEntry + pCurrentEntry->FileNameOffset);
543     wcsncpy(wname, name, len);
544     pCurrentEntry->FileNameLength = (ULONG)(sizeof(WCHAR) * len);
545
546     osi_Log3(afsd_logp, "RDR_PopulateCurrentEntry scp=0x%p fileType=%d dv=%u",
547               scp, scp->fileType, (afs_uint32)scp->dataVersion);
548
549     if (!(dwFlags & RDR_POP_NO_GETSTATUS))
550         cm_SyncOpDone( scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
551
552     if ((dwFlags & RDR_POP_NO_GETSTATUS) || !cm_HaveCallback(scp)) {
553         pCurrentEntry->TargetNameOffset = 0;
554         pCurrentEntry->TargetNameLength = 0;
555     }
556     else
557     switch (scp->fileType) {
558     case CM_SCACHETYPE_MOUNTPOINT:
559         if (dwFlags & RDR_POP_FOLLOW_MOUNTPOINTS) {
560             if ((code2 = cm_ReadMountPoint(scp, userp, reqp)) == 0) {
561                 cm_scache_t *targetScp = NULL;
562
563                 pCurrentEntry->TargetNameOffset = pCurrentEntry->FileNameOffset + pCurrentEntry->FileNameLength;
564                 len = strlen(scp->mountPointStringp);
565                 wtarget = (WCHAR *)((PBYTE)pCurrentEntry + pCurrentEntry->TargetNameOffset);
566
567 #ifdef UNICODE
568                 cch = MultiByteToWideChar( CP_UTF8, 0, scp->mountPointStringp,
569                                            len * sizeof(char),
570                                            wtarget,
571                                            len * sizeof(WCHAR));
572 #else
573                 mbstowcs(wtarget, scp->mountPointStringp, len);
574 #endif
575                 pCurrentEntry->TargetNameLength = (ULONG)(sizeof(WCHAR) * len);
576
577                 code2 = cm_FollowMountPoint(scp, dscp, userp, reqp, &targetScp);
578
579                 if (code2 == 0) {
580                     pCurrentEntry->TargetFileId.Cell = targetScp->fid.cell;
581                     pCurrentEntry->TargetFileId.Volume = targetScp->fid.volume;
582                     pCurrentEntry->TargetFileId.Vnode = targetScp->fid.vnode;
583                     pCurrentEntry->TargetFileId.Unique = targetScp->fid.unique;
584                     pCurrentEntry->TargetFileId.Hash = targetScp->fid.hash;
585
586                     osi_Log4(afsd_logp, "RDR_PopulateCurrentEntry target FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
587                               pCurrentEntry->TargetFileId.Cell, pCurrentEntry->TargetFileId.Volume,
588                               pCurrentEntry->TargetFileId.Vnode, pCurrentEntry->TargetFileId.Unique);
589
590                     cm_ReleaseSCache(targetScp);
591                 } else {
592                     osi_Log2(afsd_logp, "RDR_PopulateCurrentEntry cm_FollowMountPoint failed scp=0x%p code=0x%x",
593                               scp, code2);
594                 }
595             } else {
596                 osi_Log2(afsd_logp, "RDR_PopulateCurrentEntry cm_ReadMountPoint failed scp=0x%p code=0x%x",
597                           scp, code2);
598             }
599         }
600         break;
601     case CM_SCACHETYPE_SYMLINK:
602     case CM_SCACHETYPE_DFSLINK:
603         {
604             pCurrentEntry->TargetNameOffset = pCurrentEntry->FileNameOffset + pCurrentEntry->FileNameLength;
605             wtarget = (WCHAR *)((PBYTE)pCurrentEntry + pCurrentEntry->TargetNameOffset);
606
607             if (dwFlags & RDR_POP_EVALUATE_SYMLINKS) {
608                 char * mp;
609
610                 code2 = cm_HandleLink(scp, userp, reqp);
611                 if (code2 == 0) {
612                     mp = scp->mountPointStringp;
613                     len = strlen(mp);
614                     if ( len != 0 ) {
615                         /* Strip off the msdfs: prefix from the target name for the file system */
616                         if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
617                             osi_Log0(afsd_logp, "RDR_PopulateCurrentEntry DFSLink Detected");
618                             pCurrentEntry->FileType = scp->fileType;
619
620                             if (!strncmp("msdfs:", mp, 6)) {
621                                 mp += 6;
622                                 len -= 6;
623                             }
624                         }
625                         /* only send one slash to the redirector */
626                         if (mp[0] == '\\' && mp[1] == '\\') {
627                             mp++;
628                             len--;
629                         }
630 #ifdef UNICODE
631                         cch = MultiByteToWideChar( CP_UTF8, 0, mp,
632                                                    len * sizeof(char),
633                                                    wtarget,
634                                                    len * sizeof(WCHAR));
635 #else
636                         mbstowcs(wtarget, mp, len);
637 #endif
638                     }
639                     pCurrentEntry->TargetNameLength = (ULONG)(sizeof(WCHAR) * len);
640                 } else {
641                     osi_Log2(afsd_logp, "RDR_PopulateCurrentEntry cm_HandleLink failed scp=0x%p code=0x%x",
642                              scp, code2);
643                 }
644             }
645
646         }
647         break;
648
649     default:
650         pCurrentEntry->TargetNameOffset = 0;
651         pCurrentEntry->TargetNameLength = 0;
652     }
653     lock_ReleaseWrite(&scp->rw);
654
655     dwEntryLength += pCurrentEntry->FileNameLength + pCurrentEntry->TargetNameLength;
656     dwEntryLength += (dwEntryLength % 8) ? 8 - (dwEntryLength % 8) : 0;   /* quad align */
657     if (ppNextEntry)
658         *ppNextEntry = (AFSDirEnumEntry *)((PBYTE)pCurrentEntry + dwEntryLength);
659     if (pdwRemainingLength)
660         *pdwRemainingLength = dwMaxEntryLength - dwEntryLength;
661
662     osi_Log3(afsd_logp, "RDR_PopulateCurrentEntry Success FileNameLength=%d TargetNameLength=%d RemainingLength=%d",
663               pCurrentEntry->FileNameLength, pCurrentEntry->TargetNameLength, *pdwRemainingLength);
664
665     return code;
666 }
667
668 static afs_uint32
669 RDR_PopulateCurrentEntryNoScp( IN  AFSDirEnumEntry * pCurrentEntry,
670                                IN  DWORD             dwMaxEntryLength,
671                                IN  cm_scache_t     * dscp,
672                                IN  cm_fid_t        * fidp,
673                                IN  cm_user_t       * userp,
674                                IN  cm_req_t        * reqp,
675                                IN  wchar_t         * name,
676                                IN  wchar_t         * shortName,
677                                IN  DWORD             dwFlags,
678                                IN  afs_uint32        cmError,
679                                OUT AFSDirEnumEntry **ppNextEntry,
680                                OUT DWORD           * pdwRemainingLength)
681 {
682     FILETIME ft;
683     WCHAR *  wname;
684     size_t   len;
685     DWORD      dwEntryLength;
686     afs_uint32 code = 0, code2 = 0;
687
688     osi_Log4(afsd_logp, "RDR_PopulateCurrentEntryNoEntry dscp=0x%p name=%S short=%S flags=0x%x",
689              dscp, osi_LogSaveStringW(afsd_logp, name),
690              osi_LogSaveStringW(afsd_logp, shortName), dwFlags);
691     osi_Log1(afsd_logp, "... maxLength=%d", dwMaxEntryLength);
692
693     if (dwMaxEntryLength < sizeof(AFSDirEnumEntry) + (MAX_PATH + MOUNTPOINTLEN) * sizeof(wchar_t)) {
694         if (ppNextEntry)
695             *ppNextEntry = pCurrentEntry;
696         if (pdwRemainingLength)
697             *pdwRemainingLength = dwMaxEntryLength;
698         osi_Log2(afsd_logp, "RDR_PopulateCurrentEntryNoEntry Not Enough Room for Entry %d < %d",
699                  dwMaxEntryLength, sizeof(AFSDirEnumEntry) + (MAX_PATH + MOUNTPOINTLEN) * sizeof(wchar_t));
700         return CM_ERROR_TOOBIG;
701     }
702
703     if (!name)
704         name = L"";
705     if (!shortName)
706         shortName = L"";
707
708     dwEntryLength = sizeof(AFSDirEnumEntry);
709
710     /* Populate the error code */
711     smb_MapNTError(cmError, &pCurrentEntry->NTStatus, TRUE);
712
713     /* Populate the fake data */
714     pCurrentEntry->FileId.Cell = fidp->cell;
715     pCurrentEntry->FileId.Volume = fidp->volume;
716     pCurrentEntry->FileId.Vnode = fidp->vnode;
717     pCurrentEntry->FileId.Unique = fidp->unique;
718     pCurrentEntry->FileId.Hash = fidp->hash;
719
720     pCurrentEntry->FileType = CM_SCACHETYPE_UNKNOWN;
721
722     pCurrentEntry->DataVersion.QuadPart = CM_SCACHE_VERSION_BAD;
723
724     cm_LargeSearchTimeFromUnixTime(&ft, 0);
725     pCurrentEntry->Expiration.LowPart = ft.dwLowDateTime;
726     pCurrentEntry->Expiration.HighPart = ft.dwHighDateTime;
727
728     cm_LargeSearchTimeFromUnixTime(&ft, 0);
729     pCurrentEntry->CreationTime.LowPart = ft.dwLowDateTime;
730     pCurrentEntry->CreationTime.HighPart = ft.dwHighDateTime;
731     pCurrentEntry->LastAccessTime = pCurrentEntry->CreationTime;
732     pCurrentEntry->LastWriteTime = pCurrentEntry->CreationTime;
733     pCurrentEntry->ChangeTime = pCurrentEntry->CreationTime;
734
735     pCurrentEntry->EndOfFile.QuadPart = 0;
736     pCurrentEntry->AllocationSize.QuadPart = 0;
737     pCurrentEntry->FileAttributes = 0;
738     pCurrentEntry->EaSize = 0;
739     pCurrentEntry->Links = 0;
740
741     len = wcslen(shortName);
742     wcsncpy(pCurrentEntry->ShortName, shortName, len);
743     pCurrentEntry->ShortNameLength = (CCHAR)(len * sizeof(WCHAR));
744
745     pCurrentEntry->FileNameOffset = sizeof(AFSDirEnumEntry);
746     len = wcslen(name);
747     wname = (WCHAR *)((PBYTE)pCurrentEntry + pCurrentEntry->FileNameOffset);
748     wcsncpy(wname, name, len);
749     pCurrentEntry->FileNameLength = (ULONG)(sizeof(WCHAR) * len);
750
751     pCurrentEntry->TargetNameOffset = 0;
752     pCurrentEntry->TargetNameLength = 0;
753
754     dwEntryLength += pCurrentEntry->FileNameLength + pCurrentEntry->TargetNameLength;
755     dwEntryLength += (dwEntryLength % 8) ? 8 - (dwEntryLength % 8) : 0;   /* quad align */
756     if (ppNextEntry)
757         *ppNextEntry = (AFSDirEnumEntry *)((PBYTE)pCurrentEntry + dwEntryLength);
758     if (pdwRemainingLength)
759         *pdwRemainingLength = dwMaxEntryLength - dwEntryLength;
760
761     osi_Log3(afsd_logp, "RDR_PopulateCurrentEntryNoScp Success FileNameLength=%d TargetNameLength=%d RemainingLength=%d",
762               pCurrentEntry->FileNameLength, pCurrentEntry->TargetNameLength, *pdwRemainingLength);
763
764     return code;
765 }
766
767 void
768 RDR_EnumerateDirectory( IN cm_user_t *userp,
769                         IN AFSFileID DirID,
770                         IN AFSDirQueryCB *QueryCB,
771                         IN BOOL bWow64,
772                         IN BOOL bSkipStatus,
773                         IN DWORD ResultBufferLength,
774                         IN OUT AFSCommResult **ResultCB)
775 {
776     DWORD status;
777     cm_direnum_t *      enump = NULL;
778     AFSDirEnumResp  * pDirEnumResp;
779     AFSDirEnumEntry * pCurrentEntry;
780     size_t size = ResultBufferLength ? sizeof(AFSCommResult) + ResultBufferLength - 1 : sizeof(AFSCommResult);
781     DWORD             dwMaxEntryLength;
782     afs_uint32  code = 0;
783     cm_fid_t      fid;
784     cm_scache_t * dscp = NULL;
785     cm_req_t      req;
786
787     RDR_InitReq(&req, bWow64);
788
789     osi_Log4(afsd_logp, "RDR_EnumerateDirectory FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
790              DirID.Cell, DirID.Volume, DirID.Vnode, DirID.Unique);
791
792     *ResultCB = (AFSCommResult *)malloc(size);
793     if (!(*ResultCB)) {
794         osi_Log0(afsd_logp, "RDR_EnumerateDirectory Out of Memory");
795         return;
796     }
797
798     memset(*ResultCB, 0, size);
799
800     if (QueryCB->EnumHandle == (ULONG_PTR)-1) {
801         osi_Log0(afsd_logp, "RDR_EnumerateDirectory No More Entries");
802         (*ResultCB)->ResultStatus = STATUS_NO_MORE_ENTRIES;
803         (*ResultCB)->ResultBufferLength = 0;
804         return;
805     }
806
807     (*ResultCB)->ResultBufferLength = dwMaxEntryLength = ResultBufferLength;
808     if (ResultBufferLength) {
809         pDirEnumResp = (AFSDirEnumResp *)&(*ResultCB)->ResultData;
810         pCurrentEntry = (AFSDirEnumEntry *)&pDirEnumResp->Entry;
811         dwMaxEntryLength -= FIELD_OFFSET( AFSDirEnumResp, Entry);      /* AFSDirEnumResp */
812     }
813
814     if (DirID.Cell != 0) {
815         fid.cell   = DirID.Cell;
816         fid.volume = DirID.Volume;
817         fid.vnode  = DirID.Vnode;
818         fid.unique = DirID.Unique;
819         fid.hash   = DirID.Hash;
820
821         code = cm_GetSCache(&fid, NULL, &dscp, userp, &req);
822         if (code) {
823             smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
824             (*ResultCB)->ResultStatus = status;
825             osi_Log2(afsd_logp, "RDR_EnumerateDirectory cm_GetSCache failure code=0x%x status=0x%x",
826                       code, status);
827             return;
828         }
829     } else {
830         (*ResultCB)->ResultStatus = STATUS_OBJECT_NAME_INVALID;
831         osi_Log0(afsd_logp, "RDR_EnumerateDirectory Object Name Invalid - Cell = 0");
832         return;
833     }
834
835     /* get the directory size */
836     lock_ObtainWrite(&dscp->rw);
837     code = cm_SyncOp(dscp, NULL, userp, &req, PRSFS_LOOKUP,
838                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
839     if (code) {
840         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
841         (*ResultCB)->ResultStatus = status;
842         lock_ReleaseWrite(&dscp->rw);
843         cm_ReleaseSCache(dscp);
844         osi_Log2(afsd_logp, "RDR_EnumerateDirectory cm_SyncOp failure code=0x%x status=0x%x",
845                   code, status);
846         return;
847     }
848
849     cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
850     lock_ReleaseWrite(&dscp->rw);
851
852     if (dscp->fileType != CM_SCACHETYPE_DIRECTORY) {
853         (*ResultCB)->ResultStatus = STATUS_NOT_A_DIRECTORY;
854         cm_ReleaseSCache(dscp);
855         osi_Log1(afsd_logp, "RDR_EnumerateDirectory Not a Directory dscp=0x%p",
856                  dscp);
857         return;
858     }
859
860     osi_Log1(afsd_logp, "RDR_EnumerateDirectory dv=%u", (afs_uint32)dscp->dataVersion);
861
862     /*
863      * If there is no enumeration handle, then this is a new query
864      * and we must perform an enumeration for the specified object.
865      */
866     if (QueryCB->EnumHandle == (ULONG_PTR)NULL) {
867         cm_dirOp_t    dirop;
868
869         code = cm_BeginDirOp(dscp, userp, &req, CM_DIRLOCK_READ, CM_DIROP_FLAG_NONE, &dirop);
870         if (code == 0) {
871             code = cm_BPlusDirEnumerate(dscp, userp, &req,
872                                         TRUE /* dir locked */, NULL /* no mask */,
873                                         TRUE /* fetch status? */, &enump);
874             if (code) {
875                 osi_Log1(afsd_logp, "RDR_EnumerateDirectory cm_BPlusDirEnumerate failure code=0x%x",
876                           code);
877             }
878             cm_EndDirOp(&dirop);
879         } else {
880             osi_Log1(afsd_logp, "RDR_EnumerateDirectory cm_BeginDirOp failure code=0x%x",
881                       code);
882         }
883     } else {
884         enump = (cm_direnum_t *)QueryCB->EnumHandle;
885     }
886
887     if (enump) {
888         if (ResultBufferLength == 0) {
889             code = cm_BPlusDirEnumBulkStat(enump);
890             if (code) {
891                 osi_Log1(afsd_logp, "RDR_EnumerateDirectory cm_BPlusDirEnumBulkStat failure code=0x%x",
892                           code);
893             }
894         } else {
895             cm_direnum_entry_t * entryp = NULL;
896
897             pDirEnumResp->SnapshotDataVersion.QuadPart = enump->dataVersion;
898
899           getnextentry:
900             if (dwMaxEntryLength < sizeof(AFSDirEnumEntry) + (MAX_PATH + MOUNTPOINTLEN) * sizeof(wchar_t)) {
901                 osi_Log0(afsd_logp, "RDR_EnumerateDirectory out of space, returning");
902                 goto outofspace;
903             }
904
905             code = cm_BPlusDirNextEnumEntry(enump, &entryp);
906
907             if ((code == 0 || code == CM_ERROR_STOPNOW) && entryp) {
908                 cm_scache_t *scp = NULL;
909                 int stopnow = (code == CM_ERROR_STOPNOW);
910
911                 if ( !wcscmp(L".", entryp->name) || !wcscmp(L"..", entryp->name) ) {
912                     osi_Log0(afsd_logp, "RDR_EnumerateDirectory skipping . or ..");
913                     if (stopnow)
914                         goto outofspace;
915                     goto getnextentry;
916                 }
917
918                 if (bSkipStatus) {
919                     code = cm_GetSCache(&entryp->fid, &dscp->fid, &scp, userp, &req);
920                     if (code) {
921                         osi_Log5(afsd_logp, "RDR_EnumerateDirectory cm_GetSCache failure cell %u vol %u vnode %u uniq %u code=0x%x",
922                                  entryp->fid.cell, entryp->fid.volume, entryp->fid.vnode, entryp->fid.unique, code);
923                     }
924                 } else {
925                     code = entryp->errorCode;
926                     scp = code ? NULL : cm_FindSCache(&entryp->fid);
927                 }
928
929                 if (scp) {
930                     code = RDR_PopulateCurrentEntry( pCurrentEntry, dwMaxEntryLength,
931                                                      dscp, scp, userp, &req,
932                                                      entryp->name,
933                                                      cm_shortNames && cm_Is8Dot3(entryp->name) ? NULL : entryp->shortName,
934                                                      (bWow64 ? RDR_POP_WOW64 : 0) |
935                                                      (bSkipStatus ? RDR_POP_NO_GETSTATUS : 0),
936                                                      code,
937                                                      &pCurrentEntry, &dwMaxEntryLength);
938                     cm_ReleaseSCache(scp);
939                 } else {
940                     code = RDR_PopulateCurrentEntryNoScp( pCurrentEntry, dwMaxEntryLength,
941                                                           dscp, &entryp->fid, userp, &req,
942                                                           entryp->name,
943                                                           cm_shortNames && cm_Is8Dot3(entryp->name) ? NULL : entryp->shortName,
944                                                           (bWow64 ? RDR_POP_WOW64 : 0),
945                                                           code,
946                                                           &pCurrentEntry, &dwMaxEntryLength);
947                 }
948                 if (stopnow)
949                     goto outofspace;
950                 goto getnextentry;
951             }
952         }
953     }
954
955   outofspace:
956
957     if (code || enump->next == enump->count || ResultBufferLength == 0) {
958         cm_BPlusDirFreeEnumeration(enump);
959         enump = (cm_direnum_t *)(ULONG_PTR)-1;
960     }
961
962     if (code == 0 || code == CM_ERROR_STOPNOW) {
963         (*ResultCB)->ResultStatus = STATUS_SUCCESS;
964         osi_Log0(afsd_logp, "RDR_EnumerateDirectory SUCCESS");
965     } else {
966         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
967         (*ResultCB)->ResultStatus = status;
968         osi_Log2(afsd_logp, "RDR_EnumerateDirectory Failure code=0x%x status=0x%x",
969                   code, status);
970     }
971
972     if (ResultBufferLength) {
973         (*ResultCB)->ResultBufferLength = ResultBufferLength - dwMaxEntryLength;
974
975         pDirEnumResp->EnumHandle = (ULONG_PTR) enump;
976         pDirEnumResp->CurrentDataVersion.QuadPart = dscp->dataVersion;
977     }
978
979     if (dscp)
980         cm_ReleaseSCache(dscp);
981
982     return;
983 }
984
985 void
986 RDR_EvaluateNodeByName( IN cm_user_t *userp,
987                         IN AFSFileID ParentID,
988                         IN WCHAR   *FileNameCounted,
989                         IN DWORD    FileNameLength,
990                         IN BOOL     CaseSensitive,
991                         IN BOOL     LastComponent,
992                         IN BOOL     bWow64,
993                         IN BOOL     bHoldFid,
994                         IN BOOL     bNoFollow,
995                         IN DWORD    ResultBufferLength,
996                         IN OUT AFSCommResult **ResultCB)
997 {
998     AFSFileEvalResultCB *pEvalResultCB = NULL;
999     AFSDirEnumEntry * pCurrentEntry;
1000     size_t size = ResultBufferLength ? sizeof(AFSCommResult) + ResultBufferLength - 1 : sizeof(AFSCommResult);
1001     afs_uint32  code = 0;
1002     cm_scache_t * scp = NULL;
1003     cm_scache_t * dscp = NULL;
1004     cm_req_t      req;
1005     cm_fid_t      parentFid;
1006     DWORD         status;
1007     DWORD         dwRemaining;
1008     WCHAR       * wszName = NULL;
1009     size_t        cbName;
1010     BOOL          bVol = FALSE;
1011     wchar_t       FileName[260];
1012     afs_uint32    lookupFlags;
1013
1014     StringCchCopyNW(FileName, 260, FileNameCounted, FileNameLength / sizeof(WCHAR));
1015
1016     RDR_InitReq(&req, bWow64);
1017
1018     osi_Log4(afsd_logp, "RDR_EvaluateNodeByName parent FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
1019              ParentID.Cell, ParentID.Volume, ParentID.Vnode, ParentID.Unique);
1020
1021     /* Allocate enough room to add a volume prefix if necessary */
1022     cbName = FileNameLength + (CM_PREFIX_VOL_CCH + 64) * sizeof(WCHAR);
1023     wszName = malloc(cbName);
1024     if (!wszName) {
1025         osi_Log0(afsd_logp, "RDR_EvaluateNodeByName Out of Memory");
1026         return;
1027     }
1028     StringCbCopyNW(wszName, cbName, FileName, FileNameLength);
1029     osi_Log1(afsd_logp, "... name=%S", osi_LogSaveStringW(afsd_logp, wszName));
1030
1031     *ResultCB = (AFSCommResult *)malloc(size);
1032     if (!(*ResultCB)) {
1033         osi_Log0(afsd_logp, "RDR_EvaluateNodeByName Out of Memory");
1034         free(wszName);
1035         return;
1036     }
1037
1038     memset(*ResultCB, 0, size);
1039     (*ResultCB)->ResultBufferLength = 0;
1040     dwRemaining = ResultBufferLength;
1041     if (ResultBufferLength >= sizeof( AFSFileEvalResultCB)) {
1042         pEvalResultCB = (AFSFileEvalResultCB *)&(*ResultCB)->ResultData;
1043         pCurrentEntry = &pEvalResultCB->DirEnum;
1044         dwRemaining -= (sizeof( AFSFileEvalResultCB) - sizeof( AFSDirEnumEntry));
1045     }
1046
1047     if (ParentID.Cell != 0) {
1048         parentFid.cell   = ParentID.Cell;
1049         parentFid.volume = ParentID.Volume;
1050         parentFid.vnode  = ParentID.Vnode;
1051         parentFid.unique = ParentID.Unique;
1052         parentFid.hash   = ParentID.Hash;
1053
1054         code = cm_GetSCache(&parentFid, NULL, &dscp, userp, &req);
1055         if (code) {
1056             smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
1057             (*ResultCB)->ResultStatus = status;
1058             if ( status == STATUS_INVALID_HANDLE)
1059                 status = STATUS_OBJECT_PATH_INVALID;
1060             osi_Log2(afsd_logp, "RDR_EvaluateNodeByName cm_GetSCache parentFID failure code=0x%x status=0x%x",
1061                       code, status);
1062             free(wszName);
1063             return;
1064         }
1065     } else {
1066         (*ResultCB)->ResultStatus = STATUS_OBJECT_NAME_INVALID;
1067         osi_Log0(afsd_logp, "RDR_EvaluateNodeByName Object Name Invalid - Cell = 0");
1068         return;
1069     }
1070
1071     /* get the directory size */
1072     lock_ObtainWrite(&dscp->rw);
1073     code = cm_SyncOp(dscp, NULL, userp, &req, 0,
1074                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1075     if (code) {
1076         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
1077         (*ResultCB)->ResultStatus = status;
1078         lock_ReleaseWrite(&dscp->rw);
1079         cm_ReleaseSCache(dscp);
1080         osi_Log3(afsd_logp, "RDR_EvaluateNodeByName cm_SyncOp failure dscp=0x%p code=0x%x status=0x%x",
1081                  dscp, code, status);
1082         free(wszName);
1083         return;
1084     }
1085     cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1086     lock_ReleaseWrite(&dscp->rw);
1087
1088     if (dscp->fileType != CM_SCACHETYPE_DIRECTORY) {
1089         (*ResultCB)->ResultStatus = STATUS_NOT_A_DIRECTORY;
1090         cm_ReleaseSCache(dscp);
1091         osi_Log1(afsd_logp, "RDR_EvaluateNodeByName Not a Directory dscp=0x%p",
1092                  dscp);
1093         free(wszName);
1094         return;
1095     }
1096
1097     lookupFlags = CM_FLAG_NOMOUNTCHASE;
1098
1099     if ( !LastComponent )
1100         lookupFlags |= CM_FLAG_CHECKPATH;
1101     code = cm_Lookup(dscp, wszName, lookupFlags, userp, &req, &scp);
1102
1103     if (!CaseSensitive &&
1104         (code == CM_ERROR_NOSUCHPATH || code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH)) {
1105         lookupFlags |= CM_FLAG_CASEFOLD;
1106         code = cm_Lookup(dscp, wszName, lookupFlags, userp, &req, &scp);
1107     }
1108
1109     if ((code == CM_ERROR_NOSUCHPATH || code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH) &&
1110          dscp == cm_data.rootSCachep) {
1111
1112         if (wcschr(wszName, '%') != NULL || wcschr(wszName, '#') != NULL) {
1113             /*
1114              * A volume reference:  <cell>{%,#}<volume> -> @vol:<cell>{%,#}<volume>
1115              */
1116             StringCchCopyNW(wszName, cbName, _C(CM_PREFIX_VOL), CM_PREFIX_VOL_CCH);
1117             StringCbCatNW(wszName, cbName, FileName, FileNameLength);
1118             bVol = TRUE;
1119
1120             code = cm_EvaluateVolumeReference(wszName, CM_FLAG_CHECKPATH, userp, &req, &scp);
1121         }
1122 #ifdef AFS_FREELANCE_CLIENT
1123         else if (dscp->fid.cell == AFS_FAKE_ROOT_CELL_ID && dscp->fid.volume == AFS_FAKE_ROOT_VOL_ID &&
1124                  dscp->fid.vnode == 1 && dscp->fid.unique == 1) {
1125             /*
1126              * If this is the Freelance volume root directory then treat unrecognized
1127              * names as cell names and attempt to find the appropriate "root.cell".
1128              */
1129             StringCchCopyNW(wszName, cbName, _C(CM_PREFIX_VOL), CM_PREFIX_VOL_CCH);
1130             if (FileName[0] == L'.') {
1131                 StringCbCatNW(wszName, cbName, &FileName[1], FileNameLength);
1132                 StringCbCatNW(wszName, cbName, L"%", sizeof(WCHAR));
1133             } else {
1134                 StringCbCatNW(wszName, cbName, FileName, FileNameLength);
1135                 StringCbCatNW(wszName, cbName, L"#", sizeof(WCHAR));
1136             }
1137             StringCbCatNW(wszName, cbName, L"root.cell", 9 * sizeof(WCHAR));
1138             bVol = TRUE;
1139
1140             code = cm_EvaluateVolumeReference(wszName, CM_FLAG_CHECKPATH, userp, &req, &scp);
1141         }
1142 #endif
1143     }
1144
1145     if (code == 0 && scp) {
1146         wchar_t shortName[13]=L"";
1147
1148         if (!cm_shortNames) {
1149             shortName[0] = L'\0';
1150         } else if (bVol) {
1151             cm_Gen8Dot3VolNameW(scp->fid.cell, scp->fid.volume, shortName, NULL);
1152         } else if (!cm_Is8Dot3(wszName)) {
1153             cm_dirFid_t dfid;
1154
1155             dfid.vnode = htonl(scp->fid.vnode);
1156             dfid.unique = htonl(scp->fid.unique);
1157
1158             cm_Gen8Dot3NameIntW(FileName, &dfid, shortName, NULL);
1159         } else {
1160             shortName[0] = L'\0';
1161         }
1162
1163         code = RDR_PopulateCurrentEntry(pCurrentEntry, dwRemaining,
1164                                         dscp, scp, userp, &req,
1165                                         FileName, shortName,
1166                                         (bWow64 ? RDR_POP_WOW64 : 0) |
1167                                         (bNoFollow ? 0 : (RDR_POP_FOLLOW_MOUNTPOINTS | RDR_POP_EVALUATE_SYMLINKS)),
1168                                         0, NULL, &dwRemaining);
1169         if (bHoldFid)
1170             RDR_FlagScpInUse( scp, FALSE );
1171         cm_ReleaseSCache(scp);
1172
1173         if (code) {
1174             smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
1175             (*ResultCB)->ResultStatus = status;
1176             osi_Log2(afsd_logp, "RDR_EvaluateNodeByName FAILURE code=0x%x status=0x%x",
1177                       code, status);
1178         } else {
1179             pEvalResultCB->ParentDataVersion.QuadPart = dscp->dataVersion;
1180             (*ResultCB)->ResultStatus = STATUS_SUCCESS;
1181             (*ResultCB)->ResultBufferLength = ResultBufferLength - dwRemaining;
1182             osi_Log0(afsd_logp, "RDR_EvaluateNodeByName SUCCESS");
1183         }
1184     } else if (code) {
1185         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
1186         (*ResultCB)->ResultStatus = status;
1187         osi_Log2(afsd_logp, "RDR_EvaluateNodeByName FAILURE code=0x%x status=0x%x",
1188                  code, status);
1189     } else {
1190         (*ResultCB)->ResultStatus = STATUS_NO_SUCH_FILE;
1191         osi_Log0(afsd_logp, "RDR_EvaluateNodeByName No Such File");
1192     }
1193     cm_ReleaseSCache(dscp);
1194     free(wszName);
1195
1196     return;
1197 }
1198
1199 void
1200 RDR_EvaluateNodeByID( IN cm_user_t *userp,
1201                       IN AFSFileID ParentID,            /* not used */
1202                       IN AFSFileID SourceID,
1203                       IN BOOL      bWow64,
1204                       IN BOOL      bNoFollow,
1205                       IN BOOL      bHoldFid,
1206                       IN DWORD     ResultBufferLength,
1207                       IN OUT AFSCommResult **ResultCB)
1208 {
1209     AFSFileEvalResultCB *pEvalResultCB = NULL;
1210     AFSDirEnumEntry * pCurrentEntry = NULL;
1211     size_t size = ResultBufferLength ? sizeof(AFSCommResult) + ResultBufferLength - 1 : sizeof(AFSCommResult);
1212     afs_uint32  code = 0;
1213     cm_scache_t * scp = NULL;
1214     cm_scache_t * dscp = NULL;
1215     cm_req_t      req;
1216     cm_fid_t      Fid;
1217     cm_fid_t      parentFid;
1218     DWORD         status;
1219     DWORD         dwRemaining;
1220
1221     osi_Log4(afsd_logp, "RDR_EvaluateNodeByID source FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
1222               SourceID.Cell, SourceID.Volume, SourceID.Vnode, SourceID.Unique);
1223     osi_Log4(afsd_logp, "... parent FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
1224               ParentID.Cell, ParentID.Volume, ParentID.Vnode, ParentID.Unique);
1225
1226     *ResultCB = (AFSCommResult *)malloc(size);
1227     if (!(*ResultCB)) {
1228         osi_Log0(afsd_logp, "RDR_EvaluateNodeByID Out of Memory");
1229         return;
1230     }
1231
1232     memset(*ResultCB, 0, size);
1233     (*ResultCB)->ResultBufferLength = 0;
1234     dwRemaining = ResultBufferLength;
1235     if (ResultBufferLength >= sizeof( AFSFileEvalResultCB)) {
1236         pEvalResultCB = (AFSFileEvalResultCB *)&(*ResultCB)->ResultData;
1237         pCurrentEntry = &pEvalResultCB->DirEnum;
1238         dwRemaining -= (sizeof( AFSFileEvalResultCB) - sizeof( AFSDirEnumEntry));
1239     }
1240
1241     RDR_InitReq(&req, bWow64);
1242
1243     if (SourceID.Cell != 0) {
1244         cm_SetFid(&Fid, SourceID.Cell, SourceID.Volume, SourceID.Vnode, SourceID.Unique);
1245         code = cm_GetSCache(&Fid, NULL, &scp, userp, &req);
1246         if (code) {
1247             smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
1248             (*ResultCB)->ResultStatus = status;
1249             osi_Log2(afsd_logp, "RDR_EvaluateNodeByID cm_GetSCache SourceFID failure code=0x%x status=0x%x",
1250                       code, status);
1251             return;
1252         }
1253     } else {
1254         (*ResultCB)->ResultStatus = STATUS_OBJECT_NAME_INVALID;
1255         osi_Log0(afsd_logp, "RDR_EvaluateNodeByID Object Name Invalid - Cell = 0");
1256         return;
1257     }
1258
1259     if (ParentID.Cell != 0) {
1260         cm_SetFid(&parentFid, ParentID.Cell, ParentID.Volume, ParentID.Vnode, ParentID.Unique);
1261         code = cm_GetSCache(&parentFid, NULL, &dscp, userp, &req);
1262         if (code) {
1263             cm_ReleaseSCache(scp);
1264             smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
1265             if ( status == STATUS_INVALID_HANDLE)
1266                 status = STATUS_OBJECT_PATH_INVALID;
1267             (*ResultCB)->ResultStatus = status;
1268             osi_Log2(afsd_logp, "RDR_EvaluateNodeByID cm_GetSCache parentFID failure code=0x%x status=0x%x",
1269                       code, status);
1270             return;
1271         }
1272     } else if (SourceID.Vnode == 1) {
1273         dscp = scp;
1274         cm_HoldSCache(dscp);
1275     } else if (scp->parentVnode) {
1276         cm_SetFid(&parentFid, SourceID.Cell, SourceID.Volume, scp->parentVnode, scp->parentUnique);
1277         code = cm_GetSCache(&parentFid, NULL, &dscp, userp, &req);
1278         if (code) {
1279             cm_ReleaseSCache(scp);
1280             smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
1281             if ( status == STATUS_INVALID_HANDLE)
1282                 status = STATUS_OBJECT_PATH_INVALID;
1283             (*ResultCB)->ResultStatus = status;
1284             osi_Log2(afsd_logp, "RDR_EvaluateNodeByID cm_GetSCache parentFID failure code=0x%x status=0x%x",
1285                       code, status);
1286             return;
1287         }
1288     } else {
1289         (*ResultCB)->ResultStatus = STATUS_OBJECT_PATH_INVALID;
1290         osi_Log0(afsd_logp, "RDR_EvaluateNodeByID Object Path Invalid - Unknown Parent");
1291         return;
1292     }
1293
1294     /* Make sure the directory is current */
1295     lock_ObtainWrite(&dscp->rw);
1296     code = cm_SyncOp(dscp, NULL, userp, &req, 0,
1297                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1298     if (code) {
1299         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
1300         (*ResultCB)->ResultStatus = status;
1301         lock_ReleaseWrite(&dscp->rw);
1302         cm_ReleaseSCache(dscp);
1303         cm_ReleaseSCache(scp);
1304         osi_Log3(afsd_logp, "RDR_EvaluateNodeByID cm_SyncOp failure dscp=0x%p code=0x%x status=0x%x",
1305                  dscp, code, status);
1306         return;
1307     }
1308
1309     cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1310     lock_ReleaseWrite(&dscp->rw);
1311
1312     if (dscp->fileType != CM_SCACHETYPE_DIRECTORY) {
1313         (*ResultCB)->ResultStatus = STATUS_NOT_A_DIRECTORY;
1314         cm_ReleaseSCache(dscp);
1315         cm_ReleaseSCache(scp);
1316         osi_Log1(afsd_logp, "RDR_EvaluateNodeByID Not a Directory dscp=0x%p", dscp);
1317         return;
1318     }
1319
1320     code = RDR_PopulateCurrentEntry(pCurrentEntry, dwRemaining,
1321                                     dscp, scp, userp, &req, NULL, NULL,
1322                                     (bWow64 ? RDR_POP_WOW64 : 0) |
1323                                     (bNoFollow ? 0 : (RDR_POP_FOLLOW_MOUNTPOINTS | RDR_POP_EVALUATE_SYMLINKS)),
1324                                     0, NULL, &dwRemaining);
1325
1326     if (bHoldFid)
1327         RDR_FlagScpInUse( scp, FALSE );
1328     cm_ReleaseSCache(scp);
1329     cm_ReleaseSCache(dscp);
1330
1331     if (code) {
1332         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
1333         (*ResultCB)->ResultStatus = status;
1334         osi_Log2(afsd_logp, "RDR_EvaluateNodeByID FAILURE code=0x%x status=0x%x",
1335                  code, status);
1336     } else {
1337         pEvalResultCB->ParentDataVersion.QuadPart = dscp->dataVersion;
1338
1339         (*ResultCB)->ResultStatus = STATUS_SUCCESS;
1340         (*ResultCB)->ResultBufferLength = ResultBufferLength - dwRemaining;
1341         osi_Log0(afsd_logp, "RDR_EvaluateNodeByID SUCCESS");
1342     }
1343     return;
1344 }
1345
1346 void
1347 RDR_CreateFileEntry( IN cm_user_t *userp,
1348                      IN WCHAR *FileNameCounted,
1349                      IN DWORD FileNameLength,
1350                      IN AFSFileCreateCB *CreateCB,
1351                      IN BOOL bWow64,
1352                      IN BOOL bHoldFid,
1353                      IN DWORD ResultBufferLength,
1354                      IN OUT AFSCommResult **ResultCB)
1355 {
1356     AFSFileCreateResultCB *pResultCB = NULL;
1357     size_t size = sizeof(AFSCommResult) + ResultBufferLength - 1;
1358     cm_fid_t            parentFid;
1359     afs_uint32          code;
1360     cm_scache_t *       dscp = NULL;
1361     afs_uint32          flags = 0;
1362     cm_attr_t           setAttr;
1363     cm_scache_t *       scp = NULL;
1364     cm_req_t            req;
1365     DWORD               status;
1366     wchar_t             FileName[260];
1367
1368     StringCchCopyNW(FileName, 260, FileNameCounted, FileNameLength / sizeof(WCHAR));
1369
1370     osi_Log4(afsd_logp, "RDR_CreateFileEntry parent FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
1371               CreateCB->ParentId.Cell, CreateCB->ParentId.Volume,
1372               CreateCB->ParentId.Vnode, CreateCB->ParentId.Unique);
1373     osi_Log1(afsd_logp, "... name=%S", osi_LogSaveStringW(afsd_logp, FileName));
1374
1375     RDR_InitReq(&req, bWow64);
1376     memset(&setAttr, 0, sizeof(cm_attr_t));
1377
1378     *ResultCB = (AFSCommResult *)malloc(size);
1379     if (!(*ResultCB)) {
1380         osi_Log0(afsd_logp, "RDR_CreateFileEntry out of memory");
1381         return;
1382     }
1383
1384     memset( *ResultCB,
1385             '\0',
1386             size);
1387
1388     parentFid.cell   = CreateCB->ParentId.Cell;
1389     parentFid.volume = CreateCB->ParentId.Volume;
1390     parentFid.vnode  = CreateCB->ParentId.Vnode;
1391     parentFid.unique = CreateCB->ParentId.Unique;
1392     parentFid.hash   = CreateCB->ParentId.Hash;
1393
1394     code = cm_GetSCache(&parentFid, NULL, &dscp, userp, &req);
1395     if (code) {
1396         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
1397         (*ResultCB)->ResultStatus = status;
1398         if ( status == STATUS_INVALID_HANDLE)
1399             status = STATUS_OBJECT_PATH_INVALID;
1400         osi_Log2(afsd_logp, "RDR_CreateFileEntry cm_GetSCache ParentFID failure code=0x%x status=0x%x",
1401                   code, status);
1402         return;
1403     }
1404
1405     lock_ObtainWrite(&dscp->rw);
1406     code = cm_SyncOp(dscp, NULL, userp, &req, 0,
1407                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1408     if (code) {
1409         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
1410         (*ResultCB)->ResultStatus = status;
1411         lock_ReleaseWrite(&dscp->rw);
1412         cm_ReleaseSCache(dscp);
1413         osi_Log3(afsd_logp, "RDR_CreateFileEntry cm_SyncOp failure (1) dscp=0x%p code=0x%x status=0x%x",
1414                  dscp, code, status);
1415         return;
1416     }
1417
1418     cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1419     lock_ReleaseWrite(&dscp->rw);
1420
1421     if (dscp->fileType != CM_SCACHETYPE_DIRECTORY) {
1422         (*ResultCB)->ResultStatus = STATUS_NOT_A_DIRECTORY;
1423         cm_ReleaseSCache(dscp);
1424         osi_Log1(afsd_logp, "RDR_CreateFileEntry Not a Directory dscp=0x%p",
1425                  dscp);
1426         return;
1427     }
1428
1429     /* Use current time */
1430     setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
1431     setAttr.clientModTime = time(NULL);
1432
1433     if (CreateCB->FileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
1434         if (smb_unixModeDefaultDir) {
1435             setAttr.mask |= CM_ATTRMASK_UNIXMODEBITS;
1436             setAttr.unixModeBits = smb_unixModeDefaultDir;
1437             if (CreateCB->FileAttributes & FILE_ATTRIBUTE_READONLY)
1438                 setAttr.unixModeBits &= ~0222;          /* disable the write bits */
1439         }
1440
1441         code = cm_MakeDir(dscp, FileName, flags, &setAttr, userp, &req, &scp);
1442     } else {
1443         if (smb_unixModeDefaultFile) {
1444             setAttr.mask |= CM_ATTRMASK_UNIXMODEBITS;
1445             setAttr.unixModeBits = smb_unixModeDefaultFile;
1446             if (CreateCB->FileAttributes & FILE_ATTRIBUTE_READONLY)
1447                 setAttr.unixModeBits &= ~0222;          /* disable the write bits */
1448         }
1449
1450         setAttr.mask |= CM_ATTRMASK_LENGTH;
1451         setAttr.length.LowPart = CreateCB->AllocationSize.LowPart;
1452         setAttr.length.HighPart = CreateCB->AllocationSize.HighPart;
1453         code = cm_Create(dscp, FileName, flags, &setAttr, &scp, userp, &req);
1454     }
1455     if (code == 0) {
1456         wchar_t shortName[13]=L"";
1457         cm_dirFid_t dfid;
1458         DWORD dwRemaining;
1459
1460         (*ResultCB)->ResultStatus = 0;  // We will be able to fit all the data in here
1461
1462         (*ResultCB)->ResultBufferLength = sizeof( AFSFileCreateResultCB);
1463
1464         pResultCB = (AFSFileCreateResultCB *)(*ResultCB)->ResultData;
1465
1466         dwRemaining = ResultBufferLength - sizeof( AFSFileCreateResultCB) + sizeof( AFSDirEnumEntry);
1467
1468         lock_ObtainWrite(&dscp->rw);
1469         code = cm_SyncOp(dscp, NULL, userp, &req, 0,
1470                           CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1471         if (code) {
1472             smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
1473             (*ResultCB)->ResultStatus = status;
1474             lock_ReleaseWrite(&dscp->rw);
1475             cm_ReleaseSCache(dscp);
1476             cm_ReleaseSCache(scp);
1477             osi_Log3(afsd_logp, "RDR_CreateFileEntry cm_SyncOp failure (2) dscp=0x%p code=0x%x status=0x%x",
1478                       dscp, code, status);
1479             return;
1480         }
1481
1482         pResultCB->ParentDataVersion.QuadPart = dscp->dataVersion;
1483
1484         cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1485         lock_ReleaseWrite(&dscp->rw);
1486
1487         if (cm_shortNames) {
1488             dfid.vnode = htonl(scp->fid.vnode);
1489             dfid.unique = htonl(scp->fid.unique);
1490
1491             if (!cm_Is8Dot3(FileName))
1492                 cm_Gen8Dot3NameIntW(FileName, &dfid, shortName, NULL);
1493             else
1494                 shortName[0] = '\0';
1495         }
1496
1497         code = RDR_PopulateCurrentEntry(&pResultCB->DirEnum, dwRemaining,
1498                                         dscp, scp, userp, &req, FileName, shortName,
1499                                         RDR_POP_FOLLOW_MOUNTPOINTS | RDR_POP_EVALUATE_SYMLINKS,
1500                                         0, NULL, &dwRemaining);
1501
1502         if (bHoldFid)
1503             RDR_FlagScpInUse( scp, FALSE );
1504         cm_ReleaseSCache(scp);
1505         (*ResultCB)->ResultBufferLength = ResultBufferLength - dwRemaining;
1506         osi_Log0(afsd_logp, "RDR_CreateFileEntry SUCCESS");
1507     } else {
1508         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
1509         (*ResultCB)->ResultStatus = status;
1510         (*ResultCB)->ResultBufferLength = 0;
1511         osi_Log2(afsd_logp, "RDR_CreateFileEntry FAILURE code=0x%x status=0x%x",
1512                   code, status);
1513     }
1514
1515     cm_ReleaseSCache(dscp);
1516
1517     return;
1518 }
1519
1520 void
1521 RDR_UpdateFileEntry( IN cm_user_t *userp,
1522                      IN AFSFileID FileId,
1523                      IN AFSFileUpdateCB *UpdateCB,
1524                      IN BOOL bWow64,
1525                      IN DWORD ResultBufferLength,
1526                      IN OUT AFSCommResult **ResultCB)
1527 {
1528     AFSFileUpdateResultCB *pResultCB = NULL;
1529     size_t size = sizeof(AFSCommResult) + ResultBufferLength - 1;
1530     cm_fid_t            Fid;
1531     cm_fid_t            parentFid;
1532     afs_uint32          code;
1533     afs_uint32          flags = 0;
1534     cm_attr_t           setAttr;
1535     cm_scache_t *       scp = NULL;
1536     cm_scache_t *       dscp = NULL;
1537     cm_req_t            req;
1538     time_t              clientModTime;
1539     FILETIME            ft;
1540     DWORD               status;
1541     BOOL                bScpLocked = FALSE;
1542
1543     RDR_InitReq(&req, bWow64);
1544     memset(&setAttr, 0, sizeof(cm_attr_t));
1545
1546     osi_Log4(afsd_logp, "RDR_UpdateFileEntry parent FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
1547               UpdateCB->ParentId.Cell, UpdateCB->ParentId.Volume,
1548               UpdateCB->ParentId.Vnode, UpdateCB->ParentId.Unique);
1549     osi_Log4(afsd_logp, "... object FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
1550               FileId.Cell, FileId.Volume,
1551               FileId.Vnode, FileId.Unique);
1552
1553     *ResultCB = (AFSCommResult *)malloc( size);
1554     if (!(*ResultCB)) {
1555         osi_Log0(afsd_logp, "RDR_UpdateFileEntry Out of Memory");
1556         return;
1557     }
1558
1559     memset( *ResultCB,
1560             '\0',
1561             size);
1562
1563     parentFid.cell   = UpdateCB->ParentId.Cell;
1564     parentFid.volume = UpdateCB->ParentId.Volume;
1565     parentFid.vnode  = UpdateCB->ParentId.Vnode;
1566     parentFid.unique = UpdateCB->ParentId.Unique;
1567     parentFid.hash   = UpdateCB->ParentId.Hash;
1568
1569     code = cm_GetSCache(&parentFid, NULL, &dscp, userp, &req);
1570     if (code) {
1571         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
1572         (*ResultCB)->ResultStatus = status;
1573         if ( status == STATUS_INVALID_HANDLE)
1574             status = STATUS_OBJECT_PATH_INVALID;
1575         osi_Log2(afsd_logp, "RDR_UpdateFileEntry cm_GetSCache ParentFID failure code=0x%x status=0x%x",
1576                   code, status);
1577         return;
1578     }
1579
1580     lock_ObtainWrite(&dscp->rw);
1581     bScpLocked = TRUE;
1582     code = cm_SyncOp(dscp, NULL, userp, &req, 0,
1583                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1584     if (code) {
1585         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
1586         (*ResultCB)->ResultStatus = status;
1587         lock_ReleaseWrite(&dscp->rw);
1588         cm_ReleaseSCache(dscp);
1589         osi_Log3(afsd_logp, "RDR_UpdateFileEntry cm_SyncOp failure dscp=0x%p code=0x%x status=0x%x",
1590                  dscp, code, status);
1591         return;
1592     }
1593
1594     cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1595     lock_ReleaseWrite(&dscp->rw);
1596     bScpLocked = FALSE;
1597
1598     if (dscp->fileType != CM_SCACHETYPE_DIRECTORY) {
1599         (*ResultCB)->ResultStatus = STATUS_NOT_A_DIRECTORY;
1600         cm_ReleaseSCache(dscp);
1601         osi_Log1(afsd_logp, "RDR_UpdateFileEntry Not a Directory dscp=0x%p",
1602                  dscp);
1603         return;
1604     }
1605
1606     Fid.cell   = FileId.Cell;
1607     Fid.volume = FileId.Volume;
1608     Fid.vnode  = FileId.Vnode;
1609     Fid.unique = FileId.Unique;
1610     Fid.hash   = FileId.Hash;
1611
1612     code = cm_GetSCache(&Fid, &dscp->fid, &scp, userp, &req);
1613     if (code) {
1614         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
1615         (*ResultCB)->ResultStatus = status;
1616         cm_ReleaseSCache(dscp);
1617         osi_Log2(afsd_logp, "RDR_UpdateFileEntry cm_GetSCache object FID failure code=0x%x status=0x%x",
1618                   code, status);
1619         return;
1620     }
1621
1622     lock_ObtainWrite(&scp->rw);
1623     bScpLocked = TRUE;
1624     code = cm_SyncOp(scp, NULL, userp, &req, 0,
1625                       CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
1626     if (code) {
1627         lock_ReleaseWrite(&scp->rw);
1628         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
1629         (*ResultCB)->ResultStatus = status;
1630         (*ResultCB)->ResultBufferLength = 0;
1631         cm_ReleaseSCache(dscp);
1632         cm_ReleaseSCache(scp);
1633         osi_Log3(afsd_logp, "RDR_UpdateFileEntry cm_SyncOp failure scp=0x%p code=0x%x status=0x%x",
1634                  scp, code, status);
1635         return;
1636     }
1637     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1638
1639     if (UpdateCB->ChangeTime.QuadPart) {
1640
1641         if (scp->fileType == CM_SCACHETYPE_FILE) {
1642             /* Do not set length and other attributes at the same time */
1643             if (scp->length.QuadPart != UpdateCB->AllocationSize.QuadPart) {
1644                 osi_Log2(afsd_logp, "RDR_UpdateFileEntry Length Change 0x%x -> 0x%x",
1645                           (afs_uint32)scp->length.QuadPart, (afs_uint32)UpdateCB->AllocationSize.QuadPart);
1646                 setAttr.mask |= CM_ATTRMASK_LENGTH;
1647                 setAttr.length.LowPart = UpdateCB->AllocationSize.LowPart;
1648                 setAttr.length.HighPart = UpdateCB->AllocationSize.HighPart;
1649                 lock_ReleaseWrite(&scp->rw);
1650                 bScpLocked = FALSE;
1651                 code = cm_SetAttr(scp, &setAttr, userp, &req);
1652                 if (code)
1653                     goto on_error;
1654                 setAttr.mask = 0;
1655             }
1656         }
1657
1658         if (!bScpLocked) {
1659             lock_ObtainWrite(&scp->rw);
1660             bScpLocked = TRUE;
1661         }
1662         if ((scp->unixModeBits & 0200) && (UpdateCB->FileAttributes & FILE_ATTRIBUTE_READONLY)) {
1663             setAttr.mask |= CM_ATTRMASK_UNIXMODEBITS;
1664             setAttr.unixModeBits = scp->unixModeBits & ~0222;
1665         } else if (!(scp->unixModeBits & 0200) && !(UpdateCB->FileAttributes & FILE_ATTRIBUTE_READONLY)) {
1666             setAttr.mask |= CM_ATTRMASK_UNIXMODEBITS;
1667             setAttr.unixModeBits = scp->unixModeBits | 0222;
1668         }
1669     }
1670
1671     if (UpdateCB->LastWriteTime.QuadPart) {
1672         ft.dwLowDateTime = UpdateCB->LastWriteTime.LowPart;
1673         ft.dwHighDateTime = UpdateCB->LastWriteTime.HighPart;
1674
1675         cm_UnixTimeFromLargeSearchTime(& clientModTime, &ft);
1676
1677         if (!bScpLocked) {
1678             lock_ObtainWrite(&scp->rw);
1679             bScpLocked = TRUE;
1680         }
1681         if (scp->clientModTime != clientModTime) {
1682             setAttr.mask |= CM_ATTRMASK_CLIENTMODTIME;
1683             setAttr.clientModTime = clientModTime;
1684         }
1685
1686         /* call setattr */
1687         if (setAttr.mask) {
1688             lock_ReleaseWrite(&scp->rw);
1689             bScpLocked = FALSE;
1690             code = cm_SetAttr(scp, &setAttr, userp, &req);
1691         } else
1692             code = 0;
1693     }
1694
1695   on_error:
1696     if (bScpLocked) {
1697         lock_ReleaseWrite(&scp->rw);
1698     }
1699
1700     if (code == 0) {
1701         DWORD dwRemaining = ResultBufferLength - sizeof( AFSFileUpdateResultCB) + sizeof( AFSDirEnumEntry);
1702
1703         pResultCB = (AFSFileUpdateResultCB *)(*ResultCB)->ResultData;
1704
1705         pResultCB->ParentDataVersion.QuadPart = dscp->dataVersion;
1706
1707         code = RDR_PopulateCurrentEntry(&pResultCB->DirEnum, dwRemaining,
1708                                         dscp, scp, userp, &req, NULL, NULL,
1709                                         RDR_POP_FOLLOW_MOUNTPOINTS | RDR_POP_EVALUATE_SYMLINKS,
1710                                         0, NULL, &dwRemaining);
1711         (*ResultCB)->ResultBufferLength = ResultBufferLength - dwRemaining;
1712         osi_Log0(afsd_logp, "RDR_UpdateFileEntry SUCCESS");
1713     } else {
1714         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
1715         (*ResultCB)->ResultStatus = status;
1716         (*ResultCB)->ResultBufferLength = 0;
1717         osi_Log2(afsd_logp, "RDR_UpdateFileEntry FAILURE code=0x%x status=0x%x",
1718                   code, status);
1719     }
1720     cm_ReleaseSCache(scp);
1721     cm_ReleaseSCache(dscp);
1722
1723     return;
1724 }
1725
1726 void
1727 RDR_CleanupFileEntry( IN cm_user_t *userp,
1728                       IN AFSFileID FileId,
1729                       IN WCHAR *FileNameCounted,
1730                       IN DWORD FileNameLength,
1731                       IN AFSFileCleanupCB *CleanupCB,
1732                       IN BOOL bWow64,
1733                       IN BOOL bLastHandle,
1734                       IN BOOL bDeleteFile,
1735                       IN BOOL bUnlockFile,
1736                       IN DWORD ResultBufferLength,
1737                       IN OUT AFSCommResult **ResultCB)
1738 {
1739     AFSFileCleanupResultCB *pResultCB = NULL;
1740     size_t size = sizeof(AFSCommResult) + ResultBufferLength - 1;
1741     cm_fid_t            Fid;
1742     cm_fid_t            parentFid;
1743     afs_uint32          code = 0;
1744     afs_uint32          flags = 0;
1745     cm_attr_t           setAttr;
1746     cm_scache_t *       scp = NULL;
1747     cm_scache_t *       dscp = NULL;
1748     cm_req_t            req;
1749     time_t              clientModTime;
1750     FILETIME            ft;
1751     DWORD               status;
1752     BOOL                bScpLocked = FALSE;
1753     BOOL                bDscpLocked = FALSE;
1754     BOOL                bFlushFile = FALSE;
1755     cm_key_t            key;
1756
1757     RDR_InitReq(&req, bWow64);
1758     memset(&setAttr, 0, sizeof(cm_attr_t));
1759
1760     osi_Log4(afsd_logp, "RDR_CleanupFileEntry parent FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
1761               CleanupCB->ParentId.Cell, CleanupCB->ParentId.Volume,
1762               CleanupCB->ParentId.Vnode, CleanupCB->ParentId.Unique);
1763     osi_Log4(afsd_logp, "... object FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
1764               FileId.Cell, FileId.Volume,
1765               FileId.Vnode, FileId.Unique);
1766
1767     *ResultCB = (AFSCommResult *)malloc( size);
1768     if (!(*ResultCB)) {
1769         osi_Log0(afsd_logp, "RDR_CleanupFileEntry Out of Memory");
1770         return;
1771     }
1772
1773     memset( *ResultCB,
1774             '\0',
1775             size);
1776
1777     parentFid.cell   = CleanupCB->ParentId.Cell;
1778     parentFid.volume = CleanupCB->ParentId.Volume;
1779     parentFid.vnode  = CleanupCB->ParentId.Vnode;
1780     parentFid.unique = CleanupCB->ParentId.Unique;
1781     parentFid.hash   = CleanupCB->ParentId.Hash;
1782
1783     if (parentFid.cell) {
1784         code = cm_GetSCache(&parentFid, NULL, &dscp, userp, &req);
1785         if (code) {
1786             smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
1787             if ( status == STATUS_INVALID_HANDLE)
1788                 status = STATUS_OBJECT_PATH_INVALID;
1789             (*ResultCB)->ResultStatus = status;
1790             osi_Log2(afsd_logp, "RDR_CleanupFileEntry cm_GetSCache ParentFID failure code=0x%x status=0x%x",
1791                      code, status);
1792             return;
1793         }
1794
1795         lock_ObtainWrite(&dscp->rw);
1796         bDscpLocked = TRUE;
1797         code = cm_SyncOp(dscp, NULL, userp, &req, 0,
1798                          CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1799         if (code) {
1800             osi_Log2(afsd_logp, "RDR_CleanupFileEntry cm_SyncOp failure dscp=0x%p code=0x%x",
1801                     dscp, code);
1802             if (code)
1803                 goto on_error;
1804         }
1805
1806         cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1807         lock_ReleaseWrite(&dscp->rw);
1808         bDscpLocked = FALSE;
1809
1810         if (dscp->fileType != CM_SCACHETYPE_DIRECTORY) {
1811             (*ResultCB)->ResultStatus = STATUS_NOT_A_DIRECTORY;
1812             cm_ReleaseSCache(dscp);
1813             osi_Log1(afsd_logp, "RDR_CleanupFileEntry Not a Directory dscp=0x%p",
1814                      dscp);
1815             if (code)
1816                 goto on_error;
1817         }
1818     }
1819
1820     Fid.cell   = FileId.Cell;
1821     Fid.volume = FileId.Volume;
1822     Fid.vnode  = FileId.Vnode;
1823     Fid.unique = FileId.Unique;
1824     Fid.hash   = FileId.Hash;
1825
1826     code = cm_GetSCache(&Fid, dscp ? &dscp->fid : NULL, &scp, userp, &req);
1827     if (code) {
1828         osi_Log1(afsd_logp, "RDR_CleanupFileEntry cm_GetSCache object FID failure code=0x%x",
1829                  code);
1830         goto on_error;
1831     }
1832
1833     lock_ObtainWrite(&scp->rw);
1834     bScpLocked = TRUE;
1835     code = cm_SyncOp(scp, NULL, userp, &req, 0,
1836                       CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
1837     if (code) {
1838         osi_Log2(afsd_logp, "RDR_CleanupFileEntry cm_SyncOp failure scp=0x%p code=0x%x",
1839                  scp, code);
1840         goto on_error;
1841     }
1842     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1843
1844     if (bLastHandle && (scp->fileType == CM_SCACHETYPE_FILE) &&
1845         scp->redirBufCount > 0)
1846     {
1847         LARGE_INTEGER heldExtents;
1848         AFSFileExtentCB extentList[1024];
1849         DWORD extentCount = 0;
1850         cm_buf_t *srbp;
1851         time_t now;
1852
1853         time(&now);
1854         heldExtents.QuadPart = 0;
1855
1856         for ( srbp = redirq_to_cm_buf_t(scp->redirQueueT);
1857               srbp;
1858               srbp = redirq_to_cm_buf_t(osi_QPrev(&srbp->redirq)))
1859         {
1860             extentList[extentCount].Flags = 0;
1861             extentList[extentCount].Length = cm_data.blockSize;
1862             extentList[extentCount].FileOffset.QuadPart = srbp->offset.QuadPart;
1863             extentList[extentCount].CacheOffset.QuadPart = srbp->datap - RDR_extentBaseAddress;
1864             lock_ObtainWrite(&buf_globalLock);
1865             srbp->redirReleaseRequested = now;
1866             lock_ReleaseWrite(&buf_globalLock);
1867             extentCount++;
1868
1869             if (extentCount == 1024) {
1870                 lock_ReleaseWrite(&scp->rw);
1871                 code = RDR_RequestExtentRelease(&scp->fid, heldExtents, extentCount, extentList);
1872                 if (code) {
1873                     if (code == CM_ERROR_RETRY) {
1874                         /*
1875                          * The redirector either is not holding the extents or cannot let them
1876                          * go because they are otherwise in use.  At the moment, do nothing.
1877                          */
1878                     } else
1879                         break;
1880                 }
1881                 extentCount = 0;
1882                 bFlushFile = TRUE;
1883                 lock_ObtainWrite(&scp->rw);
1884             }
1885         }
1886
1887         if (code == 0 && extentCount > 0) {
1888             if (bScpLocked) {
1889                 lock_ReleaseWrite(&scp->rw);
1890                 bScpLocked = FALSE;
1891             }
1892             code = RDR_RequestExtentRelease(&scp->fid, heldExtents, extentCount, extentList);
1893             bFlushFile = TRUE;
1894         }
1895     }
1896
1897     /* No longer in use by redirector */
1898     if (!bScpLocked) {
1899         lock_ObtainWrite(&scp->rw);
1900         bScpLocked = TRUE;
1901     }
1902
1903     if (bLastHandle) {
1904         lock_AssertWrite(&scp->rw);
1905         scp->flags &= ~CM_SCACHEFLAG_RDR_IN_USE;
1906     }
1907
1908     /* If not a readonly object, flush dirty data and update metadata */
1909     if (!(scp->flags & CM_SCACHEFLAG_RO)) {
1910         if ((scp->fileType == CM_SCACHETYPE_FILE) && (bLastHandle || bFlushFile)) {
1911             /* Serialize with any outstanding AsyncStore operation */
1912             code = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_ASYNCSTORE);
1913             if (code == 0) {
1914                 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_ASYNCSTORE);
1915
1916                 code = cm_SyncOp(scp, NULL, userp, &req, PRSFS_WRITE,
1917                                  CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1918                 /*
1919                  * If we only have 'i' bits, then we should still be able to
1920                  * set flush the file.
1921                  */
1922                 if (code == CM_ERROR_NOACCESS && scp->creator == userp) {
1923                     code = cm_SyncOp(scp, NULL, userp, &req, PRSFS_INSERT,
1924                                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1925                 }
1926                 if (code == 0) {
1927                     if (bScpLocked) {
1928                         lock_ReleaseWrite(&scp->rw);
1929                         bScpLocked = FALSE;
1930                     }
1931
1932                     code = cm_FSync(scp, userp, &req, bScpLocked);
1933                 }
1934             }
1935             if (bLastHandle && code)
1936                 goto unlock;
1937         }
1938
1939         if (CleanupCB->ChangeTime.QuadPart) {
1940
1941             if (scp->fileType == CM_SCACHETYPE_FILE) {
1942                 /* Do not set length and other attributes at the same time */
1943                 if (scp->length.QuadPart != CleanupCB->AllocationSize.QuadPart) {
1944                     osi_Log2(afsd_logp, "RDR_CleanupFileEntry Length Change 0x%x -> 0x%x",
1945                              (afs_uint32)scp->length.QuadPart, (afs_uint32)CleanupCB->AllocationSize.QuadPart);
1946                     setAttr.mask |= CM_ATTRMASK_LENGTH;
1947                     setAttr.length.LowPart = CleanupCB->AllocationSize.LowPart;
1948                     setAttr.length.HighPart = CleanupCB->AllocationSize.HighPart;
1949
1950                     if (bScpLocked) {
1951                         lock_ReleaseWrite(&scp->rw);
1952                         bScpLocked = FALSE;
1953                     }
1954                     code = cm_SetAttr(scp, &setAttr, userp, &req);
1955                     if (code)
1956                         goto unlock;
1957                     setAttr.mask = 0;
1958                 }
1959             }
1960
1961             if (!bScpLocked) {
1962                 lock_ObtainWrite(&scp->rw);
1963                 bScpLocked = TRUE;
1964             }
1965
1966             if ((scp->unixModeBits & 0200) && (CleanupCB->FileAttributes & FILE_ATTRIBUTE_READONLY)) {
1967                 setAttr.mask |= CM_ATTRMASK_UNIXMODEBITS;
1968                 setAttr.unixModeBits = scp->unixModeBits & ~0222;
1969             } else if (!(scp->unixModeBits & 0200) && !(CleanupCB->FileAttributes & FILE_ATTRIBUTE_READONLY)) {
1970                 setAttr.mask |= CM_ATTRMASK_UNIXMODEBITS;
1971                 setAttr.unixModeBits = scp->unixModeBits | 0222;
1972             }
1973         }
1974
1975         if (CleanupCB->LastWriteTime.QuadPart) {
1976             ft.dwLowDateTime = CleanupCB->LastWriteTime.LowPart;
1977             ft.dwHighDateTime = CleanupCB->LastWriteTime.HighPart;
1978
1979             cm_UnixTimeFromLargeSearchTime(&clientModTime, &ft);
1980             if (scp->clientModTime != clientModTime) {
1981                 setAttr.mask |= CM_ATTRMASK_CLIENTMODTIME;
1982                 setAttr.clientModTime = clientModTime;
1983             }
1984         }
1985
1986         /* call setattr */
1987         if (setAttr.mask) {
1988             if (bScpLocked) {
1989                 lock_ReleaseWrite(&scp->rw);
1990                 bScpLocked = FALSE;
1991             }
1992             code = cm_SetAttr(scp, &setAttr, userp, &req);
1993         } else
1994             code = 0;
1995     }
1996
1997   unlock:
1998     /* Now drop the lock enforcing the share access */
1999     if ( CleanupCB->FileAccess != AFS_FILE_ACCESS_NOLOCK) {
2000         unsigned int sLockType;
2001         LARGE_INTEGER LOffset, LLength;
2002
2003         if (CleanupCB->FileAccess == AFS_FILE_ACCESS_SHARED)
2004             sLockType = LOCKING_ANDX_SHARED_LOCK;
2005         else
2006             sLockType = 0;
2007
2008         key = cm_GenerateKey(CM_SESSION_IFS, SMB_FID_QLOCK_PID, CleanupCB->Identifier);
2009
2010         LOffset.HighPart = SMB_FID_QLOCK_HIGH;
2011         LOffset.LowPart = SMB_FID_QLOCK_LOW;
2012         LLength.HighPart = 0;
2013         LLength.LowPart = SMB_FID_QLOCK_LENGTH;
2014
2015         if (!bScpLocked) {
2016             lock_ObtainWrite(&scp->rw);
2017             bScpLocked = TRUE;
2018         }
2019
2020         code = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_LOCK);
2021         if (code == 0)
2022         {
2023             code = cm_Unlock(scp, sLockType, LOffset, LLength, key, 0, userp, &req);
2024
2025             cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
2026
2027             if (code == CM_ERROR_RANGE_NOT_LOCKED)
2028             {
2029                 osi_Log3(afsd_logp, "RDR_CleanupFileEntry Range Not Locked -- FileAccess 0x%x ProcessId 0x%x HandleId 0x%x",
2030                          CleanupCB->FileAccess, CleanupCB->ProcessId, CleanupCB->Identifier);
2031
2032             }
2033         }
2034     }
2035
2036     if (bUnlockFile || bDeleteFile) {
2037         if (!bScpLocked) {
2038             lock_ObtainWrite(&scp->rw);
2039             bScpLocked = TRUE;
2040         }
2041         code = cm_SyncOp(scp, NULL, userp, &req, 0,
2042                           CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_LOCK);
2043         if (code) {
2044             osi_Log2(afsd_logp, "RDR_CleanupFileEntry cm_SyncOp (2) failure scp=0x%p code=0x%x",
2045                      scp, code);
2046             goto on_error;
2047         }
2048
2049         key = cm_GenerateKey(CM_SESSION_IFS, CleanupCB->ProcessId, 0);
2050
2051         /* the scp is now locked and current */
2052         code = cm_UnlockByKey(scp, key,
2053                               bDeleteFile ? CM_UNLOCK_FLAG_BY_FID : 0,
2054                               userp, &req);
2055
2056         cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_LOCK);
2057
2058         if (code)
2059             goto on_error;
2060     }
2061
2062   on_error:
2063     if (bDscpLocked)
2064         lock_ReleaseWrite(&dscp->rw);
2065     if (bScpLocked)
2066         lock_ReleaseWrite(&scp->rw);
2067
2068     if (code == 0 && dscp && bDeleteFile) {
2069         WCHAR FileName[260];
2070
2071         StringCchCopyNW(FileName, 260, FileNameCounted, FileNameLength / sizeof(WCHAR));
2072
2073         if (scp->fileType == CM_SCACHETYPE_DIRECTORY)
2074             code = cm_RemoveDir(dscp, NULL, FileName, userp, &req);
2075         else
2076             code = cm_Unlink(dscp, NULL, FileName, userp, &req);
2077     }
2078
2079     if (code == 0) {
2080         if ( ResultBufferLength >=  sizeof( AFSFileCleanupResultCB))
2081         {
2082             (*ResultCB)->ResultBufferLength = sizeof( AFSFileCleanupResultCB);
2083             pResultCB = (AFSFileCleanupResultCB *)&(*ResultCB)->ResultData;
2084             pResultCB->ParentDataVersion.QuadPart = dscp ? dscp->dataVersion : 0;
2085         } else {
2086             (*ResultCB)->ResultBufferLength = 0;
2087         }
2088
2089         (*ResultCB)->ResultStatus = 0;
2090         osi_Log0(afsd_logp, "RDR_CleanupFileEntry SUCCESS");
2091     } else {
2092         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
2093         (*ResultCB)->ResultStatus = status;
2094         osi_Log2(afsd_logp, "RDR_CleanupFileEntry FAILURE code=0x%x status=0x%x",
2095                   code, status);
2096     }
2097
2098     if (scp)
2099         cm_ReleaseSCache(scp);
2100     if (dscp)
2101         cm_ReleaseSCache(dscp);
2102
2103     return;
2104 }
2105
2106 void
2107 RDR_DeleteFileEntry( IN cm_user_t *userp,
2108                      IN AFSFileID ParentId,
2109                      IN ULONGLONG ProcessId,
2110                      IN WCHAR *FileNameCounted,
2111                      IN DWORD FileNameLength,
2112                      IN BOOL bWow64,
2113                      IN BOOL bCheckOnly,
2114                      IN DWORD ResultBufferLength,
2115                      IN OUT AFSCommResult **ResultCB)
2116 {
2117
2118     AFSFileDeleteResultCB *pResultCB = NULL;
2119     size_t size = sizeof(AFSCommResult) + ResultBufferLength - 1;
2120     cm_fid_t            parentFid;
2121     afs_uint32          code;
2122     cm_scache_t *       dscp = NULL;
2123     cm_scache_t *       scp = NULL;
2124     afs_uint32          flags = 0;
2125     cm_attr_t           setAttr;
2126     cm_req_t            req;
2127     DWORD               status;
2128     wchar_t             FileName[260];
2129     cm_key_t            key;
2130
2131     StringCchCopyNW(FileName, 260, FileNameCounted, FileNameLength / sizeof(WCHAR));
2132
2133     osi_Log4(afsd_logp, "RDR_DeleteFileEntry parent FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
2134               ParentId.Cell,  ParentId.Volume,
2135               ParentId.Vnode, ParentId.Unique);
2136     osi_Log2(afsd_logp, "... name=%S checkOnly=%x",
2137              osi_LogSaveStringW(afsd_logp, FileName),
2138              bCheckOnly);
2139
2140     RDR_InitReq(&req, bWow64);
2141     memset(&setAttr, 0, sizeof(cm_attr_t));
2142
2143     *ResultCB = (AFSCommResult *)malloc( size);
2144     if (!(*ResultCB)) {
2145         osi_Log0(afsd_logp, "RDR_DeleteFileEntry out of memory");
2146         return;
2147     }
2148
2149     memset( *ResultCB,
2150             '\0',
2151             size);
2152
2153     parentFid.cell   = ParentId.Cell;
2154     parentFid.volume = ParentId.Volume;
2155     parentFid.vnode  = ParentId.Vnode;
2156     parentFid.unique = ParentId.Unique;
2157     parentFid.hash   = ParentId.Hash;
2158
2159     code = cm_GetSCache(&parentFid, NULL, &dscp, userp, &req);
2160     if (code) {
2161         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
2162         if ( status == STATUS_INVALID_HANDLE)
2163             status = STATUS_OBJECT_PATH_INVALID;
2164         (*ResultCB)->ResultStatus = status;
2165         osi_Log2(afsd_logp, "RDR_DeleteFileEntry cm_GetSCache ParentFID failure code=0x%x status=0x%x",
2166                   code, status);
2167         return;
2168     }
2169
2170     lock_ObtainWrite(&dscp->rw);
2171
2172     code = cm_SyncOp(dscp, NULL, userp, &req, 0,
2173                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2174     if (code) {
2175         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
2176         (*ResultCB)->ResultStatus = status;
2177         (*ResultCB)->ResultBufferLength = 0;
2178         lock_ReleaseWrite(&dscp->rw);
2179         cm_ReleaseSCache(dscp);
2180         osi_Log3(afsd_logp, "RDR_DeleteFileEntry cm_SyncOp failure dscp=0x%p code=0x%x status=0x%x",
2181                  dscp, code, status);
2182         return;
2183     }
2184
2185     cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2186     lock_ReleaseWrite(&dscp->rw);
2187
2188     if (dscp->fileType != CM_SCACHETYPE_DIRECTORY) {
2189         (*ResultCB)->ResultStatus = STATUS_NOT_A_DIRECTORY;
2190         cm_ReleaseSCache(dscp);
2191         osi_Log1(afsd_logp, "RDR_DeleteFileEntry Not a Directory dscp=0x%p",
2192                  dscp);
2193         return;
2194     }
2195
2196     code = cm_Lookup(dscp, FileName, 0, userp, &req, &scp);
2197     if (code) {
2198         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
2199         (*ResultCB)->ResultStatus = status;
2200         (*ResultCB)->ResultBufferLength = 0;
2201         cm_ReleaseSCache(dscp);
2202         osi_Log2(afsd_logp, "RDR_DeleteFileEntry cm_Lookup failure code=0x%x status=0x%x",
2203                  code, status);
2204         return;
2205     }
2206
2207     lock_ObtainWrite(&scp->rw);
2208     code = cm_SyncOp(scp, NULL, userp, &req, PRSFS_DELETE,
2209                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2210     if (code) {
2211         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
2212         (*ResultCB)->ResultStatus = status;
2213         (*ResultCB)->ResultBufferLength = 0;
2214         lock_ReleaseWrite(&scp->rw);
2215         cm_ReleaseSCache(scp);
2216         cm_ReleaseSCache(dscp);
2217         osi_Log3(afsd_logp, "RDR_DeleteFileEntry cm_SyncOp failure scp=0x%p code=0x%x status=0x%x",
2218                  scp, code, status);
2219         return;
2220     }
2221
2222     if (!bCheckOnly) {
2223         /* Drop all locks since the file is being deleted */
2224         code = cm_SyncOp(scp, NULL, userp, &req, 0,
2225                          CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_LOCK);
2226         if (code) {
2227             smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
2228             (*ResultCB)->ResultStatus = status;
2229             (*ResultCB)->ResultBufferLength = 0;
2230             lock_ReleaseWrite(&scp->rw);
2231             cm_ReleaseSCache(scp);
2232             cm_ReleaseSCache(dscp);
2233             osi_Log3(afsd_logp, "RDR_DeleteFileEntry cm_SyncOp Lock failure scp=0x%p code=0x%x status=0x%x",
2234                      scp, code, status);
2235         }
2236
2237         /* the scp is now locked and current */
2238         key = cm_GenerateKey(CM_SESSION_IFS, ProcessId, 0);
2239
2240         code = cm_UnlockByKey(scp, key,
2241                               CM_UNLOCK_FLAG_BY_FID,
2242                               userp, &req);
2243
2244         cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_LOCK);
2245         lock_ReleaseWrite(&scp->rw);
2246
2247         if (scp->fileType == CM_SCACHETYPE_DIRECTORY)
2248             code = cm_RemoveDir(dscp, NULL, FileName, userp, &req);
2249         else
2250             code = cm_Unlink(dscp, NULL, FileName, userp, &req);
2251     } else {
2252         lock_ReleaseWrite(&scp->rw);
2253     }
2254
2255     if (code == 0) {
2256         (*ResultCB)->ResultStatus = 0;  // We will be able to fit all the data in here
2257
2258         (*ResultCB)->ResultBufferLength = sizeof( AFSFileDeleteResultCB);
2259
2260         pResultCB = (AFSFileDeleteResultCB *)(*ResultCB)->ResultData;
2261
2262         pResultCB->ParentDataVersion.QuadPart = dscp->dataVersion;
2263         osi_Log0(afsd_logp, "RDR_DeleteFileEntry SUCCESS");
2264     } else {
2265         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
2266         (*ResultCB)->ResultStatus = status;
2267         (*ResultCB)->ResultBufferLength = 0;
2268         osi_Log2(afsd_logp, "RDR_DeleteFileEntry FAILURE code=0x%x status=0x%x",
2269                   code, status);
2270     }
2271
2272     cm_ReleaseSCache(dscp);
2273     cm_ReleaseSCache(scp);
2274
2275     return;
2276 }
2277
2278 void
2279 RDR_RenameFileEntry( IN cm_user_t *userp,
2280                      IN WCHAR    *SourceFileNameCounted,
2281                      IN DWORD     SourceFileNameLength,
2282                      IN AFSFileID SourceFileId,
2283                      IN AFSFileRenameCB *pRenameCB,
2284                      IN BOOL bWow64,
2285                      IN DWORD ResultBufferLength,
2286                      IN OUT AFSCommResult **ResultCB)
2287 {
2288
2289     AFSFileRenameResultCB *pResultCB = NULL;
2290     size_t size = sizeof(AFSCommResult) + ResultBufferLength - 1;
2291     AFSFileID              SourceParentId   = pRenameCB->SourceParentId;
2292     AFSFileID              TargetParentId   = pRenameCB->TargetParentId;
2293     WCHAR *                TargetFileNameCounted = pRenameCB->TargetName;
2294     DWORD                  TargetFileNameLength = pRenameCB->TargetNameLength;
2295     cm_fid_t               SourceParentFid;
2296     cm_fid_t               TargetParentFid;
2297     cm_fid_t               SourceFid;
2298     cm_fid_t               OrigTargetFid = {0,0,0,0,0};
2299     cm_fid_t               TargetFid;
2300     cm_scache_t *          oldDscp;
2301     cm_scache_t *          newDscp;
2302     cm_dirOp_t dirop;
2303     wchar_t                shortName[13];
2304     wchar_t                SourceFileName[260];
2305     wchar_t                TargetFileName[260];
2306     cm_dirFid_t            dfid;
2307     cm_req_t               req;
2308     afs_uint32             code;
2309     DWORD                  status;
2310
2311     RDR_InitReq(&req, bWow64);
2312
2313     StringCchCopyNW(SourceFileName, 260, SourceFileNameCounted, SourceFileNameLength / sizeof(WCHAR));
2314     StringCchCopyNW(TargetFileName, 260, TargetFileNameCounted, TargetFileNameLength / sizeof(WCHAR));
2315
2316     osi_Log4(afsd_logp, "RDR_RenameFileEntry Source Parent FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
2317               SourceParentId.Cell,  SourceParentId.Volume,
2318               SourceParentId.Vnode, SourceParentId.Unique);
2319     osi_Log2(afsd_logp, "... Source Name=%S Length %u", osi_LogSaveStringW(afsd_logp, SourceFileName), SourceFileNameLength);
2320     osi_Log4(afsd_logp, "... Target Parent FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
2321               TargetParentId.Cell,  TargetParentId.Volume,
2322               TargetParentId.Vnode, TargetParentId.Unique);
2323     osi_Log2(afsd_logp, "... Target Name=%S Length %u", osi_LogSaveStringW(afsd_logp, TargetFileName), TargetFileNameLength);
2324
2325     *ResultCB = (AFSCommResult *)malloc( size);
2326     if (!(*ResultCB))
2327         return;
2328
2329     memset( *ResultCB,
2330             '\0',
2331             size);
2332
2333     pResultCB = (AFSFileRenameResultCB *)(*ResultCB)->ResultData;
2334
2335     if (SourceFileNameLength == 0 || TargetFileNameLength == 0)
2336     {
2337         osi_Log2(afsd_logp, "RDR_RenameFileEntry Invalid Name Length: src %u target %u",
2338                  SourceFileNameLength, TargetFileNameLength);
2339         (*ResultCB)->ResultStatus = STATUS_INVALID_PARAMETER;
2340         return;
2341     }
2342
2343     SourceParentFid.cell   = SourceParentId.Cell;
2344     SourceParentFid.volume = SourceParentId.Volume;
2345     SourceParentFid.vnode  = SourceParentId.Vnode;
2346     SourceParentFid.unique = SourceParentId.Unique;
2347     SourceParentFid.hash   = SourceParentId.Hash;
2348
2349     TargetParentFid.cell   = TargetParentId.Cell;
2350     TargetParentFid.volume = TargetParentId.Volume;
2351     TargetParentFid.vnode  = TargetParentId.Vnode;
2352     TargetParentFid.unique = TargetParentId.Unique;
2353     TargetParentFid.hash   = TargetParentId.Hash;
2354
2355     code = cm_GetSCache(&SourceParentFid, NULL, &oldDscp, userp, &req);
2356     if (code) {
2357         osi_Log1(afsd_logp, "RDR_RenameFileEntry cm_GetSCache source parent failed code 0x%x", code);
2358         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
2359         if ( status == STATUS_INVALID_HANDLE)
2360             status = STATUS_OBJECT_PATH_INVALID;
2361         (*ResultCB)->ResultStatus = status;
2362         return;
2363     }
2364
2365     lock_ObtainWrite(&oldDscp->rw);
2366     code = cm_SyncOp(oldDscp, NULL, userp, &req, 0,
2367                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2368     if (code) {
2369         osi_Log2(afsd_logp, "RDR_RenameFileEntry cm_SyncOp oldDscp 0x%p failed code 0x%x", oldDscp, code);
2370         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
2371         if ( status == STATUS_INVALID_HANDLE)
2372             status = STATUS_OBJECT_PATH_INVALID;
2373         (*ResultCB)->ResultStatus = status;
2374         lock_ReleaseWrite(&oldDscp->rw);
2375         cm_ReleaseSCache(oldDscp);
2376         return;
2377     }
2378
2379     cm_SyncOpDone(oldDscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2380     lock_ReleaseWrite(&oldDscp->rw);
2381
2382
2383     if (oldDscp->fileType != CM_SCACHETYPE_DIRECTORY) {
2384         osi_Log1(afsd_logp, "RDR_RenameFileEntry oldDscp 0x%p not a directory", oldDscp);
2385         (*ResultCB)->ResultStatus = STATUS_NOT_A_DIRECTORY;
2386         cm_ReleaseSCache(oldDscp);
2387         return;
2388     }
2389
2390     code = cm_GetSCache(&TargetParentFid, NULL, &newDscp, userp, &req);
2391     if (code) {
2392         osi_Log1(afsd_logp, "RDR_RenameFileEntry cm_GetSCache target parent failed code 0x%x", code);
2393         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
2394         (*ResultCB)->ResultStatus = status;
2395         cm_ReleaseSCache(oldDscp);
2396         return;
2397     }
2398
2399     lock_ObtainWrite(&newDscp->rw);
2400     code = cm_SyncOp(newDscp, NULL, userp, &req, 0,
2401                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2402     if (code) {
2403         osi_Log2(afsd_logp, "RDR_RenameFileEntry cm_SyncOp newDscp 0x%p failed code 0x%x", newDscp, code);
2404         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
2405         (*ResultCB)->ResultStatus = status;
2406         lock_ReleaseWrite(&newDscp->rw);
2407         cm_ReleaseSCache(oldDscp);
2408         cm_ReleaseSCache(newDscp);
2409         return;
2410     }
2411
2412     cm_SyncOpDone(newDscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2413     lock_ReleaseWrite(&newDscp->rw);
2414
2415
2416     if (newDscp->fileType != CM_SCACHETYPE_DIRECTORY) {
2417         osi_Log1(afsd_logp, "RDR_RenameFileEntry newDscp 0x%p not a directory", newDscp);
2418         (*ResultCB)->ResultStatus = STATUS_NOT_A_DIRECTORY;
2419         cm_ReleaseSCache(oldDscp);
2420         cm_ReleaseSCache(newDscp);
2421         return;
2422     }
2423
2424     /* Obtain the original FID just for debugging purposes */
2425     code = cm_BeginDirOp( oldDscp, userp, &req, CM_DIRLOCK_READ, CM_DIROP_FLAG_NONE, &dirop);
2426     if (code == 0) {
2427         code = cm_BPlusDirLookup(&dirop, SourceFileName, &SourceFid);
2428         code = cm_BPlusDirLookup(&dirop, TargetFileName, &OrigTargetFid);
2429         cm_EndDirOp(&dirop);
2430     }
2431
2432     code = cm_Rename( oldDscp, NULL, SourceFileName,
2433                       newDscp, TargetFileName, userp, &req);
2434     if (code == 0) {
2435         cm_scache_t *scp = 0;
2436         DWORD dwRemaining;
2437
2438         (*ResultCB)->ResultBufferLength = ResultBufferLength;
2439         dwRemaining = ResultBufferLength - sizeof( AFSFileRenameResultCB) + sizeof( AFSDirEnumEntry);
2440         (*ResultCB)->ResultStatus = 0;
2441
2442         pResultCB->SourceParentDataVersion.QuadPart = oldDscp->dataVersion;
2443         pResultCB->TargetParentDataVersion.QuadPart = newDscp->dataVersion;
2444
2445         osi_Log2(afsd_logp, "RDR_RenameFileEntry cm_Rename oldDscp 0x%p newDscp 0x%p SUCCESS",
2446                  oldDscp, newDscp);
2447
2448         code = cm_BeginDirOp( newDscp, userp, &req, CM_DIRLOCK_READ, CM_DIROP_FLAG_NONE, &dirop);
2449         if (code == 0) {
2450             code = cm_BPlusDirLookup(&dirop, TargetFileName, &TargetFid);
2451             cm_EndDirOp(&dirop);
2452         }
2453
2454         if (code != 0) {
2455             osi_Log1(afsd_logp, "RDR_RenameFileEntry cm_BPlusDirLookup failed code 0x%x",
2456                      code);
2457             (*ResultCB)->ResultStatus = STATUS_OBJECT_PATH_INVALID;
2458             cm_ReleaseSCache(oldDscp);
2459             cm_ReleaseSCache(newDscp);
2460             return;
2461         }
2462
2463         osi_Log4(afsd_logp, "RDR_RenameFileEntry Target FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
2464                   TargetFid.cell,  TargetFid.volume,
2465                   TargetFid.vnode, TargetFid.unique);
2466
2467         code = cm_GetSCache(&TargetFid, &newDscp->fid, &scp, userp, &req);
2468         if (code) {
2469             osi_Log1(afsd_logp, "RDR_RenameFileEntry cm_GetSCache target failed code 0x%x", code);
2470             smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
2471             (*ResultCB)->ResultStatus = status;
2472             cm_ReleaseSCache(oldDscp);
2473             cm_ReleaseSCache(newDscp);
2474             return;
2475         }
2476
2477         /* Make sure the source vnode is current */
2478         lock_ObtainWrite(&scp->rw);
2479         code = cm_SyncOp(scp, NULL, userp, &req, 0,
2480                           CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2481         if (code) {
2482             osi_Log2(afsd_logp, "RDR_RenameFileEntry cm_SyncOp scp 0x%p failed code 0x%x", scp, code);
2483             smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
2484             (*ResultCB)->ResultStatus = status;
2485             lock_ReleaseWrite(&scp->rw);
2486             cm_ReleaseSCache(oldDscp);
2487             cm_ReleaseSCache(newDscp);
2488             cm_ReleaseSCache(scp);
2489             return;
2490         }
2491
2492         cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2493         lock_ReleaseWrite(&scp->rw);
2494
2495         if (cm_shortNames) {
2496             dfid.vnode = htonl(scp->fid.vnode);
2497             dfid.unique = htonl(scp->fid.unique);
2498
2499             if (!cm_Is8Dot3(TargetFileName))
2500                 cm_Gen8Dot3NameIntW(TargetFileName, &dfid, shortName, NULL);
2501             else
2502                 shortName[0] = '\0';
2503         }
2504
2505         RDR_PopulateCurrentEntry(&pResultCB->DirEnum, dwRemaining,
2506                                  newDscp, scp, userp, &req, TargetFileName, shortName,
2507                                  RDR_POP_FOLLOW_MOUNTPOINTS | RDR_POP_EVALUATE_SYMLINKS,
2508                                  0, NULL, &dwRemaining);
2509         (*ResultCB)->ResultBufferLength = ResultBufferLength - dwRemaining;
2510         cm_ReleaseSCache(scp);
2511
2512         osi_Log0(afsd_logp, "RDR_RenameFileEntry SUCCESS");
2513     } else {
2514         osi_Log3(afsd_logp, "RDR_RenameFileEntry cm_Rename oldDscp 0x%p newDscp 0x%p failed code 0x%x",
2515                  oldDscp, newDscp, code);
2516         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
2517         (*ResultCB)->ResultStatus = status;
2518         (*ResultCB)->ResultBufferLength = 0;
2519     }
2520
2521     cm_ReleaseSCache(oldDscp);
2522     cm_ReleaseSCache(newDscp);
2523     return;
2524 }
2525
2526 /*
2527  * AFS does not support cross-directory hard links but RDR_HardLinkFileEntry
2528  * is written as if AFS does.  The check for cross-directory links is
2529  * implemented in cm_Link().
2530  *
2531  * Windows supports optional ReplaceIfExists functionality.  The AFS file
2532  * server does not.  If the target name already exists and bReplaceIfExists
2533  * is true, check to see if the user has insert permission before calling
2534  * cm_Unlink() on the existing object.  If the user does not have insert
2535  * permission return STATUS_ACCESS_DENIED.
2536  */
2537
2538 void
2539 RDR_HardLinkFileEntry( IN cm_user_t *userp,
2540                        IN WCHAR    *SourceFileNameCounted,
2541                        IN DWORD     SourceFileNameLength,
2542                        IN AFSFileID SourceFileId,
2543                        IN AFSFileHardLinkCB *pHardLinkCB,
2544                        IN BOOL bWow64,
2545                        IN DWORD ResultBufferLength,
2546                        IN OUT AFSCommResult **ResultCB)
2547 {
2548
2549     AFSFileHardLinkResultCB *pResultCB = NULL;
2550     size_t size = sizeof(AFSCommResult) + ResultBufferLength - 1;
2551     AFSFileID              SourceParentId   = pHardLinkCB->SourceParentId;
2552     AFSFileID              TargetParentId   = pHardLinkCB->TargetParentId;
2553     WCHAR *                TargetFileNameCounted = pHardLinkCB->TargetName;
2554     DWORD                  TargetFileNameLength = pHardLinkCB->TargetNameLength;
2555     cm_fid_t               SourceParentFid;
2556     cm_fid_t               TargetParentFid;
2557     cm_fid_t               SourceFid;
2558     cm_fid_t               OrigTargetFid = {0,0,0,0,0};
2559     cm_scache_t *          srcDscp = NULL;
2560     cm_scache_t *          targetDscp = NULL;
2561     cm_scache_t *          srcScp = NULL;
2562     cm_dirOp_t             dirop;
2563     wchar_t                shortName[13];
2564     wchar_t                SourceFileName[260];
2565     wchar_t                TargetFileName[260];
2566     cm_dirFid_t            dfid;
2567     cm_req_t               req;
2568     afs_uint32             code;
2569     DWORD                  status;
2570
2571     RDR_InitReq(&req, bWow64);
2572
2573     StringCchCopyNW(SourceFileName, 260, SourceFileNameCounted, SourceFileNameLength / sizeof(WCHAR));
2574     StringCchCopyNW(TargetFileName, 260, TargetFileNameCounted, TargetFileNameLength / sizeof(WCHAR));
2575
2576     osi_Log4(afsd_logp, "RDR_HardLinkFileEntry Source Parent FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
2577               SourceParentId.Cell,  SourceParentId.Volume,
2578               SourceParentId.Vnode, SourceParentId.Unique);
2579     osi_Log2(afsd_logp, "... Source Name=%S Length %u", osi_LogSaveStringW(afsd_logp, SourceFileName), SourceFileNameLength);
2580     osi_Log4(afsd_logp, "... Target Parent FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
2581               TargetParentId.Cell,  TargetParentId.Volume,
2582               TargetParentId.Vnode, TargetParentId.Unique);
2583     osi_Log2(afsd_logp, "... Target Name=%S Length %u", osi_LogSaveStringW(afsd_logp, TargetFileName), TargetFileNameLength);
2584
2585     *ResultCB = (AFSCommResult *)malloc( size);
2586     if (!(*ResultCB))
2587         return;
2588
2589     memset( *ResultCB,
2590             '\0',
2591             size);
2592
2593     pResultCB = (AFSFileHardLinkResultCB *)(*ResultCB)->ResultData;
2594
2595     if (SourceFileNameLength == 0 || TargetFileNameLength == 0)
2596     {
2597         osi_Log2(afsd_logp, "RDR_HardLinkFileEntry Invalid Name Length: src %u target %u",
2598                  SourceFileNameLength, TargetFileNameLength);
2599         (*ResultCB)->ResultStatus = STATUS_INVALID_PARAMETER;
2600         return;
2601     }
2602
2603     SourceFid.cell   = SourceFileId.Cell;
2604     SourceFid.volume = SourceFileId.Volume;
2605     SourceFid.vnode  = SourceFileId.Vnode;
2606     SourceFid.unique = SourceFileId.Unique;
2607     SourceFid.hash   = SourceFileId.Hash;
2608
2609     SourceParentFid.cell   = SourceParentId.Cell;
2610     SourceParentFid.volume = SourceParentId.Volume;
2611     SourceParentFid.vnode  = SourceParentId.Vnode;
2612     SourceParentFid.unique = SourceParentId.Unique;
2613     SourceParentFid.hash   = SourceParentId.Hash;
2614
2615     TargetParentFid.cell   = TargetParentId.Cell;
2616     TargetParentFid.volume = TargetParentId.Volume;
2617     TargetParentFid.vnode  = TargetParentId.Vnode;
2618     TargetParentFid.unique = TargetParentId.Unique;
2619     TargetParentFid.hash   = TargetParentId.Hash;
2620
2621     code = cm_GetSCache(&SourceFid, NULL, &srcScp, userp, &req);
2622     if (code) {
2623         osi_Log1(afsd_logp, "RDR_HardLinkFileEntry cm_GetSCache source failed code 0x%x", code);
2624         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
2625         (*ResultCB)->ResultStatus = status;
2626         return;
2627     }
2628
2629     code = cm_GetSCache(&TargetParentFid, NULL, &targetDscp, userp, &req);
2630     if (code) {
2631         osi_Log1(afsd_logp, "RDR_HardLinkFileEntry cm_GetSCache target parent failed code 0x%x", code);
2632         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
2633         (*ResultCB)->ResultStatus = status;
2634         cm_ReleaseSCache(srcScp);
2635         return;
2636     }
2637
2638     lock_ObtainWrite(&targetDscp->rw);
2639     code = cm_SyncOp(targetDscp, NULL, userp, &req, PRSFS_INSERT,
2640                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2641     if (code) {
2642         osi_Log2(afsd_logp, "RDR_HardLinkFileEntry cm_SyncOp targetDscp 0x%p failed code 0x%x", targetDscp, code);
2643         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
2644         (*ResultCB)->ResultStatus = status;
2645         lock_ReleaseWrite(&targetDscp->rw);
2646         cm_ReleaseSCache(srcScp);
2647         cm_ReleaseSCache(targetDscp);
2648         return;
2649     }
2650
2651     cm_SyncOpDone(targetDscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2652     lock_ReleaseWrite(&targetDscp->rw);
2653
2654     if (targetDscp->fileType != CM_SCACHETYPE_DIRECTORY) {
2655         osi_Log1(afsd_logp, "RDR_HardLinkFileEntry targetDscp 0x%p not a directory", targetDscp);
2656         (*ResultCB)->ResultStatus = STATUS_NOT_A_DIRECTORY;
2657         cm_ReleaseSCache(srcScp);
2658         cm_ReleaseSCache(targetDscp);
2659         return;
2660     }
2661
2662     if ( cm_FidCmp(&SourceParentFid, &TargetParentFid) ) {
2663         code = cm_GetSCache(&SourceParentFid, NULL, &srcDscp, userp, &req);
2664         if (code) {
2665             osi_Log1(afsd_logp, "RDR_HardLinkFileEntry cm_GetSCache source parent failed code 0x%x", code);
2666             smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
2667             if ( status == STATUS_INVALID_HANDLE)
2668                 status = STATUS_OBJECT_PATH_INVALID;
2669             (*ResultCB)->ResultStatus = status;
2670             cm_ReleaseSCache(srcScp);
2671             cm_ReleaseSCache(targetDscp);
2672             return;
2673         }
2674
2675         lock_ObtainWrite(&srcDscp->rw);
2676         code = cm_SyncOp(srcDscp, NULL, userp, &req, 0,
2677                           CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2678         if (code) {
2679             osi_Log2(afsd_logp, "RDR_HardLinkFileEntry cm_SyncOp srcDscp 0x%p failed code 0x%x", srcDscp, code);
2680             smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
2681             if ( status == STATUS_INVALID_HANDLE)
2682                 status = STATUS_OBJECT_PATH_INVALID;
2683             (*ResultCB)->ResultStatus = status;
2684             lock_ReleaseWrite(&srcDscp->rw);
2685             if (srcDscp != targetDscp)
2686                 cm_ReleaseSCache(srcDscp);
2687             cm_ReleaseSCache(targetDscp);
2688             cm_ReleaseSCache(srcScp);
2689             return;
2690         }
2691
2692         cm_SyncOpDone(srcDscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2693         lock_ReleaseWrite(&srcDscp->rw);
2694
2695         if (srcDscp->fileType != CM_SCACHETYPE_DIRECTORY) {
2696             osi_Log1(afsd_logp, "RDR_HardLinkFileEntry srcDscp 0x%p not a directory", srcDscp);
2697             (*ResultCB)->ResultStatus = STATUS_NOT_A_DIRECTORY;
2698             if (srcDscp != targetDscp)
2699                 cm_ReleaseSCache(srcDscp);
2700             cm_ReleaseSCache(targetDscp);
2701             cm_ReleaseSCache(srcScp);
2702             return;
2703         }
2704     } else {
2705         srcDscp = targetDscp;
2706     }
2707
2708     /* Obtain the target FID if it exists */
2709     code = cm_BeginDirOp( targetDscp, userp, &req, CM_DIRLOCK_READ, CM_DIROP_FLAG_NONE, &dirop);
2710     if (code == 0) {
2711         code = cm_BPlusDirLookup(&dirop, TargetFileName, &OrigTargetFid);
2712         cm_EndDirOp(&dirop);
2713     }
2714
2715     if (OrigTargetFid.vnode) {
2716
2717         /* An object exists with the target name */
2718         if (!pHardLinkCB->bReplaceIfExists) {
2719             osi_Log0(afsd_logp, "RDR_HardLinkFileEntry target name collision and !ReplaceIfExists");
2720             (*ResultCB)->ResultStatus = STATUS_OBJECT_NAME_COLLISION;
2721             if (srcDscp != targetDscp)
2722                 cm_ReleaseSCache(srcDscp);
2723             cm_ReleaseSCache(targetDscp);
2724             cm_ReleaseSCache(srcScp);
2725             return;
2726         }
2727
2728         lock_ObtainWrite(&targetDscp->rw);
2729         code = cm_SyncOp(targetDscp, NULL, userp, &req, PRSFS_INSERT | PRSFS_DELETE,
2730                           CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2731         if (code) {
2732             smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
2733             (*ResultCB)->ResultStatus = status;
2734             lock_ReleaseWrite(&srcDscp->rw);
2735             if (srcDscp != targetDscp)
2736                 cm_ReleaseSCache(srcDscp);
2737             cm_ReleaseSCache(targetDscp);
2738             cm_ReleaseSCache(srcScp);
2739             return;
2740         }
2741         cm_SyncOpDone(targetDscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2742         lock_ReleaseWrite(&targetDscp->rw);
2743
2744         code = cm_Unlink(targetDscp, NULL, TargetFileName, userp, &req);
2745         if (code) {
2746             osi_Log1(afsd_logp, "RDR_HardLinkFileEntry cm_Unlink code 0x%x", code);
2747             smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
2748             (*ResultCB)->ResultStatus = status;
2749             lock_ReleaseWrite(&srcDscp->rw);
2750             if (srcDscp != targetDscp)
2751                 cm_ReleaseSCache(srcDscp);
2752             cm_ReleaseSCache(targetDscp);
2753             cm_ReleaseSCache(srcScp);
2754             return;
2755         }
2756     }
2757
2758     code = cm_Link( targetDscp, TargetFileName, srcScp, 0, userp, &req);
2759     if (code == 0) {
2760         cm_fid_t TargetFid;
2761         cm_scache_t *targetScp = 0;
2762         DWORD dwRemaining;
2763
2764         (*ResultCB)->ResultBufferLength = ResultBufferLength;
2765         dwRemaining = ResultBufferLength - sizeof( AFSFileHardLinkResultCB) + sizeof( AFSDirEnumEntry);
2766         (*ResultCB)->ResultStatus = 0;
2767
2768         pResultCB->SourceParentDataVersion.QuadPart = srcDscp->dataVersion;
2769         pResultCB->TargetParentDataVersion.QuadPart = targetDscp->dataVersion;
2770
2771         osi_Log2(afsd_logp, "RDR_HardLinkFileEntry cm_Link srcDscp 0x%p targetDscp 0x%p SUCCESS",
2772                  srcDscp, targetDscp);
2773
2774         code = cm_BeginDirOp( targetDscp, userp, &req, CM_DIRLOCK_READ, CM_DIROP_FLAG_NONE, &dirop);
2775         if (code == 0) {
2776             code = cm_BPlusDirLookup(&dirop, TargetFileName, &TargetFid);
2777             cm_EndDirOp(&dirop);
2778         }
2779
2780         if (code != 0) {
2781             osi_Log1(afsd_logp, "RDR_HardLinkFileEntry cm_BPlusDirLookup failed code 0x%x",
2782                      code);
2783             (*ResultCB)->ResultStatus = STATUS_OBJECT_PATH_INVALID;
2784             if (srcDscp != targetDscp)
2785                 cm_ReleaseSCache(srcDscp);
2786             cm_ReleaseSCache(srcScp);
2787             cm_ReleaseSCache(targetDscp);
2788             return;
2789         }
2790
2791         osi_Log4(afsd_logp, "RDR_HardLinkFileEntry Target FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
2792                   TargetFid.cell,  TargetFid.volume,
2793                   TargetFid.vnode, TargetFid.unique);
2794
2795         code = cm_GetSCache(&TargetFid, &targetDscp->fid, &targetScp, userp, &req);
2796         if (code) {
2797             osi_Log1(afsd_logp, "RDR_HardLinkFileEntry cm_GetSCache target failed code 0x%x", code);
2798             smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
2799             (*ResultCB)->ResultStatus = status;
2800             if (srcDscp != targetDscp)
2801                 cm_ReleaseSCache(srcDscp);
2802             cm_ReleaseSCache(srcScp);
2803             cm_ReleaseSCache(targetDscp);
2804             return;
2805         }
2806
2807         /* Make sure the source vnode is current */
2808         lock_ObtainWrite(&targetScp->rw);
2809         code = cm_SyncOp(targetScp, NULL, userp, &req, 0,
2810                          CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2811         if (code) {
2812             osi_Log2(afsd_logp, "RDR_HardLinkFileEntry cm_SyncOp scp 0x%p failed code 0x%x",
2813                      targetScp, code);
2814             smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
2815             (*ResultCB)->ResultStatus = status;
2816             lock_ReleaseWrite(&targetScp->rw);
2817             cm_ReleaseSCache(targetScp);
2818             if (srcDscp != targetDscp)
2819                 cm_ReleaseSCache(srcDscp);
2820             cm_ReleaseSCache(srcScp);
2821             cm_ReleaseSCache(targetDscp);
2822             return;
2823         }
2824
2825         cm_SyncOpDone(targetScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2826         lock_ReleaseWrite(&targetScp->rw);
2827
2828         if (cm_shortNames) {
2829             dfid.vnode = htonl(targetScp->fid.vnode);
2830             dfid.unique = htonl(targetScp->fid.unique);
2831
2832             if (!cm_Is8Dot3(TargetFileName))
2833                 cm_Gen8Dot3NameIntW(TargetFileName, &dfid, shortName, NULL);
2834             else
2835                 shortName[0] = '\0';
2836         }
2837
2838         RDR_PopulateCurrentEntry(&pResultCB->DirEnum, dwRemaining,
2839                                  targetDscp, targetScp, userp, &req, TargetFileName, shortName,
2840                                  RDR_POP_FOLLOW_MOUNTPOINTS | RDR_POP_EVALUATE_SYMLINKS,
2841                                  0, NULL, &dwRemaining);
2842         (*ResultCB)->ResultBufferLength = ResultBufferLength - dwRemaining;
2843         cm_ReleaseSCache(targetScp);
2844
2845         osi_Log0(afsd_logp, "RDR_HardLinkFileEntry SUCCESS");
2846     } else {
2847         osi_Log3(afsd_logp, "RDR_HardLinkFileEntry cm_Link srcDscp 0x%p targetDscp 0x%p failed code 0x%x",
2848                  srcDscp, targetDscp, code);
2849         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
2850         (*ResultCB)->ResultStatus = status;
2851         (*ResultCB)->ResultBufferLength = 0;
2852     }
2853
2854     cm_ReleaseSCache(srcScp);
2855     if (srcDscp != targetDscp)
2856         cm_ReleaseSCache(srcDscp);
2857     cm_ReleaseSCache(targetDscp);
2858     return;
2859 }
2860
2861 void
2862 RDR_FlushFileEntry( IN cm_user_t *userp,
2863                     IN AFSFileID FileId,
2864                     IN BOOL bWow64,
2865                     IN DWORD ResultBufferLength,
2866                     IN OUT AFSCommResult **ResultCB)
2867 {
2868     cm_scache_t *scp = NULL;
2869     cm_fid_t    Fid;
2870     afs_uint32  code;
2871     cm_req_t    req;
2872     DWORD       status;
2873 #ifdef ODS_DEBUG
2874     char        dbgstr[1024];
2875 #endif
2876
2877     RDR_InitReq(&req, bWow64);
2878
2879     osi_Log4(afsd_logp, "RDR_FlushFileEntry File FID cell 0x%x vol 0x%x vno 0x%x uniq 0x%x",
2880               FileId.Cell, FileId.Volume,
2881               FileId.Vnode, FileId.Unique);
2882 #ifdef ODS_DEBUG
2883     snprintf( dbgstr, 1024,
2884               "RDR_FlushFileEntry File FID cell 0x%x vol 0x%x vno 0x%x uniq 0x%x\n",
2885               FileId.Cell, FileId.Volume,
2886               FileId.Vnode, FileId.Unique);
2887     OutputDebugStringA( dbgstr);
2888 #endif
2889
2890     *ResultCB = (AFSCommResult *)malloc( sizeof( AFSCommResult));
2891     if (!(*ResultCB)) {
2892         osi_Log0(afsd_logp, "RDR_FlushFileEntry out of memory");
2893         return;
2894     }
2895
2896     memset( *ResultCB,
2897             '\0',
2898             sizeof( AFSCommResult));
2899
2900     /* Process the release */
2901     Fid.cell = FileId.Cell;
2902     Fid.volume = FileId.Volume;
2903     Fid.vnode = FileId.Vnode;
2904     Fid.unique = FileId.Unique;
2905     Fid.hash = FileId.Hash;
2906
2907     code = cm_GetSCache(&Fid, NULL, &scp, userp, &req);
2908     if (code) {
2909         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
2910         (*ResultCB)->ResultStatus = status;
2911         osi_Log2(afsd_logp, "RDR_FlushFileEntry cm_GetSCache FID failure code=0x%x status=0x%x",
2912                   code, status);
2913         return;
2914     }
2915
2916     lock_ObtainWrite(&scp->rw);
2917     if (scp->flags & CM_SCACHEFLAG_DELETED) {
2918         lock_ReleaseWrite(&scp->rw);
2919         (*ResultCB)->ResultStatus = STATUS_INVALID_HANDLE;
2920         return;
2921     }
2922
2923     code = cm_SyncOp(scp, NULL, userp, &req, 0,
2924                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2925     if (code) {
2926         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
2927         (*ResultCB)->ResultStatus = status;
2928         lock_ReleaseWrite(&scp->rw);
2929         cm_ReleaseSCache(scp);
2930         osi_Log3(afsd_logp, "RDR_FlushFileEntry cm_SyncOp failure scp=0x%p code=0x%x status=0x%x",
2931                  scp, code, status);
2932         return;
2933     }
2934
2935     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2936     lock_ReleaseWrite(&scp->rw);
2937
2938     code = cm_FSync(scp, userp, &req, FALSE);
2939     cm_ReleaseSCache(scp);
2940
2941     if (code) {
2942         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
2943         (*ResultCB)->ResultStatus = status;
2944         osi_Log2(afsd_logp, "RDR_FlushFileEntry FAILURE code=0x%x status=0x%x",
2945                   code, status);
2946     } else {
2947         (*ResultCB)->ResultStatus = 0;
2948         osi_Log0(afsd_logp, "RDR_FlushFileEntry SUCCESS");
2949     }
2950     (*ResultCB)->ResultBufferLength = 0;
2951
2952     return;
2953 }
2954
2955 afs_uint32
2956 RDR_CheckAccess( IN cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp,
2957                  ULONG access,
2958                  ULONG *granted)
2959 {
2960     ULONG afs_acc, afs_gr;
2961     BOOLEAN file, dir;
2962     afs_uint32 code = 0;
2963
2964     file = (scp->fileType == CM_SCACHETYPE_FILE);
2965     dir = !file;
2966
2967     /* access definitions from prs_fs.h */
2968     afs_acc = 0;
2969     if (access & FILE_READ_DATA)
2970         afs_acc |= PRSFS_READ;
2971     if (access & FILE_READ_EA || access & FILE_READ_ATTRIBUTES)
2972         afs_acc |= PRSFS_READ;
2973     if (file && ((access & FILE_WRITE_DATA) || (access & FILE_APPEND_DATA)))
2974         afs_acc |= PRSFS_WRITE;
2975     if (access & FILE_WRITE_EA || access & FILE_WRITE_ATTRIBUTES)
2976         afs_acc |= PRSFS_WRITE;
2977     if (dir && ((access & FILE_ADD_FILE) || (access & FILE_ADD_SUBDIRECTORY)))
2978         afs_acc |= PRSFS_INSERT;
2979     if (dir && (access & FILE_LIST_DIRECTORY))
2980         afs_acc |= PRSFS_LOOKUP;
2981     if (file && (access & FILE_EXECUTE))
2982         afs_acc |= PRSFS_WRITE;
2983     if (dir && (access & FILE_TRAVERSE))
2984         afs_acc |= PRSFS_READ;
2985     if (dir && (access & FILE_DELETE_CHILD))
2986         afs_acc |= PRSFS_DELETE;
2987     if ((access & DELETE))
2988         afs_acc |= PRSFS_DELETE;
2989
2990     /* check ACL with server */
2991     lock_ObtainWrite(&scp->rw);
2992     while (1)
2993     {
2994         if (cm_HaveAccessRights(scp, userp, reqp, afs_acc, &afs_gr))
2995         {
2996             break;
2997         }
2998         else
2999         {
3000             /* we don't know the required access rights */
3001             code = cm_GetAccessRights(scp, userp, reqp);
3002             if (code)
3003                 break;
3004             continue;
3005         }
3006     }
3007     lock_ReleaseWrite(&(scp->rw));
3008
3009     if (code == 0) {
3010         *granted = 0;
3011         if (afs_gr & PRSFS_READ)
3012             *granted |= FILE_READ_DATA | FILE_READ_EA | FILE_READ_ATTRIBUTES | FILE_EXECUTE;
3013         if (afs_gr & PRSFS_WRITE)
3014             *granted |= FILE_WRITE_DATA | FILE_APPEND_DATA | FILE_WRITE_EA | FILE_WRITE_ATTRIBUTES | FILE_EXECUTE;
3015         if (afs_gr & PRSFS_INSERT)
3016             *granted |= (dir ? FILE_ADD_FILE | FILE_ADD_SUBDIRECTORY : 0) | (file ? FILE_ADD_SUBDIRECTORY : 0);
3017         if (afs_gr & PRSFS_LOOKUP)
3018             *granted |= (dir ? FILE_LIST_DIRECTORY : 0);
3019         if (afs_gr & PRSFS_DELETE)
3020             *granted |= FILE_DELETE_CHILD | DELETE;
3021         if (afs_gr & PRSFS_LOCK)
3022             *granted |= 0;
3023         if (afs_gr & PRSFS_ADMINISTER)
3024             *granted |= 0;
3025
3026         *granted |= SYNCHRONIZE | READ_CONTROL;
3027
3028         /* don't give more access than what was requested */
3029         *granted &= access;
3030         osi_Log3(afsd_logp, "RDR_CheckAccess SUCCESS scp=0x%p requested=0x%x granted=0x%x", scp, access, *granted);
3031     } else
3032         osi_Log2(afsd_logp, "RDR_CheckAccess FAILURE scp=0x%p code=0x%x",
3033                  scp, code);
3034
3035     return code;
3036 }
3037
3038 void
3039 RDR_OpenFileEntry( IN cm_user_t *userp,
3040                    IN AFSFileID FileId,
3041                    IN AFSFileOpenCB *OpenCB,
3042                    IN BOOL bWow64,
3043                    IN BOOL bHoldFid,
3044                    IN DWORD ResultBufferLength,
3045                    IN OUT AFSCommResult **ResultCB)
3046 {
3047     AFSFileOpenResultCB *pResultCB = NULL;
3048     cm_scache_t *scp = NULL;
3049     cm_user_t   *sysUserp = NULL;
3050     cm_fid_t    Fid;
3051     cm_lock_data_t      *ldp = NULL;
3052     afs_uint32  code;
3053     cm_req_t    req;
3054     DWORD       status;
3055
3056     RDR_InitReq(&req, bWow64);
3057
3058     osi_Log4(afsd_logp, "RDR_OpenFileEntry File FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
3059               FileId.Cell, FileId.Volume,
3060               FileId.Vnode, FileId.Unique);
3061
3062     *ResultCB = (AFSCommResult *)malloc( sizeof( AFSCommResult) + sizeof( AFSFileOpenResultCB));
3063     if (!(*ResultCB)) {
3064         osi_Log0(afsd_logp, "RDR_OpenFileEntry out of memory");
3065         return;
3066     }
3067
3068     memset( *ResultCB,
3069             '\0',
3070             sizeof( AFSCommResult) + sizeof( AFSFileOpenResultCB));
3071
3072     pResultCB = (AFSFileOpenResultCB *)(*ResultCB)->ResultData;
3073
3074     /* Process the release */
3075     Fid.cell = FileId.Cell;
3076     Fid.volume = FileId.Volume;
3077     Fid.vnode = FileId.Vnode;
3078     Fid.unique = FileId.Unique;
3079     Fid.hash = FileId.Hash;
3080
3081     code = cm_GetSCache(&Fid, NULL, &scp, userp, &req);
3082     if (code) {
3083         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
3084         (*ResultCB)->ResultStatus = status;
3085         osi_Log2(afsd_logp, "RDR_OpenFileEntry cm_GetSCache FID failure code=0x%x status=0x%x",
3086                   code, status);
3087         return;
3088     }
3089
3090     lock_ObtainWrite(&scp->rw);
3091     code = cm_SyncOp(scp, NULL, userp, &req, 0,
3092                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3093     if (code) {
3094         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
3095         (*ResultCB)->ResultStatus = status;
3096         lock_ReleaseWrite(&scp->rw);
3097         cm_ReleaseSCache(scp);
3098         osi_Log3(afsd_logp, "RDR_OpenFileEntry cm_SyncOp failure scp=0x%p code=0x%x status=0x%x",
3099                  scp, code, status);
3100         return;
3101     }
3102
3103     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3104     lock_ReleaseWrite(&scp->rw);
3105
3106     sysUserp = RDR_GetLocalSystemUser();
3107
3108     /*
3109      * Skip the open check if the request is coming from the local system account.
3110      * The local system has no tokens and therefore any requests sent to a file
3111      * server will fail.  Unfortunately, there are special system processes that
3112      * perform actions on files and directories in preparation for memory mapping
3113      * executables.  If the open check fails, the real request from the user process
3114      * will never be issued.
3115      *
3116      * Permitting the file system to allow subsequent operations to proceed does
3117      * not compromise security.  All requests to obtain file data or directory
3118      * enumerations will subsequently fail if they are not submitted under the
3119      * context of a process for that have access to the necessary credentials.
3120      */
3121
3122     if ( userp == sysUserp)
3123     {
3124         osi_Log1(afsd_logp, "RDR_OpenFileEntry LOCAL_SYSTEM access check skipped scp=0x%p",
3125                  scp);
3126         pResultCB->GrantedAccess = OpenCB->DesiredAccess;
3127         pResultCB->FileAccess = AFS_FILE_ACCESS_NOLOCK;
3128         code = 0;
3129     }
3130     else
3131     {
3132         int count = 0;
3133
3134         do {
3135             if (count++ > 0) {
3136                 Sleep(350);
3137                 osi_Log3(afsd_logp,
3138                          "RDR_OpenFileEntry repeating open check scp=0x%p userp=0x%p code=0x%x",
3139                          scp, userp, code);
3140             }
3141             code = cm_CheckNTOpen(scp, OpenCB->DesiredAccess, OpenCB->ShareAccess,
3142                                   OPEN_ALWAYS,
3143                                   OpenCB->ProcessId, OpenCB->Identifier,
3144                                   userp, &req, &ldp);
3145             if (code == 0)
3146                 code = RDR_CheckAccess(scp, userp, &req, OpenCB->DesiredAccess, &pResultCB->GrantedAccess);
3147
3148
3149             cm_CheckNTOpenDone(scp, userp, &req, &ldp);
3150         } while (count < 100 && (code == CM_ERROR_RETRY || code == CM_ERROR_WOULDBLOCK));
3151     }
3152
3153     /*
3154      * If we are restricting sharing, we should do so with a suitable
3155      * share lock.
3156      */
3157     if (code == 0 && scp->fileType == CM_SCACHETYPE_FILE && !(OpenCB->ShareAccess & FILE_SHARE_WRITE)) {
3158         cm_key_t key;
3159         LARGE_INTEGER LOffset, LLength;
3160         int sLockType;
3161
3162         LOffset.HighPart = SMB_FID_QLOCK_HIGH;
3163         LOffset.LowPart = SMB_FID_QLOCK_LOW;
3164         LLength.HighPart = 0;
3165         LLength.LowPart = SMB_FID_QLOCK_LENGTH;
3166
3167         /*
3168          * If we are not opening the file for writing, then we don't
3169          * try to get an exclusive lock.  No one else should be able to
3170          * get an exclusive lock on the file anyway, although someone
3171          * else can get a shared lock.
3172          */
3173         if ((OpenCB->ShareAccess & FILE_SHARE_READ) || !(OpenCB->DesiredAccess & AFS_ACCESS_WRITE))
3174         {
3175             sLockType = LOCKING_ANDX_SHARED_LOCK;
3176         } else {
3177             sLockType = 0;
3178         }
3179
3180         key = cm_GenerateKey(CM_SESSION_IFS, SMB_FID_QLOCK_PID, OpenCB->Identifier);
3181
3182         lock_ObtainWrite(&scp->rw);
3183         code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL);
3184         lock_ReleaseWrite(&scp->rw);
3185
3186         if (code) {
3187             code = CM_ERROR_SHARING_VIOLATION;
3188             pResultCB->FileAccess = AFS_FILE_ACCESS_NOLOCK;
3189         } else {
3190             if (sLockType == LOCKING_ANDX_SHARED_LOCK)
3191                 pResultCB->FileAccess = AFS_FILE_ACCESS_SHARED;
3192             else
3193                 pResultCB->FileAccess = AFS_FILE_ACCESS_EXCLUSIVE;
3194         }
3195     } else {
3196         pResultCB->FileAccess = AFS_FILE_ACCESS_NOLOCK;
3197     }
3198
3199     cm_ReleaseUser(sysUserp);
3200     if (code == 0 && bHoldFid)
3201         RDR_FlagScpInUse( scp, FALSE );
3202     cm_ReleaseSCache(scp);
3203
3204     if (code) {
3205         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
3206         (*ResultCB)->ResultStatus = status;
3207         osi_Log2(afsd_logp, "RDR_OpenFileEntry FAILURE code=0x%x status=0x%x",
3208                   code, status);
3209     } else {
3210         (*ResultCB)->ResultStatus = 0;
3211         (*ResultCB)->ResultBufferLength = sizeof( AFSFileOpenResultCB);
3212         osi_Log0(afsd_logp, "RDR_OpenFileEntry SUCCESS");
3213     }
3214     return;
3215 }
3216
3217 void
3218 RDR_ReleaseFileAccess( IN cm_user_t *userp,
3219                        IN AFSFileID FileId,
3220                        IN AFSFileAccessReleaseCB *ReleaseFileCB,
3221                        IN BOOL bWow64,
3222                        IN DWORD ResultBufferLength,
3223                        IN OUT AFSCommResult **ResultCB)
3224 {
3225     cm_key_t key;
3226     unsigned int sLockType;
3227     LARGE_INTEGER LOffset, LLength;
3228     cm_scache_t *scp = NULL;
3229     cm_fid_t    Fid;
3230     afs_uint32  code;
3231     cm_req_t    req;
3232     DWORD       status;
3233
3234     RDR_InitReq(&req, bWow64);
3235
3236     osi_Log4(afsd_logp, "RDR_ReleaseFileAccess File FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
3237               FileId.Cell, FileId.Volume,
3238               FileId.Vnode, FileId.Unique);
3239
3240     *ResultCB = (AFSCommResult *)malloc( sizeof( AFSCommResult));
3241     if (!(*ResultCB)) {
3242         osi_Log0(afsd_logp, "RDR_ReleaseFileAccess out of memory");
3243         return;
3244     }
3245
3246     memset( *ResultCB, '\0', sizeof( AFSCommResult));
3247
3248     if (ReleaseFileCB->FileAccess == AFS_FILE_ACCESS_NOLOCK)
3249         return;
3250
3251     /* Process the release */
3252     Fid.cell = FileId.Cell;
3253     Fid.volume = FileId.Volume;
3254     Fid.vnode = FileId.Vnode;
3255     Fid.unique = FileId.Unique;
3256     Fid.hash = FileId.Hash;
3257
3258     code = cm_GetSCache(&Fid, NULL, &scp, userp, &req);
3259     if (code) {
3260         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
3261         (*ResultCB)->ResultStatus = status;
3262         osi_Log2(afsd_logp, "RDR_ReleaseFileAccess cm_GetSCache FID failure code=0x%x status=0x%x",
3263                   code, status);
3264         return;
3265     }
3266
3267     if (ReleaseFileCB->FileAccess == AFS_FILE_ACCESS_SHARED)
3268         sLockType = LOCKING_ANDX_SHARED_LOCK;
3269     else
3270         sLockType = 0;
3271
3272     key = cm_GenerateKey(CM_SESSION_IFS, SMB_FID_QLOCK_PID, ReleaseFileCB->Identifier);
3273
3274     LOffset.HighPart = SMB_FID_QLOCK_HIGH;
3275     LOffset.LowPart = SMB_FID_QLOCK_LOW;
3276     LLength.HighPart = 0;
3277     LLength.LowPart = SMB_FID_QLOCK_LENGTH;
3278
3279     lock_ObtainWrite(&scp->rw);
3280
3281     code = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_LOCK);
3282     if (code == 0)
3283     {
3284         code = cm_Unlock(scp, sLockType, LOffset, LLength, key, 0, userp, &req);
3285
3286         cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
3287
3288         if (code == CM_ERROR_RANGE_NOT_LOCKED)
3289         {
3290             osi_Log3(afsd_logp, "RDR_ReleaseFileAccess Range Not Locked -- FileAccess 0x%x ProcessId 0x%x HandleId 0x%x",
3291                      ReleaseFileCB->FileAccess, ReleaseFileCB->ProcessId, ReleaseFileCB->Identifier);
3292         }
3293     }
3294
3295     lock_ReleaseWrite(&scp->rw);
3296
3297     osi_Log0(afsd_logp, "RDR_ReleaseFileAccessEntry SUCCESS");
3298 }
3299
3300 static const char *
3301 HexCheckSum(unsigned char * buf, int buflen, unsigned char * md5cksum)
3302 {
3303     int i, k;
3304     static char tr[16] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
3305
3306     if (buflen < 33)
3307         return "buffer length too small to HexCheckSum";
3308
3309     for (i=0;i<16;i++) {
3310         k = md5cksum[i];
3311
3312         buf[i*2] = tr[k / 16];
3313         buf[i*2+1] = tr[k % 16];
3314     }
3315     buf[32] = '\0';
3316
3317     return buf;
3318 }
3319
3320 /*
3321  * Extent requests from the file system are triggered when a file
3322  * page is not resident in the Windows cache.  The file system is
3323  * responsible for loading the page but cannot block the request
3324  * while doing so.  The AFS Redirector forwards the requests to
3325  * the AFS cache manager while indicating to Windows that the page
3326  * is not yet available.  A polling operation will then ensue with
3327  * the AFS Redirector issuing a RDR_RequestFileExtentsXXX call for
3328  * each poll&nbs