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